patternMinor
Get Quarterly Data For a Year
Viewed 0 times
yearquarterlygetfordata
Problem
I need a way to query a SQL Table and pull back data on a quarter by quarter basis. I know that SQL Server has a
EDIT
My desired returned results is like so
EDIT 2
I tried this syntax using a
Msg 130, Level 15, State 1, Line 18
Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
```
SELECT
Employeename
,SUM(
case
when Datepart(Year, [DatePaid]) = '2016' AND DATEPART(Quarter, [DatePaid]) = 1
Then SUM(ISNULL(TotalCheckamt,0))
end
) As Q12016
,SUM(
case
when Datepart(Year, [DatePaid]) = '2017' AND DATEPART(Quarter, [DatePaid]) = 1
Then SUM(ISNULL(TotalCheckamt,0))
end
) As Q12017
,SUM(
case
when Datepart(Year, [DatePaid]) = '2016' AND DATEPART(Quarter, [DatePaid]) = 2
Then SUM(ISNULL(TotalCheckamt,0))
end
) As Q22016
,SUM(
case
when Datepart(Year, [DatePaid]) = '2017' AND DATEPART(Quarter, [DatePaid]) = 2
Then SUM(ISNULL(TotalCheckamt,0))
end
) As Q22017
,SU
DatePart() function which has a parameter of q = Quarter and I came up with this syntax, but for a table that holds roughly 50,000 rows this syntax is extremely slow in it. Is this the best way to achieve this result or is there more optimization that can occur?Declare @startdate date = '20170101', @enddate date = '20171231'
Select
Employeename
,[Total Amount Paid] = SUM(ISNULL(Totalcheckamt,0))
FROM dbo.PaymentHistory
WHERE DatePart(q,[DatePaid]) = 1
AND [DatePaid] BETWEEN CAST(DateAdd(yy, -1, @startdate) As Date)
AND CAST(DateAdd(yy, -1, @enddate) As Date)
GROUP BY Employeename
Order By Employeename ASCEDIT
My desired returned results is like so
Employee Name -- Q1 --- Q2 --- Q3 --- Q4
James XXXXX.XX XXXX.XX XXXX.XX XXXX.XX
Roger XXXXX.XX XXXX.XX XXXX.XX XXXX.XXEDIT 2
I tried this syntax using a
case statement but it gives me an error of the error below. What should I alter in order to be able to succesfully execute this statement?Msg 130, Level 15, State 1, Line 18
Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
```
SELECT
Employeename
,SUM(
case
when Datepart(Year, [DatePaid]) = '2016' AND DATEPART(Quarter, [DatePaid]) = 1
Then SUM(ISNULL(TotalCheckamt,0))
end
) As Q12016
,SUM(
case
when Datepart(Year, [DatePaid]) = '2017' AND DATEPART(Quarter, [DatePaid]) = 1
Then SUM(ISNULL(TotalCheckamt,0))
end
) As Q12017
,SUM(
case
when Datepart(Year, [DatePaid]) = '2016' AND DATEPART(Quarter, [DatePaid]) = 2
Then SUM(ISNULL(TotalCheckamt,0))
end
) As Q22016
,SUM(
case
when Datepart(Year, [DatePaid]) = '2017' AND DATEPART(Quarter, [DatePaid]) = 2
Then SUM(ISNULL(TotalCheckamt,0))
end
) As Q22017
,SU
Solution
Using your
After you accepted my original answer, I noticed where other posters were advocating the use of PIVOT to achieve the same result as multiple
To summarize some of the key points of PIVOT (from the link):
You use the PIVOT operator within your query’s FROM clause to rotate
and aggregate the values in a dataset. The data is pivoted based on
one of the columns in the dataset. Each unique value in that column
becomes its own column, which contains aggregated pivoted data.
To better understand how this all works, let’s start with the basic
syntax for a query that uses the PIVOT operator:
For the SELECT clause, you can specify an asterisk (*) or the
individual columns, and for the FROM clause, you can specify a table
or table expression. If you use a table expression, then you must also
define a table alias. You can also include an ORDER BY clause, but
that’s optional. You’ll get to see these clauses in action as we
progress through the questions. For now, let’s focus on the PIVOT
clause. You need to understand how this clause works to make sure your
pivots work the way you want.
After you specify the PIVOT keyword, you pass in what are essentially
three arguments, enclosed in parentheses. The first is the aggregate
function and the name of the column to be aggregated. You can use any
aggregate function except the COUNT function, when used with an
asterisk, as in COUNT(*).
CASE expression example, here's how it could be written:DECLARE @PaymentHistory TABLE (
EmployeeName VARCHAR(100)
,DatePaid DATE
,TotalCheckAmt DECIMAL(11, 2)
)
insert into @Paymenthistory values ('James','2016-01-01',100.00)
insert into @Paymenthistory values ('James','2016-02-01',100.00)
insert into @Paymenthistory values ('James','2016-03-01',100.00)
insert into @Paymenthistory values ('James','2016-04-01',100.00)
insert into @Paymenthistory values ('James','2016-05-01',100.00)
insert into @Paymenthistory values ('James','2016-06-01',100.00)
insert into @Paymenthistory values ('James','2016-07-01',100.00)
insert into @Paymenthistory values ('Roger','2016-01-01',100.00)
insert into @Paymenthistory values ('Roger','2016-02-01',100.00)
insert into @Paymenthistory values ('Roger','2016-03-01',100.00)
insert into @Paymenthistory values ('Roger','2016-04-01',100.00)
insert into @Paymenthistory values ('Roger','2016-05-01',100.00)
insert into @Paymenthistory values ('Roger','2016-06-01',100.00)
insert into @Paymenthistory values ('Roger','2016-07-01',100.00)
SELECT Employeename
,ISNULL(SUM(CASE
WHEN Datepart(Year, [DatePaid]) = '2016'
AND DATEPART(Quarter, [DatePaid]) = 1
THEN TotalCheckamt
END), 0) AS Q12016
,ISNULL(SUM(CASE
WHEN Datepart(Year, [DatePaid]) = '2017'
AND DATEPART(Quarter, [DatePaid]) = 1
THEN TotalCheckamt
END), 0) AS Q12017
,ISNULL(SUM(CASE
WHEN Datepart(Year, [DatePaid]) = '2016'
AND DATEPART(Quarter, [DatePaid]) = 2
THEN TotalCheckamt
END), 0) AS Q22016
,ISNULL(SUM(CASE
WHEN Datepart(Year, [DatePaid]) = '2017'
AND DATEPART(Quarter, [DatePaid]) = 2
THEN TotalCheckamt
END), 0) AS Q22017
,ISNULL(SUM(CASE
WHEN Datepart(Year, [DatePaid]) = '2016'
AND DATEPART(Quarter, [DatePaid]) = 3
THEN TotalCheckamt
END), 0) AS Q32016
,ISNULL(SUM(CASE
WHEN Datepart(Year, [DatePaid]) = '2017'
AND DATEPART(Quarter, [DatePaid]) = 3
THEN TotalCheckamt
END), 0) AS Q32017
,ISNULL(SUM(CASE
WHEN Datepart(Year, [DatePaid]) = '2016'
AND DATEPART(Quarter, [DatePaid]) = 4
THEN TotalCheckamt
END), 0) AS Q42016
,ISNULL(SUM(CASE
WHEN Datepart(Year, [DatePaid]) = '2017'
AND DATEPART(Quarter, [DatePaid]) = 4
THEN TotalCheckamt
END), 0) AS Q42017
FROM @PaymentHistory
GROUP BY Employeename
ORDER BY Employeename ASCAfter you accepted my original answer, I noticed where other posters were advocating the use of PIVOT to achieve the same result as multiple
CASE expressions. For completeness of my answer, I decided to try my hand at using PIVOT to provide additional options for you (and learn something myself in the process). I've found the information from Questions About Pivoting Data in SQL Server You Were Too Shy to Ask to be quite useful when trying to understand how to use PIVOT. You'll learn a lot about PIVOT by working through the examples (static and dynamic PIVOT) in the link - I know I did. To summarize some of the key points of PIVOT (from the link):
You use the PIVOT operator within your query’s FROM clause to rotate
and aggregate the values in a dataset. The data is pivoted based on
one of the columns in the dataset. Each unique value in that column
becomes its own column, which contains aggregated pivoted data.
To better understand how this all works, let’s start with the basic
syntax for a query that uses the PIVOT operator:
SELECT column_list
FROM table_expression
PIVOT
(
aggregate_function(aggregate_column)
FOR pivot_column
IN( pivot_column_values )
) [AS] pivot_table_alias
[ORDER BY column_list];For the SELECT clause, you can specify an asterisk (*) or the
individual columns, and for the FROM clause, you can specify a table
or table expression. If you use a table expression, then you must also
define a table alias. You can also include an ORDER BY clause, but
that’s optional. You’ll get to see these clauses in action as we
progress through the questions. For now, let’s focus on the PIVOT
clause. You need to understand how this clause works to make sure your
pivots work the way you want.
After you specify the PIVOT keyword, you pass in what are essentially
three arguments, enclosed in parentheses. The first is the aggregate
function and the name of the column to be aggregated. You can use any
aggregate function except the COUNT function, when used with an
asterisk, as in COUNT(*).
Code Snippets
DECLARE @PaymentHistory TABLE (
EmployeeName VARCHAR(100)
,DatePaid DATE
,TotalCheckAmt DECIMAL(11, 2)
)
insert into @Paymenthistory values ('James','2016-01-01',100.00)
insert into @Paymenthistory values ('James','2016-02-01',100.00)
insert into @Paymenthistory values ('James','2016-03-01',100.00)
insert into @Paymenthistory values ('James','2016-04-01',100.00)
insert into @Paymenthistory values ('James','2016-05-01',100.00)
insert into @Paymenthistory values ('James','2016-06-01',100.00)
insert into @Paymenthistory values ('James','2016-07-01',100.00)
insert into @Paymenthistory values ('Roger','2016-01-01',100.00)
insert into @Paymenthistory values ('Roger','2016-02-01',100.00)
insert into @Paymenthistory values ('Roger','2016-03-01',100.00)
insert into @Paymenthistory values ('Roger','2016-04-01',100.00)
insert into @Paymenthistory values ('Roger','2016-05-01',100.00)
insert into @Paymenthistory values ('Roger','2016-06-01',100.00)
insert into @Paymenthistory values ('Roger','2016-07-01',100.00)
SELECT Employeename
,ISNULL(SUM(CASE
WHEN Datepart(Year, [DatePaid]) = '2016'
AND DATEPART(Quarter, [DatePaid]) = 1
THEN TotalCheckamt
END), 0) AS Q12016
,ISNULL(SUM(CASE
WHEN Datepart(Year, [DatePaid]) = '2017'
AND DATEPART(Quarter, [DatePaid]) = 1
THEN TotalCheckamt
END), 0) AS Q12017
,ISNULL(SUM(CASE
WHEN Datepart(Year, [DatePaid]) = '2016'
AND DATEPART(Quarter, [DatePaid]) = 2
THEN TotalCheckamt
END), 0) AS Q22016
,ISNULL(SUM(CASE
WHEN Datepart(Year, [DatePaid]) = '2017'
AND DATEPART(Quarter, [DatePaid]) = 2
THEN TotalCheckamt
END), 0) AS Q22017
,ISNULL(SUM(CASE
WHEN Datepart(Year, [DatePaid]) = '2016'
AND DATEPART(Quarter, [DatePaid]) = 3
THEN TotalCheckamt
END), 0) AS Q32016
,ISNULL(SUM(CASE
WHEN Datepart(Year, [DatePaid]) = '2017'
AND DATEPART(Quarter, [DatePaid]) = 3
THEN TotalCheckamt
END), 0) AS Q32017
,ISNULL(SUM(CASE
WHEN Datepart(Year, [DatePaid]) = '2016'
AND DATEPART(Quarter, [DatePaid]) = 4
THEN TotalCheckamt
END), 0) AS Q42016
,ISNULL(SUM(CASE
WHEN Datepart(Year, [DatePaid]) = '2017'
AND DATEPART(Quarter, [DatePaid]) = 4
THEN TotalCheckamt
END), 0) AS Q42017
FROM @PaymentHistory
GROUP BY Employeename
ORDER BY Employeename ASCSELECT column_list
FROM table_expression
PIVOT
(
aggregate_function(aggregate_column)
FOR pivot_column
IN( pivot_column_values )
) [AS] pivot_table_alias
[ORDER BY column_list];DECLARE @PaymentHistory TABLE (
EmployeeName VARCHAR(100)
,DatePaid DATE
,TotalCheckAmt DECIMAL(11, 2)
);
insert into @Paymenthistory values ('James','2016-01-01',100.00);
insert into @Paymenthistory values ('James','2016-02-01',100.00);
insert into @Paymenthistory values ('James','2016-03-01',100.00);
insert into @Paymenthistory values ('James','2016-04-01',100.00);
insert into @Paymenthistory values ('James','2016-05-01',100.00);
insert into @Paymenthistory values ('James','2016-06-01',100.00);
insert into @Paymenthistory values ('James','2016-07-01',100.00);
insert into @Paymenthistory values ('James','2017-01-01',100.00);
insert into @Paymenthistory values ('James','2018-10-01',900.00);
insert into @Paymenthistory values ('Roger','2016-01-01',100.00);
insert into @Paymenthistory values ('Roger','2016-02-01',100.00);
insert into @Paymenthistory values ('Roger','2016-03-01',100.00);
insert into @Paymenthistory values ('Roger','2016-04-01',100.00);
insert into @Paymenthistory values ('Roger','2016-05-01',100.00);
insert into @Paymenthistory values ('Roger','2016-06-01',100.00);
insert into @Paymenthistory values ('Roger','2016-07-01',100.00);
insert into @Paymenthistory values ('Roger','2020-10-01',900.00);
;
WITH cte_Paymenthistory
AS (
SELECT CASE
WHEN Datepart(Year, [DatePaid]) = '2016'
AND DATEPART(Quarter, [DatePaid]) = 1
THEN 'Q12016'
WHEN Datepart(Year, [DatePaid]) = '2016'
AND DATEPART(Quarter, [DatePaid]) = 2
THEN 'Q22016'
WHEN Datepart(Year, [DatePaid]) = '2016'
AND DATEPART(Quarter, [DatePaid]) = 3
THEN 'Q32016'
WHEN Datepart(Year, [DatePaid]) = '2016'
AND DATEPART(Quarter, [DatePaid]) = 4
THEN 'Q42016'
WHEN Datepart(Year, [DatePaid]) = '2017'
AND DATEPART(Quarter, [DatePaid]) = 2
THEN 'Q12017'
WHEN Datepart(Year, [DatePaid]) = '2017'
AND DATEPART(Quarter, [DatePaid]) = 3
THEN 'Q32017'
WHEN Datepart(Year, [DatePaid]) = '2017'
AND DATEPART(Quarter, [DatePaid]) = 4
THEN 'Q42017'
END AS ColumnLabel
,EmployeeName
,TotalCheckAmt
FROM @PaymentHistory
)
SELECT EmployeeName
,coalesce([Q12016], 0) AS [Q12016]
,coalesce([Q12017], 0) AS [Q12076]
,coalesce([Q22016], 0) AS [Q22016]
,coalesce([Q22017], 0) AS [Q12017]
,coalesce([Q32016], 0) AS [Q32016]
,coalesce([Q32017], 0) AS [Q32017]
,coalesce([Q42016], 0) AS [Q42016]
,coalesce([Q42017], 0) AS [Q42017]
FROM cte_Paymenthistory
PIVOT(SUM(TotalCheckAmt) FOR ColumnLabel IN (
[Q12016]
,[Q12017]
,[Q22016]
,[Q22017]
,[Q32016]
,[Q32017]
,[Q42016]
,[Q42017]
)) AS pvt
ORDER BY employeename;set nocount on
DECLARE @sql AS NVARCHAR(2000);
DECLARE @col AS NVARCHAR(2000);
DECLARE @colCoalesceNull AS NVARCHAR(2000);
IF OBJECT_ID('tempdb..#PaymentHistory') IS NOT NULL drop Table #PaymentHistory
CREATE TABLE #PaymentHistory (
EmployeeName VARCHAR(100)
,DatePaid DATE
,TotalCheckAmt DECIMAL(11, 2)
);
insert into #Paymenthistory values ('James','2016-01-01',100.00);
insert into #Paymenthistory values ('James','2016-02-01',100.00);
insert into #Paymenthistory values ('James','2016-03-01',100.00);
insert into #Paymenthistory values ('James','2016-04-01',100.00);
insert into #Paymenthistory values ('James','2016-05-01',100.00);
insert into #Paymenthistory values ('James','2016-06-01',100.00);
insert into #Paymenthistory values ('James','2016-07-01',100.00);
insert into #Paymenthistory values ('James','2017-01-01',100.00);
insert into #Paymenthistory values ('James','2018-10-01',900.00);
insert into #Paymenthistory values ('Roger','2016-01-01',100.00);
insert into #Paymenthistory values ('Roger','2016-02-01',100.00);
insert into #Paymenthistory values ('Roger','2016-03-01',100.00);
insert into #Paymenthistory values ('Roger','2016-04-01',100.00);
insert into #Paymenthistory values ('Roger','2016-05-01',100.00);
insert into #Paymenthistory values ('Roger','2016-06-01',100.00);
insert into #Paymenthistory values ('Roger','2016-07-01',100.00);
insert into #Paymenthistory values ('Roger','2020-10-01',900.00);
;
;
SELECT @col =
Coalesce(@col + ', ', '') + QUOTENAME(PvtColumnName)
,@colCoalesceNull =
Coalesce(@colCoalesceNull + ', ', '') + 'coalesce(' + QUOTENAME(PvtColumnName) + ',0) as ' + QUOTENAME(PvtColumnName)
FROM (
SELECT DISTINCT
'Q' +
CONVERT(VARCHAR(1), DATEPART(Quarter, [DatePaid])) +
CONVERT(VARCHAR(4), year([DatePaid]))
AS PvtColumnName
FROM #PaymentHistory
) AS PaymentHistory;
PRINT @col
PRINT @colcoalescenull
SET @sql = N'
with cte_PaymentHistory as
(
select
''Q'' + CONVERT(varchar(1),DATEPART(Quarter, [DatePaid])) + CONVERT(varchar(4),year([DatePaid])) as PvtColumnName
,EmployeeName
,TotalCheckAmt
from #PaymentHistory
)
SELECT EmployeeName, ' + @colCoalesceNull + 'FROM cte_PaymentHistory
PIVOT(SUM(TotalCheckAmt)
FOR PvtColumnName IN (' + @col + ')) AS PivotPaymentHistory';
EXEC sp_executesql @sql;Context
StackExchange Database Administrators Q#164549, answer score: 6
Revisions (0)
No revisions yet.