Related
Here is a vanilla "Sales" database:
CREATE TABLE Sales(id INT, category VARCHAR(50), item VARCHAR(50), date DATE, amount DECIMAL(10, 2));
INSERT INTO Sales VALUES
(1, 'Memory', 'Corsair 16GB', '2021-01-01', 200),
(2, 'Storage', 'Seagate BarraCuda 2TB', '2021-01-02', 50),
(3, 'Storage', 'Samsung 980 1TB', '2021-01-02', 150),
(4, 'OS', 'Windows 11', '2021-01-02', 150),
(5, 'OS', 'Ubuntu', '2021-01-03', 15),
(6, 'DBMS', 'MySQL Enterprise Edition 8', '2021-01-03', 5000),
(7, 'DBMS', 'SQL Server 2022', '2021-01-04', 15000),
(8, 'Memory', 'Corsair 16GB', '2021-01-04', 200),
(9, 'Memory', 'G.Skill Trident 32GB', '2021-01-04', 250),
(10, 'OS', 'Ubuntu', '2021-01-05', 15),
(11, 'DBMS', 'SQL Server 2022', '2021-01-06', 15000),
(12, 'DBMS', 'MySQL Enterprise Edition 8', '2021-01-06', 5000);
From it we build an SSAS Multidimensional cube with 3 dimensions:
Category with attribute Name,
Item with attribute Name,
Date with attribute Date.
So far so good.
Now creating some measures to get the maximum amounts along some dimensions:
WITH
MEMBER [Max Daily Sale] AS MAX([Date].[Date].Children, [Amount])
MEMBER [Max Category Sale] AS MAX([Category].[Name].Children, [Amount])
MEMBER [Max Category Daily Sale] AS MAX(([Category].[Name].Children, [Date].[Date].Children), [Amount])
MEMBER [Max Item Daily Sale] AS MAX(([Item].[Name].Children, [Date].[Date].Children), [Amount])
MEMBER [Max Item Sale] AS MAX([Item].[Name].Children, [Amount])
They are working fine except when one of the dimensions used in the MDX query is also used in the measure.
As an example:
SELECT
[Category].[Name].Children ON ROWS,
--[Item].[Name].Children ON ROWS,
--[Date].[Date].Children ON ROWS,
{ Amount, [Max Daily Sale], [Max Category Sale], [Max Category Daily Sale], [Max Item Sale], [Max Item Daily Sale] } ON COLUMNS
FROM Sales
Gives:
Amount Max Daily Sale Max Category Sale Max Category Daily Sale Max Item Sale Max Item Daily Sale
DBMS 40000 20000 (null) (null) 30000 15000
Memory 650 450 (null) (null) 400 250
OS 180 150 (null) (null) 150 150
Storage 200 200 (null) (null) 150 150
All the measures using dimension Category, [Max Category Sale] and [Max Category Daily Sale], result in NULL.
In the same way, using [Item].[Name] as the ROWS axis will "break" the [Max Item Sale] and [Max Item Daily Sale] measures.
And so on for [Max Daily Sale], [Max Category Daily Sale], and [Max Item Daily Sale], when using [Date].[Date].
It's obviously some MDX triviality I'm missing, but which one?
You are correct in what you observe. Each dimension can only be used in one section of the MDX: either on ROWS, on COLUMNS, in the WHERE clause, or within a calculated member. Sometimes an MDX statement will appear to break that rule, but look closely and you'll see that the dimension is only being used in one consistent way.
There are ways around this, often with the use of [Dimension name].currentMember but I'm not sure what to suggest for your particular case. Can this report be broken down into separate reports, to simply matters?
Let's assume I have a table in SQL Server called Budget_Spend like this
I know, with proper group by, sum and order by reach the next table (it's pretty obvious)
However, I don't how to replicate "Aviable" column, constructed following the logic:
For the first month, it's Budget - Spend - Taxes
For the following months is computed like PREVIOUS(Aviable)-CURRENT(Spend)-CURRENT(Taxes)
I've tried to use LAG function without succes (most of my tries didn't run due to syntax problems).
Any idea of doing? I imagine I need LAG and maybe a CASE in order to get the first value.
This is the DDL for creating the table
/* CREATE TABLE */
CREATE TABLE Budget_Spend(
Month DOUBLE,
Budget DOUBLE,
Spend DOUBLE,
Taxes DOUBLE);
/* INSERT */
INSERT INTO Budget_Spend(Month, Budget, Spend, Taxes) VALUES
(1, 1000, 75, 11.25);
INSERT INTO Budget_Spend(Month, Budget, Spend, Taxes) VALUES
(1, 1000, 25, 3.75);
INSERT INTO Budget_Spend(Month, Budget, Spend, Taxes) VALUES
(2, 1000, 200, 30);
INSERT INTO Budget_Spend(Month, Budget, Spend, Taxes) VALUES
(3, 1000, 150, 22.5);
INSERT INTO Budget_Spend(Month, Budget, Spend, Taxes) VALUES
(4, 1000, 10, 1.5);
INSERT INTO Budget_Spend(Month, Budget, Spend, Taxes) VALUES
(4, 1000, 10, 1.5);
You need window function :
select bs.*,
Budget - sum(Spend + Taxes) over (order by month) as Available
from (select month, Budget, sum(Spend) as Spend, sum(Taxes) as Taxes
from Budget_Spend bs
group by month, Budget
) bs;
I have a table which looks like
Order
OrderId
OrderStatus
OrderTime
I also have another table
OrderId
OrderLineId
OrderLineAmount
OrderLineCost
I am trying to get an average amount per hour between 2 dates I.e could be start and end of day, or start and end of week.
So for example if two orders where placed at 9am and 9:30am at £50 each. Then I am trying to get:
20/07/2018 09:00:00 - 20/07/2018 10:00:00
2
100
If that makes sense?
I currently have this but not quite working the way I need
SELECT
COUNT(*) as "number of orders",
sum(ol.quantity * ol.amount) as "line total",
to_timestamp(floor((extract('epoch' from "ordertimestamp") / 600 )) * 600) AT TIME ZONE 'UTC' as interval_alias
FROM "Order" as o
inner join "OrderLine" as ol on o.orderid = ol.orderid
GROUP BY interval_alias;
Any help would be awesome, Thanks
Here you go:
create table ord (
orderid int,
orderstatus int,
ordertime timestamp
);
insert into ord values (1, 1, '2018-07-20 09:10:00');
insert into ord values (2, 1, '2018-07-20 09:40:00');
insert into ord values (3, 1, '2018-07-20 10:15:00');
create table orderline (
orderid int,
orderlineid int,
orderlineamount int,
orderlinecost int
);
insert into orderline values (1, 100, 50, 40);
insert into orderline values (2, 100, 25, 40);
insert into orderline values (2, 100, 25, 40);
insert into orderline values (3, 10, 1234, 40);
select
date_trunc('hour', o.ordertime),
count(distinct o.orderid),
sum(l.orderlineamount)
from ord o
join orderline l on l.orderid = o.orderid
group by date_trunc('hour', o.ordertime)
order by date_trunc('hour', o.ordertime);
Result:
date_trunc count sum
---------------------------------------------------------------------------
2018-07-20 09:00:00.0 2 100
2018-07-20 10:00:00.0 1 1234
I am trying to generate a report where I want to get total sale values and quantities .
explanation:
When customers some products they get free gift , so items are two types standard and free gift . When they buy standard item they get free gift but not all the customers are eligible for it. In database they are hard coded as standard =0 and free gift as =1.
Aim 1: I would like to get only number of orders with free gifts and the total of that orders.
Aim 2: I want to count each count of free gift to find out top 10.
All the fields are in brackets.
below is simple example .
Hope this make sense. Thank you .
Results :
my script:
select
oh.[order date],
oh.[order guid],
[Item No_] as SKU
,ti.[Description],
ol.[quantity],
ol.Amount,
[EMS Available Quantity] as Stock_Qty,
(case when [Product Type]=0 then 'Standard'
when[Product Type]=1 then 'free_gift'
end) as Product_Type
from [Big$Item] TI
Inner join [Big$Inventory] I
ON I.[Item No_] = TI.[No_]
inner join [Big$Order Line] ol
on ti.[No_]=ol.[No_]
inner join [Big$Order header]oh
on oh.[order guid]=ol.[order guid]
where [Product Type] in ('0','1')
and oh.[order date] between'2017-06-12' and '2017-06-18'
order by [order date] asc
finally i have a solution - maybe not the most beautiful one - but it is working:
i have also added the create statement and the testdata insert - you can also reproduce it with this test link: http://rextester.com/JRV11837
The first Select just returns all orderguid which have at least one free gift.
The second Select i used to join includes the total amount of each order. As i use an INNER JOIN the final result will be just orders which include freegifts.
Finally i just group the resultset by the description of the freegift.
CREATE TABLE mygifttable
( Date datetime
,orderguid varchar(10)
,description varchar(55)
,sku int
,amount decimal)
;
INSERT INTO mygifttable VALUES
('2017-06-01', '1234', 'Sony Speakers' , 25, 100),
('2017-06-01', '1234', 'Sony Tv' , 23, 250),
('2017-06-01', '1234', 'Tv stand' , 11, 0),
('2017-06-01', '1235', 'Samsung Speakers', 28, 150),
('2017-06-01', '1235', 'Samsung Tv' , 26, 350),
('2017-06-01', '1235', 'Wall mount' , 10, 0),
('2017-06-01', '1236', 'Sony Speakers' , 25, 100),
('2017-06-01', '1236', 'Sony Tv' , 23, 250),
('2017-06-01', '1236', 'Tv stand' , 11, 0),
('2017-06-01', '1237', 'Apple mobiles' , 29, 900),
('2017-06-01', '1237', 'Apple cable' , 30, 800)
;
SELECT freegifttable.description
,SUM(freegifttable.freegift) as Free_Gifts
,SUM(totalamount.orderamount) as Total_Orderamount
FROM (
SELECT description
,orderguid
,SUM(IIF(amount = 0, 1,0)) as freegift
FROM mygifttable
GROUP BY description, orderguid
HAVING SUM(IIF(amount = 0, 1,0)) != 0
) freegifttable
INNER JOIN
(
SELECT orderguid
,SUM(amount) as orderamount
FROM mygifttable
GROUP BY orderguid
) totalamount
ON totalamount.orderguid = freegifttable.orderguid
GROUP BY freegifttable.description
;
I have a query that returns one row. However, I want to invert the rows and columns, meaning show the rows as columns and columns as rows. I think the best way to do this is to use a pivot table, which I am no expert in.
Here is my simple query:
SELECT Period1, Period2, Period3
FROM GL.Actuals
WHERE Year = 2009 AND Account = '001-4000-50031'
Results (with headers):
Period1, Period2, Period3
612.58, 681.36, 676.42
I would like for the results to look like this:
Desired Results:
Period, Amount
Jan, 612.58
Feb, 681.36
Mar, 676.42
This is a simple example, but what I'm really after is a bit more comlex than this. I realize I could produce theses results by using several SELECT commands instead. I'm just hoping someone can shine some light on how to accomplish this with a Pivot Table or if there is yet a better way.
For a fixed set of fields, you can use a UNION of select statements, each statement fetching one of the fields. Standard SQL does not provide a way to transpose the result for a variable number of fields, e.g. select * from table.
If MSSQL has an extension which helps (like pivot), I don't know about it.
Try something like this (tested on MSSQL2008):
DECLARE #Data TABLE(Period1 Decimal(5, 2), Period2 Decimal(5, 2), Period3 Decimal(5, 2))
INSERT #Data
VALUES (612.58, 681.36, 676.42)
SELECT Period, Amount
FROM (SELECT Period1 AS Jan, Period2 AS Feb, Period3 AS Mar FROM #Data) AS D
UNPIVOT (Amount FOR Period IN (Jan, Feb, Mar)) AS U
Update
Based on Jeff's comment, how about this:
DECLARE #Actuals TABLE(Account INT, [Year] INT, Period1 Decimal(5, 2), Period2 Decimal(5, 2), Period3 Decimal(5, 2))
INSERT #Actuals VALUES (1, 2010, 612.58, 681.36, 676.42)
INSERT #Actuals VALUES (1, 2009, 512.58, 581.36, 576.42)
SELECT Account, Period, Amount
FROM
(
SELECT a.Account, a.Period1 AS Jan, a.Period2 AS Feb, a.Period3 AS Mar, a1.Period1 AS Jan1, a1.Period2 AS Feb1, a1.Period3 AS Mar1
FROM #Actuals AS a
LEFT OUTER JOIN #Actuals AS a1 ON a.Account = a1.Account AND a1.[Year] = a.[Year] - 1
WHERE a.[Year] = 2010
) AS d
UNPIVOT (Amount FOR Period IN (Jan, Feb, Mar, Jan1, Feb1, Mar1)) AS u
or, with an explicit year column:
DECLARE #Actuals TABLE(Account INT, [Year] INT, Period1 Decimal(5, 2), Period2 Decimal(5, 2), Period3 Decimal(5, 2))
INSERT #Actuals VALUES (1, 2010, 612.58, 681.36, 676.42)
INSERT #Actuals VALUES (1, 2009, 512.58, 581.36, 576.42)
SELECT Account, [Year], Period, Amount
FROM
(
SELECT a.Account, a.[Year], a.Period1 AS Jan, a.Period2 AS Feb, a.Period3 AS Mar
FROM #Actuals AS a WHERE a.[Year] IN (2009, 2010)
) AS d
UNPIVOT (Amount FOR Period IN (Jan, Feb, Mar)) AS u
Check the unnest function, its quite amazing with little overhead. Just add a select query on top of the nested select query and unnest at that point:
SELECT id,
unnest(array['a', 'b', 'c']) AS colname,
unnest(array[a, b, c]) AS thing
FROM foo
ORDER BY id;