I'm stuck on a MDX query... I have a table which looks like:
Date Client Amount
---------------------------------
2010-01-01 1 1000
2010-01-01 2 500
2010-01-02 1 1100
... ... ...
2011-09-30 3 2000
Basically, I'd like to have a MDX equivalent of the following T-SQL:
SELECT [Year], [Month], AVG(DailyTotal)
FROM (
SELECT [Year], [Month], [Day], SUM(Amount) as DailyTotal
FROM Table
GROUP BY [Year], [Month], [Day]
)
GROUP BY [Year], [Month]
I'm trying to get as result like
Jan ... Sept
2010 AVG ... AVG
2011 AVG ... AVG
Thanks in advance
I have a query using Adventure Works:
with member [measures].[Average] as Avg({Descendants([Date].[Calendar].CurrentMember, [Date].[Calendar].[Date])*[Date].[Month of Year].CurrentMember}, [Measures].[Internet Sales Amount])
select
{{[Date].[Month of Year].[Month of Year]}*{[Measures].[Internet Sales Amount], [measures].[Average]}} on columns,
{[Date].[Calendar].[Calendar Year]} on rows
From [Adventure Works]
In this query I'm using 2 hierarchies ([Date].[Calendar] and [Date].[Month of Year]). Maybe, in your case, you could need do something else if your time dimension have others hierarchies.
select *
from
(
select [Year], [Month], avg(DailyTotal) as AVERAGE
from (
select
[Year] = year([date]),
[Month] = month([date]),
[day] = day([date]) ,
[DailyTotal] = sum([Amount])
from [Table]
group by year(date), month(date), day(date)
) Q
group by [Year], [Month]
) K
pivot (max(AVERAGE) for K.[Month] in ([1],[2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12])) as S
Related
I've created a temp table #MB that has a record ID (119 rows), start and end date (partial screenshot of the list is below):
I'm trying to get a count of occurrences that happened each hour for each record ID during the start and end date (or number of occurrences each hour when ID was active between two dates).
I've used this code:
SELECT *
FROM
(SELECT
ISNULL(CAST(part AS VARCHAR(5)), 'Total') AS part,
COUNT(*) AS part_count
FROM
(SELECT DATEPART([HOUR], [Start]) AS part
FROM #MB) grp
GROUP BY
GROUPING SETS((part),())
) pre
PIVOT
(MAX(part_count)
FOR part IN ([0], [1], [2], [3], [4], [5], [6], [7], [8],
[9], [10], [11], [12], [13], [14], [15], [16],
[17], [18], [19], [20], [21], [22], [23], Total)
) pvt;
but it counts only records based on the start date (don't count each hour between two dates) and I stuck on how to generate occurrences per hour for each ID between two dates that I can later use to pre-aggregate and pivot.
first, you need to generate the list of rows for each hour
here i am using a recursive cte query to do it
; with MB as
(
select ID, [Start], [End], [Date] = [Start]
from #MB
union all
select ID, [Start], [End], [Date] = dateadd(hour, 1, convert(date, c.[Date]))
from MB c
where dateadd(hour, 1, c.[Date]) < [End]
)
select *
from MB
so in your pivot query , just change to this
; with MB as
(
select ID, [Start], [End], [Date] = [Start]
from #MB
union all
select ID, [Start], [End], [Date] = DATEADD(HH,DATEPART(HH,[Start]),CAST(CAST([Start] AS DATE) AS DATETIME))
from MB c
where dateadd(hour, 1, c.[Date]) < [End]
)
SELECT *
FROM (
SELECT ISNULL(CAST(part AS VARCHAR(5)), 'Total') AS part,
COUNT(*) AS part_count
FROM (
SELECT DATEPART([HOUR], [Date]) AS part
FROM MB -- changed to the cte
) grp
GROUP BY
GROUPING SETS((part),())
) pre
PIVOT (MAX(part_count) FOR part IN (
[0],[1],[2],[3],[4],[5],[6],[7],[8],
[9],[10],[11],[12],[13],[14],[15],[16],
[17],[18],[19],[20],[21],[22],[23], Total)) pvt;
I am trying to create a pivot in order to sum specific month as the total, below is my table and sql pivot:
CREATE TABLE yt
([Store] varchar(10), [Month] varchar(10), [xCount] int)
;
INSERT INTO yt
([Store], [Month], [xCount])
VALUES
('A', 'JAN', 1),
('A', 'FEB', 10),
('B', 'JAN', 2),
('B', 'FEB', 20),
('C', 'JAN', 3),
('C', 'FEB', 70),
('C', 'MAR', 110)
;
select *
from
(
select Store, Month, xCount
from yt
) src
pivot
(
sum(xcount)
for Month in ([JAN], [FEB], [MAR])
) piv;
Store JAN FEB MAR
A 1 10 NULL
B 2 20 NULL
C 3 70 110
The above result I am able to sum the value by the current month. Now I want to sum all the month when Store a, sum only FEB, and MAR in Store b, and Store c sum MAR, so I want my result as
Store JAN FEB MAR
A 6 100 110
B 5 90 110
C 3 70 110
Can I do it in pivot? Or need to create a table to run sql again?
Thanks for the help.
For Sql Server 2008 you need some self join and ordering to make a running sum. Here I take store as this ordering:
WITH cte AS (SELECT * FROM #yt
PIVOT(SUM(xcount) FOR Month IN ([JAN], [FEB], [MAR])) piv)
SELECT c1.Store ,
SUM(c2.jan) AS jan ,
SUM(c2.feb) AS feb ,
SUM(c2.mar) AS mar
FROM cte c1
JOIN cte c2 ON c1.Store <= c2.Store
GROUP BY c1.Store
Your problem is running total order by store desc
In SQL Server2005+, You can try this:
SELECT Store,
SUM([JAN]) OVER(ORDER BY Store DESC) AS [JAN],
SUM([FEB]) OVER(ORDER BY Store DESC) AS [FEB],
SUM([MAR]) OVER(ORDER BY Store DESC) AS [MAR]
FROM (
SELECT *
FROM
(
SELECT Store, Month, xCount
FROM yt
) src
PIVOT
(
SUM(xcount)
for Month in ([JAN], [FEB], [MAR])
) piv
) AS A
ORDER BY Store
But in MySQL, you can reference this link
If you are using SQL SERVER 2012, you can use
SELECT STORE,
SUM(JAN)
OVER (
ORDER BY RN DESC) JAN,
SUM(FEB)
OVER (
ORDER BY RN DESC) FEB,
SUM(MAR)
OVER (
ORDER BY RN DESC) MAR
FROM (SELECT ROW_NUMBER()
OVER (
ORDER BY STORE)RN,
*
FROM (SELECT STORE,
MONTH,
XCOUNT
FROM #YT) SRC
PIVOT ( SUM(XCOUNT)
FOR MONTH IN ([JAN],
[FEB],
[MAR]) ) PIV)A
ORDER BY RN ASC
I have a table called Mst_Employee. The fields are:
Emp_No | Emp_Name | Emp_JoiningDate | Emp_ResignedDate | Emp_Status
How do I get the No. of Employees by year for each year somebody joined or resigned? (Joined and Resigned includes by year)
E.g. result should look like this:
Year No. of Employees.
------------------------
2011 125
2012 130
2013 100
One way to solve it is with a recursive cte and group by:
DECLARE #FromYear int, #ToYear int
SELECT #FromYear = YEAR(MIN(Emp_JoiningDate)),
#ToYear = YEAR(GETDATE())
FROM Mst_Employee
;WITH CTE AS
(
SELECT #FromYear As TheYear
UNION ALL
SELECT TheYear + 1
FROM CTE
WHERE TheYear < #ToYear
)
SELECT TheYear as [Year],
COUNT
(
CASE WHEN TheYear <= YEAR(COALESCE(Emp_ResignedDate, GETDATE())) THEN
1
END
) As [No. of Employees.]
FROM CTE
INNER JOIN Mst_Employee ON(TheYear >= YEAR(Emp_JoiningDate))
GROUP BY TheYear
See fiddle here
You can achieve this with:
select y as [Year], count(*) as [No. of Employees.]
from(select Emp_No, YEAR(Emp_JoiningDate) as y from Mst_Employee
union
select Emp_No, YEAR(Emp_ResignedDate) from Mst_Employee
where Emp_ResignedDate is not null)t
group by y
I have two tables
1) Fund details
ID Symbol
-------------------
1 ABC
2 XYZ
2) Fund Price data
Fund_id date Price
-------------------------------------------
1 2014-07-01 00:00:00.000 25.25
1 2014-07-02 00:00:00.000 25.45
......
2 2014-07-01 00:00:00.000 75.25
2 2014-07-02 00:00:00.000 75.42
.......
Now what I want to achieve is:
Here I am fetching the monthly data of a particular Fund as below:
SELECT YEAR(date) [Year], MONTH(date) [Month],
DATENAME(MONTH,date) [Month Name], COUNT(1) [Sales Count], F.Symbol
FROM FundData FD inner join FundDetails F on F.ID = FD.Fund_ID
where F.Symbol = 'ABC'
GROUP BY YEAR(date), MONTH(date), DATENAME(MONTH, date), F.Symbol
Output:
Year Month Month Name Sales Count Symbol
-------------------------------------------
2014 4 April 21 ABC
2014 5 May 21 ABC
2014 6 June 21 ABC
2014 7 July 3 ABC
.......
Total Rows: 301
So here this is only for only particular fund which has returned 301 rows.
Now I want to get all the funds from the Fund details table which has rows less than given count ex 216 which I will pass as a parameter
Use Following query:
Declare #YourParameter int = 10
SELECT YEAR(date) [Year],
MONTH(date) [Month],
DATENAME(MONTH,date) [Month Name],
COUNT(1) [Sales Count],
F.Symbol
FROM FundData FD
INNER JOIN FundDetails F on FD.ID = F.Fund_ID
Where FD.ID IN (SELECT z.Fund_ID
FROM FundDetails z
WHERE z.Fund_ID=FD.ID
GROUP BY z.Fund_ID, YEAR(z.date), MONTH(z.date)
HAVING COUNT(*) <= #YourParameter
)
GROUP BY YEAR(date), MONTH(date), DATENAME(MONTH, date), F.Symbol
I have fixed it:
Declare #YourParameter int = 110
WITH CTE AS
(
SELECT YEAR(date) [Year], MONTH(date) [Month],
DATENAME(MONTH,date) [Month Name], COUNT(1) [Sales Count], F.Symbol
FROM FundData FD inner join FundDetails F on F.ID = FD.Fund_ID
where F.ID
IN (SELECT z.ID FROM FundDetails z)
GROUP BY F.Symbol, YEAR(date), MONTH(date), DATENAME(MONTH, date)
)
SELECT Symbol, COUNT(*) as cnt FROM CTE
GROUP BY Symbol
having COUNT(*) >= #YourParameter
I have a table with columns sales(int), month(int). I want to retrieve sum of sales corresponding to every month. I need ouput in form of 12 columns corresponding to each month in which there will be a single record containing sales for for each column(month).
You should take a look at PIVOT for switching rows with columns. This prevents a select statement for each month. Something like this:
DECLARE #salesTable TABLE
(
[month] INT,
sales INT
)
-- Note that I use SQL Server 2008 INSERT syntax here for inserting
-- multiple rows in one statement!
INSERT INTO #salesTable
VALUES (0, 2) ,(0, 2) ,(1, 2) ,(1, 2) ,(2, 2)
,(3, 2) ,(3, 2) ,(4, 2) ,(4, 2) ,(5, 2)
,(6, 2) ,(6, 2) ,(7, 2) ,(8, 2) ,(8, 2)
,(9, 2) ,(10, 2) ,(10, 2) ,(11, 2) ,(11, 2)
SELECT [0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11]
FROM
(
SELECT [month], sales
FROM #salesTable
) AS SourceTable
PIVOT
(
SUM(sales)
FOR [month] IN ([0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11])
) AS PivotTable
Not pretty... but this works well
SELECT
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 1) [Sales1],
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 2) [Sales2],
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 3) [Sales3],
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 4) [Sales4],
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 5) [Sales5],
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 6) [Sales6],
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 7) [Sales7],
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 8) [Sales8],
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 9) [Sales9],
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 10) [Sales10],
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 11) [Sales11],
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 12) [Sales12]
Here's an alternate way to write the pivot that gives you a little more control (especially over the column names). It's also a little easier to generate dynamic SQL for.
It's similar to Robin's answer, but has the advantage of only hitting the table once:
select
Sales1 = sum( case when Month = 1 then Sales end )
, Sales2 = sum( case when Month = 2 then Sales end )
, Sales3 = sum( case when Month = 3 then Sales end )
-- etc..
from SalesTable;
I did some investigation, and it seems like the new pivot operator is just syntax sugar for this type of query. The query plans end up looking identical.
As an interesting aside, the unpivot operator seems to also just be syntax sugar. For example:
If you have a table like:
Create Table Sales ( JanSales int, FebSales int, MarchSales int...)
You can write:
select unpivoted.monthName, unpivoted.sales
from Sales s
outer apply (
select 'Jan', JanSales union all
select 'Feb', FebSales union all
select 'March', MarchSales
) unpivoted( monthName, sales );
And get the unpivoted data...
You can do it with OLAP. Here is another link to MSDN documentation on the topic.
With OLAP, you can create a cube with the information you have, with the layout you need.
If you do not want to go that way, you will have to create summary tables with .NET, Java, TransacSQL, or your preferred language to manipulate SQLServer data.
To easily transpose columns into rows with its names you should use XML. In my blog I was described this with example: Link