Say that I have a SQL Server table which has 4 columns MonthEnd
, Gender
, Weight
and Age
.
Now, the MonthEnd
go from 201901 through 201912.
I have a process where a run a query which generates a variety of metrics, for instance sum(Weight) and average(Age) for each month.
Right now, I set a where MonthEnd = 201901
when I create the metrics for that month.
The output is a table with 2 columns and 2 rows. The Column1 header is Metric and the Column2 header is 201901 and then row1 column1 says Total_Weight and row1 column2 is the value generated by the sum(weight) function.
Similarly, row2 column1 says Average_Age and row2 column2 is the result of the Average(Age) function.
I have the above done.
Then, I have to rerun the code after changing the where clause to where MonthEnd = 201902 and then the same structure applies to results.
I want to be able to run 201901 through 201912 in one step and have the output reflect 13 columns, namely, column1 would still be the metric with a header “Metric” but the next 12 columns would have headers 201901 through 201912 with the corresponding results for each month included below the headers.
Can T-SQL do this? I feel like I can do it with 1 aggregation function using Pivot but I haven’t figured out how to do multiple aggregate functions at the same time.
-- THIS SECTION SETS UP THE DATA SET STARTING POINT --------- IF OBJECT_ID('[dbo].[example]') IS NOT NULL DROP TABLE [dbo].[example] GO CREATE TABLE [dbo].[example] ( MonthEnd INT NOT NULL, Grade VARCHAR(50) NOT NULL, Name VARCHAR(50) NOT NULL, Amount INT NULL ) GO INSERT INTO [dbo].[example] VALUES (201901, 'A', 'Josh', 100), (201901, 'A', 'Joe', 50), (201901, 'A', 'Jill', 150), (201901, 'B', 'Julie', 150), (201901, 'B', 'Jim', 350), (201901, 'C', 'Jeff', 100), (201901, 'C', 'Jack', 125), (201901, 'C', 'Jillian', 150), (201901, 'C', 'Jess', 175), (201901, 'C', 'James', 450), (201902, 'A', 'Josh', 95), (201902, 'A', 'Jill', 105), (201902, 'B', 'Julie', 125), (201902, 'B', 'Jim', 325), (201902, 'C', 'Jeff', 75), (201902, 'C', 'Jack', 100), (201902, 'C', 'Jillian', 125), (201903, 'A', 'Josh', 50), (201903, 'B', 'Julie', 75), (201903, 'B', 'Jim', 300), (201903, 'C', 'Jeff', 50), (201903, 'C', 'Jack', 50); select * from [dbo].[example] -- THE BELOW SECTION GENERATES THE DESIRED RESULTS WHICH I'D LIKE TO ACHIEVE THROUGH A PIVOT OR LOOP --- -- I HAVE MONTHS FROM 201801 through 202103, SO I'D LIKE TO ITERATE THROUGH THEM AND PRODUCE THE DESIRED RESULT SET PROGRAMMATICALLY --- IF OBJECT_ID('tempdb..#temp1') IS NOT NULL drop table #temp1 IF OBJECT_ID('tempdb..#temp2') IS NOT NULL drop table #temp2 IF OBJECT_ID('tempdb..#temp3') IS NOT NULL drop table #temp3 select cast(Grade as varchar(max)) as Grade ,cast(Name as varchar(max)) as Name ,'SUM' as Metric ,cast(sum(Amount) as varchar(max)) as '201901' into #temp1 from [dbo].[example] where MonthEnd = '201901' group by cast(Grade as varchar(max)) ,cast(Name as varchar(max)) union all select cast(Grade as varchar(max)) as Grade ,cast(Name as varchar(max)) as Name ,'AVG' as Metric ,cast(avg(Amount) as varchar(max)) as '201901' from [dbo].[example] where MonthEnd = '201901' group by cast(Grade as varchar(max)) ,cast(Name as varchar(max)) select cast(Grade as varchar(max)) as Grade ,cast(Name as varchar(max)) as Name ,'SUM' as Metric ,cast(sum(Amount) as varchar(max)) as '201902' into #temp2 from [dbo].[example] where MonthEnd = '201902' group by cast(Grade as varchar(max)) ,cast(Name as varchar(max)) union all select cast(Grade as varchar(max)) as Grade ,cast(Name as varchar(max)) as Name ,'AVG' as Metric ,cast(avg(Amount) as varchar(max)) as '201902' from [dbo].[example] where MonthEnd = '201902' group by cast(Grade as varchar(max)) ,cast(Name as varchar(max)) select cast(Grade as varchar(max)) as Grade ,cast(Name as varchar(max)) as Name ,'SUM' as Metric ,cast(sum(Amount) as varchar(max)) as '201903' into #temp3 from [dbo].[example] where MonthEnd = '201903' group by cast(Grade as varchar(max)) ,cast(Name as varchar(max)) union all select cast(Grade as varchar(max)) as Grade ,cast(Name as varchar(max)) as Name ,'AVG' as Metric ,cast(avg(Amount) as varchar(max)) as '201903' from [dbo].[example] where MonthEnd = '201903' group by cast(Grade as varchar(max)) ,cast(Name as varchar(max)) select a.Grade ,a.Name ,a.Metric ,a.[201901] ,b.[201902] ,c.[201903] from #temp1 a left join #temp2 b on a.Grade = b.Grade and a.Name = b.Name and a.Metric = b.Metric left join #temp3 c on a.Grade = c.Grade and a.Name = c.Name and a.Metric = c.Metric
Advertisement
Answer
I was able to use pivot approach to generate the desired result