Populating columns of one table with rows from another. Based on criteria - sql-server-2008
Good morning. Sorry for the long post but I am getting completely stomped on how to accomplish this properly.
I have a user submitted file for financial forecast by project and general ledger account by month for up to 15 years out that gets loaded into a flat staging table.
--Flat Staging Table with user submitted forecast
CREATE TABLE dbo.[STG_fcst](
[PROJ_ID] [nvarchar](50) NOT NULL,
[ACT_ID] [nvarchar](10) NOT NULL,
[FC_DATE] [nvarchar](20) NOT NULL,
[AMT_USD] [numeric](20, 2) NULL,
[UPDATEID] [nvarchar](50) NULL,
[DTSTAMP] [datetime] NULL
) ON [PRIMARY]
GO
Only one column for Dates. Users just provide year and month. On the other end I have a pivoted table that is segregated by forecast folder that looks like this
CREATE TABLE dbo.[FORECAST](
[PLANKEY] [varchar](60) NOT NULL,--Plankey=Folderkey+project_id+proj_id
[PROJ_ID] [varchar](50) NOT NULL,
[ACT_ID] [varchar](10) NOT NULL,
[Y1_ACT_JAN] [numeric](20, 2) NULL,
[Y1_ACT_FEB] [numeric](20, 2) NULL,
[Y1_ACT_MAR] [numeric](20, 2) NULL,
[Y1_ACT_APR] [numeric](20, 2) NULL,
[Y1_ACT_MAY] [numeric](20, 2) NULL,
[Y1_ACT_JUN] [numeric](20, 2) NULL,
[Y1_ACT_JUL] [numeric](20, 2) NULL,
[Y1_ACT_AUG] [numeric](20, 2) NULL,
[Y1_ACT_SEP] [numeric](20, 2) NULL,
[Y1_ACT_OCT] [numeric](20, 2) NULL,
[Y1_ACT_NOV] [numeric](20, 2) NULL,
[Y1_ACT_DEC] [numeric](20, 2) NULL,
[Y1_FC_JAN] [numeric](20, 2) NULL,
[Y1_FC_FEB] [numeric](20, 2) NULL,
[Y1_FC_MAR] [numeric](20, 2) NULL,
[Y1_FC_APR] [numeric](20, 2) NULL,
[Y1_FC_MAY] [numeric](20, 2) NULL,
[Y1_FC_JUN] [numeric](20, 2) NULL,
[Y1_FC_JUL] [numeric](20, 2) NULL,
[Y1_FC_AUG] [numeric](20, 2) NULL,
[Y1_FC_SEP] [numeric](20, 2) NULL,
[Y1_FC_OCT] [numeric](20, 2) NULL,
[Y1_FC_NOV] [numeric](20, 2) NULL,
[Y1_FC_DEC] [numeric](20, 2) NULL,
[Y2_FC_JAN] [numeric](20, 2) NULL,
[Y2_FC_FEB] [numeric](20, 2) NULL,
[Y2_FC_MAR] [numeric](20, 2) NULL,
[Y2_FC_APR] [numeric](20, 2) NULL,
[Y2_FC_MAY] [numeric](20, 2) NULL,
[Y2_FC_JUN] [numeric](20, 2) NULL,
[Y2_FC_JUL] [numeric](20, 2) NULL,
[Y2_FC_AUG] [numeric](20, 2) NULL,
[Y2_FC_SEP] [numeric](20, 2) NULL,
[Y2_FC_OCT] [numeric](20, 2) NULL,
[Y2_FC_NOV] [numeric](20, 2) NULL,
[Y2_FC_DEC] [numeric](20, 2) NULL,
[Y3_FC] [numeric](20, 2) NULL,
[Y4_FC] [numeric](20, 2) NULL,
[Y5_FC] [numeric](20, 2) NULL,
[Y6_FC] [numeric](20, 2) NULL,
[Y7_FC] [numeric](20, 2) NULL,
[Y8_FC] [numeric](20, 2) NULL,
[Y9_FC] [numeric](20, 2) NULL,
[Y10_FC] [numeric](20, 2) NULL,
[Y11_FC] [numeric](20, 2) NULL,
[Y12_FC] [numeric](20, 2) NULL,
[Y13_FC] [numeric](20, 2) NULL,
[Y14_FC] [numeric](20, 2) NULL,
[Y15_FC] [numeric](20, 2) NULL,
[UPDATEID] [varchar](25) NOT NULL,
[DTSTAMP] [datetime] NOT NULL,
CONSTRAINT [PK_FORECAST] PRIMARY KEY CLUSTERED
(
[PLANKEY] ASC,
[PROJ_ID] ASC,
[ACT_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
It is a 15 year forecast table segregated by plan_key which denotes basically forecast folder(i.e. Jan Fcst, May fcst etc.)
First two calendar years for each forecast folder is by month years 3 to 15 have to be aggregated by year.
I also have a table that tells me for each folder what the first forecasted month should be and a counter of how many month need to be by month so if the first forecasted month is Feb then counter is 24 if March then 23.
CREATE table dbo.[FOLDER_FCST_DT_XREF_VW]
(FOLDERKEY varchar(255),
(FOLDERNAME VARCHAR(255),
FCST_BASE_DATE DATE,
CTR_STOP INT)
So the question is how I would take data in a staging table and load it into forecast table I need to start loading into appropriate bucket based on the forecast base date so If Base Date is March 2016 I need to grab March 2016 from the staging table ignoring any prior month if any put that into Y1_FC_MAR column for the particular project/account combination. Increment that start date by one month however many times counter goes in xref table updating the rest of the monthly columns in Forecast table after counter runs out need to aggregate staging table by year for those dates and populate yearly buckets.
Here is sample data for the tables.
--Data for Folder Table
insert into dbo.[FOLDER_FCST_DT_XREF_VW]
(FOLDERKEY,FOLDERNAME,FCST_BASE_DATE,CTR_STOP)
Values
('AA99','Study Scenario Estimates (2016)',2016-06-01,'19'),
('AB05','2015 Feb Refresh',2015-02-01,'23'),
('AB06','2015 March Refresh',2015-03-01,'22'),
('AB07','2015 May Forecast',2015-04-01,'21'),
('AB08','2015 May Refresh',2015-05-01,'20'),
('AB09','2015 Jun Refresh',2015-06-01,'19'),
('AB10','2015 Aug Forecast',2015-07-01,'18'),
('AB11','2015 Aug Refresh',2015-08-01,'17'),
('AB12','2015 Sept Refresh',2015-09-01,'16'),
('AB13','2015 Nov Forecast',2015-10-01,'15'),
('AB14','2015 Dec Refresh',2015-12-01,'13'),
('AB16','2015 Actuals',2016-01-01,'24'),
('AB17','2016 Feb Tally',2016-02-01,'23'),
('AB18','2016 Feb Refresh',2016-02-01,'23'),
('AB19','2016 March Refresh',2016-03-01,'22'),
('AB20','2016 May Forecast',2016-04-01,'21'),
('AB21','2016 June Refresh',2016-06-01,'19'),
('AB22','2016 Aug Forecast',2016-07-01,'18'),
('AB23','2016 Sep Refresh',2016-09-01,'16'),
('AB24','2016 Nov Forecast',2016-10-01,'15'),
('AB25','2016 Dec Refresh',2016-11-01,'14')
--Data for Staging Table
insert into dbo.[STG_fcst](Proj_id,Act_Id,FC_Date)
values
('Project51','G1000','2017.03',150),
('Project7','G1000','2017.03',1867726.45),
('Project8','G1000','2017.03',168827.4),
('Project10','G1000','2017.03',38070.41),
('Project32','G1000','2017.03',13574.25),
('Project44','G1000','2017.03',23405.95),
('Project45','G1000','2017.03',164787.89),
('Project55','G1000','2017.03',76364),
('Project50','G1000','2017.03',16714.98),
('Project59','G1000','2017.03',104135.17),
('Project74','G1000','2017.03',65706),
('Project73','G1000','2017.03',5775),
('Project79','G1000','2017.03',91918.11),
('Project108','G1000','2017.03',27279),
('Project110','G1000','2017.03',142071.75),
('Project16','G1000','2017.03',45931.49),
('Project17','G1000','2017.03',141555.9),
('Project63','G1000','2017.03',423716.64),
('Project72','G1000','2017.03',25000),
('Project18','G1006','2017.03',100000),
('Project130','G1000','2017.03',92710.75),
('Project106','G1006','2017.03',44209.5),
('Project36','G1000','2017.03',207394.05),
('Project93','G1006','2017.03',63300),
('Project129','G1000','2017.03',29137.75),
('Project20','G1006','2017.03',34584),
('Project38','G1000','2017.03',57324.15),
('Project22','G1000','2017.03',169847.4),
('Project28','G1000','2017.03',49000),
('Project131','G1000','2017.03',NULL),
('Project35','G1000','2017.03',81950),
('Project57','G1006','2017.03',700),
('Project95','G1000','2017.03',21500),
('Project29','G1005','2017.03',51000),
('Project84','G1006','2017.03',47994),
('Project128','G1000','2017.03',75000),
('Project103','G1000','2017.03',37500),
('Project89','G1006','2017.03',20500),
('Project88','G1006','2017.03',42444),
('Project99','G1006','2017.03',42500),
('Project47','G1000','2017.03',56086),
('Project69','G1006','2017.03',51107),
('Project70','G1000','2017.03',14400),
('Project82','G1006','2017.03',42382),
('Project102','G1006','2017.03',7823.55),
('Project56','G1006','2017.03',8749),
('Project78','G1006','2017.03',31867),
('Project76','G1006','2017.03',20000),
('Project5','G1000','2017.03',84764),
('Project105','G1000','2017.03',3630),
('Project7','G1000','2017.06',1886317.88),
('Project8','G1000','2017.06',133876.9),
('Project65','G1000','2017.06',36573.78),
('Project12','G1000','2017.06',20000),
('Project13','G1006','2017.06',154300),
('Project45','G1000','2017.06',275020),
('Project55','G1000','2017.06',31994.89),
('Project48','G1000','2017.06',50000),
('Project50','G1000','2017.06',67140.72),
('Project59','G1000','2017.06',21168),
('Project74','G1000','2017.06',54755),
('Project73','G1000','2017.06',3000),
('Project79','G1000','2017.06',7993.3),
('Project80','G1000','2017.06',250000),
('Project104','G1000','2017.06',125000),
('Project110','G1000','2017.06',94714.5),
('Project118','G1000','2017.06',50000),
('Project115','G1000','2017.06',25000),
('Project15','G1000','2017.06',46000),
('Project16','G1000','2017.06',57639.53),
('Project58','G1000','2017.06',100000),
('Project17','G1000','2017.06',116003),
('Project63','G1000','2017.06',239148.28),
('Project126','G1000','2017.06',25000),
('Project18','G1006','2017.06',71876.64),
('Project130','G1000','2017.06',92710.75),
('Project106','G1006','2017.06',19438),
('Project36','G1000','2017.06',207394.05),
('Project93','G1006','2017.06',50000),
('Project129','G1000','2017.06',29137.75),
('Project20','G1006','2017.06',19056),
('Project21','G1006','2017.06',50000),
('Project38','G1000','2017.06',43953.56),
('Project22','G1000','2017.06',158935.4),
('Project28','G1000','2017.06',49000),
('Project46','G1000','2017.06',44175.23),
('Project42','G1000','2017.06',905600),
('Project131','G1000','2017.06',181666.67),
('Project35','G1000','2017.06',81945.19),
('Project26','G1000','2017.06',10000),
('Project112','G1000','2017.06',20000),
('Project85','G1006','2017.06',40000),
('Project92','G1006','2017.06',67143),
('Project113','G1000','2017.06',90000),
('Project83','G1006','2017.06',5000),
('Project29','G1005','2017.06',45000),
('Project103','G1000','2017.06',37500),
('Project87','G1006','2017.06',20000),
('Project121','G1000','2017.06',75000),
('Project119','G1000','2017.06',5000),
('Project120','G1000','2017.06',3000),
('Project123','G1000','2017.06',75000),
('Project122','G1000','2017.06',15000),
('Project124','G1000','2017.06',15000),
('Project125','G1000','2017.06',3000),
('Project47','G1000','2017.06',15160),
('Project107','G1000','2017.06',27000),
('Project69','G1006','2017.06',22550),
('Project70','G1000','2017.06',30000),
('Project102','G1006','2017.06',86059.05),
('Project78','G1006','2017.06',98515),
('Project51','G1000','2017.09',60000),
('Project7','G1000','2017.09',1903395.51),
('Project8','G1000','2017.09',117317.6),
('Project65','G1000','2017.09',36573.78),
('Project9','G1000','2017.09',192479.65),
('Project10','G1000','2017.09',42268.65),
('Project11','G1000','2017.09',16745),
('Project34','G1000','2017.09',75000),
('Project48','G1000','2017.09',75000),
('Project73','G1000','2017.09',3000),
('Project80','G1000','2017.09',150000),
('Project104','G1000','2017.09',100000),
('Project110','G1000','2017.09',78928.75),
('Project118','G1000','2017.09',75000),
('Project114','G1000','2017.09',125000),
('Project115','G1000','2017.09',50000),
('Project117','G1000','2017.09',150000),
('Project116','G1000','2017.09',40000),
('Project15','G1000','2017.09',25000),
('Project58','G1000','2017.09',100000),
('Project17','G1000','2017.09',97372.66),
('Project63','G1000','2017.09',115052.53),
('Project72','G1000','2017.09',100000),
('Project126','G1000','2017.09',25000),
('Project130','G1000','2017.09',92710.75),
('Project36','G1000','2017.09',207394.05),
('Project93','G1006','2017.09',100780),
('Project129','G1000','2017.09',29137.75),
('Project20','G1006','2017.09',25000),
('Project38','G1000','2017.09',47953.56),
('Project22','G1000','2017.09',700641.24),
('Project66','G1000','2017.09',9631.35),
('Project131','G1000','2017.09',181666.67),
('Project112','G1000','2017.09',30000),
('Project85','G1006','2017.09',10000),
('Project92','G1006','2017.09',52143),
('Project113','G1000','2017.09',100000),
('Project29','G1005','2017.09',25000),
('Project84','G1006','2017.09',80604),
('Project103','G1000','2017.09',37500),
('Project87','G1006','2017.09',20000),
('Project121','G1000','2017.09',75000),
('Project119','G1000','2017.09',10000),
('Project123','G1000','2017.09',75000),
('Project122','G1000','2017.09',35000),
('Project124','G1000','2017.09',30000),
('Project125','G1000','2017.09',17000),
('Project47','G1000','2017.09',30520),
('Project107','G1000','2017.09',28000),
('Project69','G1006','2017.09',48389),
('Project82','G1006','2017.09',42382),
('Project102','G1006','2017.09',86059.05),
('Project78','G1006','2017.09',32839),
('Project5','G1000','2017.09',50858.4),
('Project7','G1000','2017.12',1843590.45),
('Project8','G1000','2017.12',36933),
('Project65','G1000','2017.12',18286.96),
('Project10','G1000','2017.12',792277.82),
('Project11','G1000','2017.12',15000),
('Project34','G1000','2017.12',75000),
('Project45','G1000','2017.12',308237.74),
('Project48','G1000','2017.12',75000),
('Project73','G1000','2017.12',3000),
('Project80','G1000','2017.12',150000),
('Project104','G1000','2017.12',100000),
('Project118','G1000','2017.12',150000),
('Project114','G1000','2017.12',125000),
('Project115','G1000','2017.12',75000),
('Project117','G1000','2017.12',150000),
('Project116','G1000','2017.12',80000),
('Project15','G1000','2017.12',31000),
('Project16','G1000','2017.12',9006.17),
('Project58','G1000','2017.12',100000),
('Project31','G1000','2017.12',41428.41),
('Project17','G1000','2017.12',54301.94),
('Project63','G1000','2017.12',55555.63),
('Project72','G1000','2017.12',200000),
('Project126','G1000','2017.12',25000),
('Project19','G1000','2017.12',561577.32),
('Project130','G1000','2017.12',92710.75),
('Project106','G1006','2017.12',4900),
('Project36','G1000','2017.12',224050.93),
('Project129','G1000','2017.12',29137.75),
('Project20','G1006','2017.12',25000),
('Project86','G1000','2017.12',2000),
('Project21','G1006','2017.12',50000),
('Project38','G1000','2017.12',63851.19),
('Project22','G1000','2017.12',125000),
('Project24','G1006','2017.12',50000),
('Project46','G1000','2017.12',44175.23),
('Project42','G1000','2017.12',59921),
('Project131','G1000','2017.12',181666.67),
('Project26','G1000','2017.12',10000),
('Project112','G1000','2017.12',50000),
('Project85','G1006','2017.12',45000),
('Project92','G1006','2017.12',52143),
('Project113','G1000','2017.12',100000),
('Project83','G1006','2017.12',5000),
('Project41','G1000','2017.12',500),
('Project29','G1005','2017.12',20000),
('Project84','G1006','2017.12',67916),
('Project103','G1000','2017.12',37500),
('Project87','G1006','2017.12',10000),
('Project121','G1000','2017.12',75000),
('Project119','G1000','2017.12',25000),
('Project123','G1000','2017.12',100000),
('Project122','G1000','2017.12',30000),
('Project124','G1000','2017.12',15000),
('Project125','G1000','2017.12',10000),
('Project47','G1000','2017.12',21400),
('Project102','G1006','2017.12',86059.05),
('Project78','G1006','2017.12',22000),
('Project5','G1000','2017.12',60394.35),
('Project51','G1000','2018.12',80000),
('Project7','G1000','2018.12',6899543.92),
('Project8','G1000','2018.12',81123.9),
('Project65','G1000','2018.12',105950.62),
('Project11','G1000','2018.12',31007),
('Project34','G1000','2018.12',150000),
('Project48','G1000','2018.12',100000),
('Project104','G1000','2018.12',100000),
('Project118','G1000','2018.12',525000),
('Project115','G1000','2018.12',150000),
('Project117','G1000','2018.12',250000),
('Project116','G1000','2018.12',80000),
('Project16','G1000','2018.12',60576.98),
('Project58','G1000','2018.12',120000),
('Project31','G1000','2018.12',141714.83),
('Project17','G1000','2018.12',551764.83),
('Project63','G1000','2018.12',586148.48),
('Project72','G1000','2018.12',360000),
('Project126','G1000','2018.12',50000),
('Project19','G1000','2018.12',326584.77),
('Project130','G1000','2018.12',370843),
('Project36','G1000','2018.12',846233.08),
('Project129','G1000','2018.12',116551),
('Project20','G1006','2018.12',70000),
('Project21','G1006','2018.12',400000),
('Project38','G1000','2018.12',120000),
('Project22','G1000','2018.12',930069.86),
('Project24','G1006','2018.12',287500),
('Project46','G1000','2018.12',13382.28),
('Project42','G1000','2018.12',533701),
('Project131','G1000','2018.12',545000),
('Project112','G1000','2018.12',200000),
('Project29','G1005','2018.12',150000),
('Project84','G1006','2018.12',214133),
('Project128','G1000','2018.12',75000),
('Project82','G1006','2018.12',84764),
('Project102','G1006','2018.12',388942.2),
('Project5','G1000','2018.12',144310.71),
('Project51','G1000','2019.12',60000),
('Project7','G1000','2019.12',4782397.34),
('Project31','G1000','2019.12',78014.19),
('Project17','G1000','2019.12',522097.43),
('Project63','G1000','2019.12',504668.12),
('Project72','G1000','2019.12',244500),
('Project19','G1000','2019.12',600528.16),
('Project36','G1000','2019.12',190405.42),
('Project20','G1006','2019.12',70000),
('Project21','G1006','2019.12',500000),
('Project38','G1000','2019.12',180000),
('Project22','G1000','2019.12',973906.04),
('Project24','G1006','2019.12',500000),
('Project42','G1000','2019.12',335626),
('Project112','G1000','2019.12',200000),
('Project29','G1005','2019.12',150000),
('Project128','G1000','2019.12',75000),
('Project7','G1000','2020.12',1449182.69),
('Project17','G1000','2020.12',522097.43),
('Project63','G1000','2020.12',473304.12),
('Project72','G1000','2020.12',244500),
('Project19','G1000','2020.12',352075.36),
('Project36','G1000','2020.12',387872.15),
('Project20','G1006','2020.12',20000),
('Project21','G1006','2020.12',500000),
('Project38','G1000','2020.12',180000),
('Project22','G1000','2020.12',350673.36),
('Project24','G1006','2020.12',600000),
('Project42','G1000','2020.12',35952),
('Project29','G1005','2020.12',150000),
('Project17','G1000','2021.12',522097.43),
('Project63','G1000','2021.12',457054.12),
('Project72','G1000','2021.12',244500),
('Project19','G1000','2021.12',648372.55),
('Project21','G1006','2021.12',500000),
('Project24','G1006','2021.12',600000)
Thank you very much for your help.
At first I thought about doing this with dynamic SQL, but I think you can do it static
What you want to do is pivot and aggregate. Since it is a highly specialized pivot, I would not try to do it with the Pivot command. So I pivot by using aggregations and group by.
Here is my attempt. I cannot fill out UPDATEID and DTSTMp, and the plankey apparently has to be made by using both project_id and proj_id, and you have only supplied proj_id, but besides that I think this should give you something to work with:
select
b.FOLDERKEY + a.PROJ_ID PLANKEY
,b.FOLDERNAME
,a.PROJ_ID
,a.ACT_ID
,sum(case when b.Base_Month<=1 and cast(a.fc_date+'.01' as date)=dateadd(month,0,b.base_start) then a.AMT_USD else 0 end) Y1_ACT_JAN
,sum(case when b.Base_Month<=2 and cast(a.fc_date+'.01' as date)=dateadd(month,1,b.base_start) then a.AMT_USD else 0 end) Y1_ACT_FEB
,sum(case when b.Base_Month<=3 and cast(a.fc_date+'.01' as date)=dateadd(month,2,b.base_start) then a.AMT_USD else 0 end) Y1_ACT_MAR
,sum(case when b.Base_Month<=4 and cast(a.fc_date+'.01' as date)=dateadd(month,3,b.base_start) then a.AMT_USD else 0 end) Y1_ACT_APR
,sum(case when b.Base_Month<=5 and cast(a.fc_date+'.01' as date)=dateadd(month,4,b.base_start) then a.AMT_USD else 0 end) Y1_ACT_MAY
,sum(case when b.Base_Month<=6 and cast(a.fc_date+'.01' as date)=dateadd(month,5,b.base_start) then a.AMT_USD else 0 end) Y1_ACT_JUN
,sum(case when b.Base_Month<=7 and cast(a.fc_date+'.01' as date)=dateadd(month,6,b.base_start) then a.AMT_USD else 0 end) Y1_ACT_JUL
,sum(case when b.Base_Month<=8 and cast(a.fc_date+'.01' as date)=dateadd(month,7,b.base_start) then a.AMT_USD else 0 end) Y1_ACT_AUG
,sum(case when b.Base_Month<=9 and cast(a.fc_date+'.01' as date)=dateadd(month,8,b.base_start) then a.AMT_USD else 0 end) Y1_ACT_SEP
,sum(case when b.Base_Month<=10 and cast(a.fc_date+'.01' as date)=dateadd(month,9,b.base_start) then a.AMT_USD else 0 end) Y1_ACT_OCT
,sum(case when b.Base_Month<=11 and cast(a.fc_date+'.01' as date)=dateadd(month,10,b.base_start) then a.AMT_USD else 0 end) Y1_ACT_NOV
,sum(case when cast(a.fc_date+'.01' as date)=dateadd(month,11,b.base_start) then a.AMT_USD else 0 end) Y1_ACT_DEC
,sum(case when cast(a.fc_date+'.01' as date)=dateadd(month,12,b.base_start) then a.AMT_USD else 0 end) Y2_ACT_JAN
,sum(case when cast(a.fc_date+'.01' as date)=dateadd(month,13,b.base_start) then a.AMT_USD else 0 end) Y2_ACT_FEB
,sum(case when cast(a.fc_date+'.01' as date)=dateadd(month,14,b.base_start) then a.AMT_USD else 0 end) Y2_ACT_MAR
,sum(case when cast(a.fc_date+'.01' as date)=dateadd(month,15,b.base_start) then a.AMT_USD else 0 end) Y2_ACT_APR
,sum(case when cast(a.fc_date+'.01' as date)=dateadd(month,16,b.base_start) then a.AMT_USD else 0 end) Y2_ACT_MAY
,sum(case when cast(a.fc_date+'.01' as date)=dateadd(month,17,b.base_start) then a.AMT_USD else 0 end) Y2_ACT_JUN
,sum(case when cast(a.fc_date+'.01' as date)=dateadd(month,18,b.base_start) then a.AMT_USD else 0 end) Y2_ACT_JUL
,sum(case when cast(a.fc_date+'.01' as date)=dateadd(month,19,b.base_start) then a.AMT_USD else 0 end) Y2_ACT_AUG
,sum(case when cast(a.fc_date+'.01' as date)=dateadd(month,20,b.base_start) then a.AMT_USD else 0 end) Y2_ACT_SEP
,sum(case when cast(a.fc_date+'.01' as date)=dateadd(month,21,b.base_start) then a.AMT_USD else 0 end) Y2_ACT_OCT
,sum(case when cast(a.fc_date+'.01' as date)=dateadd(month,22,b.base_start) then a.AMT_USD else 0 end) Y2_ACT_NOV
,sum(case when cast(a.fc_date+'.01' as date)=dateadd(month,23,b.base_start) then a.AMT_USD else 0 end) Y2_ACT_DEC
, sum(case when year(cast(a.fc_date+'.01' as date))=b.Base_Year+2 then a.AMT_USD else 0 end) [Y3_FC]
, sum(case when year(cast(a.fc_date+'.01' as date))=b.Base_Year+3 then a.AMT_USD else 0 end) [Y4_FC]
, sum(case when year(cast(a.fc_date+'.01' as date))=b.Base_Year+4 then a.AMT_USD else 0 end) [Y5_FC]
, sum(case when year(cast(a.fc_date+'.01' as date))=b.Base_Year+5 then a.AMT_USD else 0 end) [Y6_FC]
, sum(case when year(cast(a.fc_date+'.01' as date))=b.Base_Year+6 then a.AMT_USD else 0 end) [Y7_FC]
, sum(case when year(cast(a.fc_date+'.01' as date))=b.Base_Year+7 then a.AMT_USD else 0 end) [Y8_FC]
, sum(case when year(cast(a.fc_date+'.01' as date))=b.Base_Year+8 then a.AMT_USD else 0 end) [Y9_FC]
, sum(case when year(cast(a.fc_date+'.01' as date))=b.Base_Year+9 then a.AMT_USD else 0 end) [Y10_FC]
, sum(case when year(cast(a.fc_date+'.01' as date))=b.Base_Year+10 then a.AMT_USD else 0 end) [Y11_FC]
, sum(case when year(cast(a.fc_date+'.01' as date))=b.Base_Year+11 then a.AMT_USD else 0 end) [Y12_FC]
, sum(case when year(cast(a.fc_date+'.01' as date))=b.Base_Year+12 then a.AMT_USD else 0 end) [Y13_FC]
, sum(case when year(cast(a.fc_date+'.01' as date))=b.Base_Year+13 then a.AMT_USD else 0 end) [Y14_FC]
, sum(case when year(cast(a.fc_date+'.01' as date))=b.Base_Year+14 then a.AMT_USD else 0 end) [Y15_FC]
from [dbo].[STG_fcst] a
inner join (select FOLDERKEY,FOLDERNAME,FCST_BASE_DATE,CTR_STOP,year(FCST_BASE_DATE) Base_Year,dateadd(year,datediff(year,0,FCST_BASE_DATE),0) base_start,month(FCST_BASE_DATE) Base_Month from dbo.FOLDER_FCST_DT_XREF_VW) b
on
-- b.FOLDERKEY='AB05'and
cast(a.FC_DATE+'.01' as date)>=b.FCST_BASE_DATE
group by b.FOLDERKEY + a.PROJ_ID
,b.FOLDERNAME
,a.PROJ_ID
,a.ACT_ID
order by PROJ_ID,PLANKEY
Two things make it a little more complicated. I have to cast the FC_DATE to a date, and in stead of just using the BASE_DATE from the plan, i make a subselect where I calculate the base month as an int, and the start of the base year eg Jan 1, 2015.
Using this information I can fill out all the columns
Y1 Jan aggregates all rows with January dates in the base year, only if the base month is january.
Y1 Feb aggregates all rows with february dates in the base year, only if the base month is january or february
...
Y2 Jan aggregates all rows with january dates in the year following the base year
...
Y2 Dec aggregates all rows with december dates in the year following the base year
Y3_FC aggregates all dates with dates in the year of base year + 2
...
Y15_FC aggregates all dates with dates in the year of base year + 14
Related
Conditional grouping in a pivoty query mysql
My schema looks like, CREATE TABLE `test` ( `Id` int(11) NOT NULL, `CategoryName` varchar(45) DEFAULT NULL, `type` varchar(40) DEFAULT NULL, `value` decimal(15,4) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; INSERT INTO `test` (`Id`, `CategoryName`, `type`, `value`) VALUES (1 ,'Allowance' ,'ADDITION',4000), (1,'Salary' ,'ADDITION',1500), (1,'Telephone' ,'ADDITION',200), (1,'Other' ,'ADDITION',500), (1,'Fine' ,'DEDUCTION',500), (1,'Other Deduction' ,'DEDUCTION',500), (1,'Salary Deduction' ,'DEDUCTION',100), (2,'Salary' ,'ADDITION',300), (2,'Other' ,'ADDITION',1300) ; The requirement is to show certain categories summed up and others as is. In this case Salary & Allowance to be shown on their own columns, while any other addition type to be summed up. Same applies to the deduction type. select Id,MAX(CASE WHEN CategoryName = 'Salary' THEN pi.value ELSE 0 END) AS 'Salary', MAX(CASE WHEN CategoryName = 'Allowance' THEN pi.value ELSE 0 END) AS 'Allowance', MAX(CASE when pi.type = 'ADDITION' THEN CASE WHEN CategoryName not in ('Salary','Allowance') THEN pi.value -- sum(pi.value) ELSE 0 END END) AS 'Other Allowances', MAX(case WHEN CategoryName = 'Fine' THEN pi.value -- sum(pi.value) ELSE 0 END) AS 'Fine' , MAX(CASE when pi.type = 'DEDUCTION' THEN CASE WHEN CategoryName not in ( 'Fine') THEN pi.value -- sum(pi.value) ELSE 0 END END) AS 'Other Deductions' from test pi group by Id; Now when i put sum(pi.value) I get error Error Code: 1111. Invalid use of group function. Without the sum function the max is returning the max value only and ignoring the rest, like the Telephone addition, which is as expected. Id Salary Allowance Other Allowances Fine Other Deductions 1 1500.0000 4000.0000 500.0000 500.0000 500.0000 2 300.0000 0.0000 1300.0000 0.0000 *null* So the Other Allowance column for id 1 should show 700 i.e. 500 (Other) + 200 (Telephone) What would be the right way to get the sum in this case while using the pivot query ? dbfiddle
How to Collect Month wise school fee where months are selected from checkboxes?
I am new in this field, I am working on a school fee management system, fee collected from students on month basis, yearly basis etc My MySQL database schema is as follow academic_classes table class_id class_name 1 1st 2 2nd .....and so on Fee_types Table fee_type_id fee_name 1 Admission Fee 2 Tuition Fee 3 Sports Fee class_wise_fee_plan table plan_id class_id fee_id amount 1 1 1 5000 2 1 2 1150 3 1 3 350 fee amount is according to classes according to your suggestion I have add a new table for fee frequency yearly, monthly etc fee_writeoff table fee_writeoff_id fee_id months 1 1 apr 2 2 jan 3 2 feb and so on ... I have 12 checkboxes for months in front end, How to calculate or show together fee values and fee name based on check boxes. I want this type of Results FeeName Apr May Jun ..... Total Admission fee 5000 0 0 5000 Tution Fee 1100 1100 1100 3300 Total 6100 1100 1100 8300 how to create mysql stored procedure if months name selected from checkboxes from front end because months name are comma saparated how to loop through and create cases
Try below query using CASE, it is not a complete solution as you have asked for but this will solve some of your issues. SELECT ft.fee_name, (CASE WHEN apr=1 THEN fee_amount ELSE 0 END) AS apr, (CASE WHEN may=1 THEN fee_amount ELSE 0 END) AS apr, (CASE WHEN jun=1 THEN fee_amount ELSE 0 END) AS apr, (CASE WHEN jul=1 THEN fee_amount ELSE 0 END) AS apr, (CASE WHEN aug=1 THEN fee_amount ELSE 0 END) AS apr, (CASE WHEN apr=1 THEN fee_amount ELSE 0 END) AS apr, FROM fee_type ft INNER JOIN fee_plan fp USING (fee_id) OUTPUT fee_name APR MAY JUNE JULY AUG Admission Fee 5000 0 0 0 0 Tuition Fee 1150 1150 1150 1150 1150
First I've to note that to design a schema you should understand the basics of relational model. When you put your spreadsheet layout to a relational table you won't get it right. So I redesigned you schema in a relational matter. It's not the only possible schema, though it depends on rest of your application. Schema CREATE TABLE `fee` ( `fee_id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `name` VARCHAR(32) NOT NULL, PRIMARY KEY (`fee_id`) ) ENGINE = InnoDB; CREATE TABLE `fee_writeoff` ( `fee_writeoff_id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `fee_id` INT UNSIGNED NULL, `date` DATE NOT NULL, PRIMARY KEY (`fee_writeoff_id`), INDEX `fee_id`(`fee_id`), CONSTRAINT `fee_writeoff_has_fee` FOREIGN KEY (`fee_id`) REFERENCES `fee` (`fee_id`) ON DELETE RESTRICT ON UPDATE CASCADE ) ENGINE = InnoDB; CREATE TABLE `fee_plan` ( `fee_plan_id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `fee_id` INT UNSIGNED NOT NULL, `amount` DECIMAL(10,0) NOT NULL, PRIMARY KEY (`fee_plan_id`), INDEX `fee_id`(`fee_id`), CONSTRAINT `fee_plan_has_fee` FOREIGN KEY (`fee_id`) REFERENCES `fee` (`fee_id`) ON DELETE RESTRICT ON UPDATE CASCADE ) ENGINE = InnoDB; Data INSERT INTO `fee`(`fee_id`, `name`) VALUES (1, 'Admission Fee'), (2, 'Tuition Fee'); INSERT INTO `fee_writeoff`(`fee_id`, `date`) VALUES (1, '2000-04-01'), (2, '2000-01-01'), (2, '2000-02-01'), (2, '2000-03-01'), (2, '2000-04-01'), (2, '2000-05-01'), (2, '2000-06-01'), (2, '2000-07-01'), (2, '2000-08-01'), (2, '2000-09-01'), (2, '2000-10-01'), (2, '2000-11-01'), (2, '2000-12-01'); INSERT INTO `fee_plan`(`fee_id`, `amount`) VALUES (1, 5000), (2, 1150); Query SELECT name, SUM(CASE MONTH(`date`) WHEN 4 THEN amount ELSE 0 END) AS `April`, SUM(CASE MONTH(`date`) WHEN 5 THEN amount ELSE 0 END) AS `May`, SUM(CASE MONTH(`date`) WHEN 6 THEN amount ELSE 0 END) AS `June`, SUM(CASE MONTH(`date`) WHEN 7 THEN amount ELSE 0 END) AS `July`, SUM(CASE MONTH(`date`) WHEN 8 THEN amount ELSE 0 END) AS `August`, SUM(CASE MONTH(`date`) WHEN 9 THEN amount ELSE 0 END) AS `September`, SUM(CASE MONTH(`date`) WHEN 10 THEN amount ELSE 0 END) AS `October`, SUM(CASE MONTH(`date`) WHEN 11 THEN amount ELSE 0 END) AS `November`, SUM(CASE MONTH(`date`) WHEN 12 THEN amount ELSE 0 END) AS `December`, SUM(CASE MONTH(`date`) WHEN 1 THEN amount ELSE 0 END) AS `January`, SUM(CASE MONTH(`date`) WHEN 2 THEN amount ELSE 0 END) AS `February`, SUM(CASE MONTH(`date`) WHEN 3 THEN amount ELSE 0 END) AS `March`, SUM(amount) AS `Total` FROM fee JOIN fee_writeoff USING(fee_id) JOIN fee_plan USING(fee_id) GROUP BY name WITH ROLLUP Here is the SQLFiddle snippet.
Create view with self join and case statements
Sql Server 2008 R2 I have this data: Id AdOrderId AdRunScheduleId CategoryCode EffectiveDate Amount 735935 3811 1629 0 3/7/14 0:00 72.19 735939 3811 1629 2 3/7/14 0:00 10 735942 3811 1629 7 3/7/14 0:00 -14.44 I would like a view that contains 1 row with all 3 records I have tried several things. Several work but all give me 3 separate rows. Here is my latest attempt: -CREATE View [dbo].[DP_AdOrder_Charges] --as SELECT Elem.Id, Elem.AdOrderId, Elem.AdRunScheduleId, Elem.EffectiveDate, Elem.Amount, Elem.CategoryCode, MAX(Case when Elem.CategoryCode = 0 then Elem.Amount End) as AdInsertAmt, MAX(Case when Elem.CategoryCode = 2 then Elem.Amount End) as ColorAmt, MAX(Case when Elem.CategoryCode = 7 then Elem.Amount End) as DiscAmt, MAX(Case when Elem.CategoryCode not in (0,2,7) then Elem.Amount End) as OtherAmt FROM [MNADTEST].[dbo].[RtChargeEntryElem] Elem INNER JOIN [MNADTEST].[dbo].[RtChargeEntryElem] J1 ON Elem.EffectiveDate=J1.EffectiveDate and Elem.Id=J1.Id and Elem.AdRunScheduleId=J1.AdRunScheduleId and Elem.AdOrderId=J1.AdOrderId Where Elem.AdRunScheduleId=1629 and Elem.EffectiveDate='2014-03-07' GROUP BY Elem.Id,Elem.EffectiveDate, Elem.AdOrderId, Elem.AdRunScheduleId, Elem.Amount, Elem.RateTableId, Elem.CategoryCode with this result Id AdOrderId AdRun Effective Amount Category AdInsertAmt ColorAmt DiscAmt OtherAmt ScheduleId Date Code 735935 3811 1629 2014-03-07 72.19 0 72.19 NULL NULL NULL 735939 3811 1629 2014-03-07 10 2 NULL 10 NULL NULL 735942 3811 1629 2014-03-07 -14.44 7 NULL NULL -14.44 NULL I would be grateful for any help. thanks. Barb Here is create table and insert code: CREATE TABLE [dbo].[RtChg]( [Id] [int] NOT NULL, [AdOrderId] [int] NULL, [AdRunScheduleId] [int] NULL, [CategoryCode] [int] NULL, [EffectiveDate] [datetime] NULL, [Amount] [float] NULL ) GO INSERT INTO [dbo].[RtChg] ([Id], [AdOrderId], [AdRunScheduleId], [CategoryCode], [EffectiveDate], [Amount]) VALUES (735935, 3811, 1629, 0, '3/7/14', '72.19'), (735939 ,3811, 1629, 2, '3/7/14', '10.00'), (735942, 3811, 1629, 7, '3/7/14', '-14.44') GO
I have this working. I did not need a self join. Also, I was grouping by a unique id instead of the column I want to capture when the value changes. CREATE View [dbo].[DP_AdOrder_Charges] as SELECT AdOrderId, Elem.AdRunScheduleId, Elem.EffectiveDate, MAX(Case when Elem.CategoryCode = 0 then Elem.Amount End) as AdInsertAmt, MAX(Case when Elem.CategoryCode = 2 then Elem.Amount End) as ColorAmt, MAX(Case when Elem.CategoryCode = 7 then Elem.Amount End) as DiscAmt, MAX(Case when Elem.CategoryCode not in (0,2,7) then Elem.Amount End) as OtherAmt FROM [MNADTEST].[dbo].[RtChargeEntryElem] Elem GROUP BY Elem.AdOrderId, Elem.AdRunScheduleId, Elem.EffectiveDate
How to obtain percents of two sums directly from a MySQL query?
Im calculating the percent of men and woman in my database using first this query: SELECT sum(case when `gender` = 'M' then 1 else 0 end) as male , sum(case when `gender` = 'F' then 1 else 0 end) as female FROM userinfo WHERE id in (10,1,5) Then in php i calculate the percents. But I wonder, is there a way to get directly the percents from the query?
SELECT sum(case when `gender` = 'M' then 1 else 0 end) as male , 100*sum(case when `gender` = 'M' then 1 else 0 end)/count(*) as malepct , sum(case when `gender` = 'F' then 1 else 0 end) as female , 100*sum(case when `gender` = 'F' then 1 else 0 end)/count(*) as femalepct FROM userinfo WHERE id in (10,1,5) ... assuming you don't run this over an empty rowset (division by zero) If you e.g. want to replace invalid (division by zero) values by -1 use if(ifnull(count(*),0)>0,100*sum(case when `gender` = 'M' then 1 else 0 end)/count(*),-1) as malepct
Best way to index and query analytic table in MySQL
I have an analytics table (5M rows and growing) with the following structure Hits id int() NOT NULL AUTO_INCREMENT, hit_date datetime NOT NULL, hit_day int(11) DEFAULT NULL, gender varchar(255) DEFAULT NULL, age_range_id int(11) DEFAULT NULL, klout_range_id int(11) DEFAULT NULL, frequency int(11) DEFAULT NULL, count int(11) DEFAULT NULL, location_id int(11) DEFAULT NULL, source_id int(11) DEFAULT NULL, target_id int(11) DEFAULT NULL, Most queries to the table is to query between two datetimes for a particular sub-set of columns and them sum up all the count column across all rows. For example: SELECT target.id, SUM(CASE gender WHEN 'm' THEN count END) AS 'gender_male', SUM(CASE gender WHEN 'f' THEN count END) AS 'gender_female', SUM(CASE age_range_id WHEN 1 THEN count END) AS 'age_18 - 20', SUM(CASE target_id WHEN 1 then count END) AS 'target_test' SUM(CASE location_id WHEN 1 then count END) AS 'location_NY' FROM Hits WHERE (location_id =1 or location_id = 2) AND (target_id = 40 OR target_id = 22) AND cast(hit_date AS date) BETWEEN '2012-5-4'AND '2012-5-10' GROUP BY target.id The interesting thing about queries to this table is that the where clause include any permutation of Hit columns names and values since those are what we're filtering against. So the particular query above is getting the # of males and females between the ages of 18 and 20 (age_range_id 1) in NY that belongs to a target called "test". However, there are over 8 age groups, 10 klout ranges, 45 locations, 10 sources etc (all foreign key references). I currently have an index on hot_date and another one on target_id. What the best way to properly index this table?. Having a composite index on all column fields seems inherently wrong. Is there any other way to run this query without using a sub-query to sum up all counts? I did some research and this seems to be the best way to get the data-set I need but is there a more efficient way of handling this query?
Here's your optimized query. The idea is to get rid of the ORs and the CAST() function on hit_date so that MySQL can utilize a compound index that covers each of the subsets of data. You'll want a compound index on (location_id, target_id, hit_date) in that order. SELECT id, gender_male, gender_female, `age_18 - 20`, target_test, location_NY FROM ( SELECT target.id, SUM(CASE gender WHEN 'm' THEN 1 END) AS gender_male, SUM(CASE gender WHEN 'f' THEN 1 END) AS gender_female, SUM(CASE age_range_id WHEN 1 THEN 1 END) AS `age_18 - 20`, SUM(CASE target_id WHEN 1 then 1 END) AS target_test, SUM(CASE location_id WHEN 1 then 1 END) AS location_NY FROM Hits WHERE (location_id =1) AND (target_id = 40) AND hit_date BETWEEN '2012-05-04 00:00:00' AND '2012-05-10 23:59:59' GROUP BY target.id UNION ALL SELECT target.id, SUM(CASE gender WHEN 'm' THEN 1 END) AS gender_male, SUM(CASE gender WHEN 'f' THEN 1 END) AS gender_female, SUM(CASE age_range_id WHEN 1 THEN 1 END) AS `age_18 - 20`, SUM(CASE target_id WHEN 1 then 1 END) AS target_test, SUM(CASE location_id WHEN 1 then 1 END) AS location_NY FROM Hits WHERE (location_id = 2) AND (target_id = 22) AND hit_date BETWEEN '2012-05-04 00:00:00' AND '2012-05-10 23:59:59' GROUP BY target.id UNION ALL SELECT target.id, SUM(CASE gender WHEN 'm' THEN 1 END) AS gender_male, SUM(CASE gender WHEN 'f' THEN 1 END) AS gender_female, SUM(CASE age_range_id WHEN 1 THEN 1 END) AS `age_18 - 20`, SUM(CASE target_id WHEN 1 then 1 END) AS target_test, SUM(CASE location_id WHEN 1 then 1 END) AS location_NY FROM Hits WHERE (location_id =1) AND (target_id = 22) AND hit_date BETWEEN '2012-05-04 00:00:00' AND '2012-05-10 23:59:59' GROUP BY target.id UNION ALL SELECT target.id, SUM(CASE gender WHEN 'm' THEN 1 END) AS gender_male, SUM(CASE gender WHEN 'f' THEN 1 END) AS gender_female, SUM(CASE age_range_id WHEN 1 THEN 1 END) AS `age_18 - 20`, SUM(CASE target_id WHEN 1 then 1 END) AS target_test, SUM(CASE location_id WHEN 1 then 1 END) AS location_NY FROM Hits WHERE (location_id = 2) AND (target_id = 22) AND hit_date BETWEEN '2012-05-04 00:00:00' AND '2012-05-10 23:59:59' GROUP BY target.id ) a GROUP BY id If your selection size is so large that this is no improvement, then you may as well keep scanning all rows like you're already doing. Note, surround aliases with back ticks, not single quotes, which are deprecated. I also fixed your CASE clauses which had count instead of 1.