Skip to content
Advertisement

Loop to create new columns

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

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement