问题
This question evolved from this one.
I have two tables that I need to query and glean some calculated sums from; I need a result set based on units -- one row for each Unit, with calculated data for them folded into that row.
The two tables contain the following pertinent members:
CustomerCategoryLog:
Unit varchar(25)
MemberNo varchar(10)
Category varchar(50)
Subcategory varchar(50)
BeginDate Datetime
EndDate Datetime
ReportingMonthlySales:
Unit (VarChar)
MemberNo (VarChar)
MonthlySales (Money)
CYear (Int)
Cmonth (Int)
For each Unit (which has many rows in both tables, one for each MemberNo, but comprises a single row in the result set), I need to populate four columns: New, Assumed, Existing, and Organic. These values are the sums of all Members for the Unit based on those belonging to the corresponding "Subcategory" field. The CustomerCategoryLog table's BeginDate/EndDate values are used for determining what Subcategory the Unit/Member was a part of during the month/year being evaluated.
So a simplified form of the result set looks like this:
Unit New Assumed Existing Organic Total
---- --- ------- -------- ------- -----
Abuelos $22 $44 $33 $11 $110
Gramps $12 $23 $1 $34 $70
. . .
To put the problem in English, it's something like:
Given the month and year provided as parameters by the user (such as "1" for Month (January) and "2016" for year), find out for each Unit how much $ there was in MonthlySales for each Subcategory within that month (where the BeginDate was less than or equal to the Month/Year date supplied by the user AND the EndDate was greater than or equal to the Month/Year date supplied).
So it seems that I will need to create a Date from the Year/Month parameters for comparison with the BeginDate and EndDate values in the CustomerCategoryLog table (The other option would be to alter the CustomerCategoryLog table, so that it has BeginDateMonth, BeginDateYear, EndDateMonth, and EndDateYear ints; but I reckon there must be a somewhat straightforward way to create a date from the Year/Month parameters supplied).
My problem is how to actually construct that in TSQL. I'm not a SQLhead, and my best (pseudosql) stab at it is:
DECLARE @Unit varchar(30);
DECLARE @Year Int;
DECLARE @Month Int;
. . .
DECLARE @PARAMDATE DATETIME = (Year + Month + 01).ToDateTime();
SELECT DISTINCT UNIT INTO #UNITS U FROM ReportingMonthlySales
WHILE NOT U.EOF DO
Unit = U.Unit
SELECT Unit, MonthlySales as 'NewSales' FROM (SELECT MonthlySales FROM ReportingMonthlySales RMS left join
CustomerCategoryLog CCL on RMS.Unit = CCL.Unit WHERE RMS.Unit = Unit AND RMS.CYear = @Year and RMS.CMonth = @Month
AND CCL.BeginDate >= PARAMDATE AND CCL.EndDate <= PARAMDATE AND CCL.Subcategory = 'New'),
MonthlySales as 'AssumedSales' FROM (SELECT MonthlySales FROM ReportingMonthlySales RMS left join
CustomerCategoryLog CCL on RMS.Unit = CCL.Unit WHERE RMS.Unit = Unit AND RMS.CYear = @Year and RMS.CMonth = @Month
AND CCL.BeginDate >= PARAMDATE AND CCL.EndDate <= PARAMDATE AND CCL.Subcategory = 'Assumed'),
MonthlySales as 'ExistingSales' FROM (SELECT MonthlySales FROM ReportingMonthlySales RMS left join
CustomerCategoryLog CCL on RMS.Unit = CCL.Unit WHERE RMS.Unit = Unit AND RMS.CYear = @Year and RMS.CMonth = @Month
AND CCL.BeginDate >= PARAMDATE AND CCL.EndDate <= PARAMDATE AND CCL.Subcategory = 'Existing'),
MonthlySales as 'OrganicSales' FROM (SELECT MonthlySales FROM ReportingMonthlySales RMS left join
CustomerCategoryLog CCL on RMS.Unit = CCL.Unit WHERE RMS.Unit = Unit AND RMS.CYear = @Year and RMS.CMonth = @Month
AND CCL.BeginDate >= PARAMDATE AND CCL.EndDate <= PARAMDATE AND CCL.Subcategory = 'Organic')
FROM ReportingMonthlySales RMS2
ORDER BY RMS2.Unit
END WHILENOTEOF
I know this is not quite right, and probably not even remotely right, but hopefully it's clear enough for a SQL expert/jr. mind reader to understand what it is I need to do/am trying to do.
UPDATE
Here's some sample data from the two tables that are queried:
CustomerCategoryLog table:
MemberNo = 007
Unit = AMC THEATERS
Subcategory = New
BeginDate = 1/1/2016
EndDate = 12/31/2016
MemberNo = 029
Unit = FOODBUY HMS
Subcategory = Existing
BeginDate = 1/1/2015
EndDate = 12/31/2015
ReportingMonthlySales table:
Unit = AMC THEATERS
MemberNo = 007
MonthlySales = $988.82
CYear = 2016
Cmonth = 1
Unit = FOODBUY HMS
MemberNo = 029
MonthlySales = $61,479.28
CYear = 2017
Cmonth = 3
回答1:
This just looks like the long way to pivot.
How about something like this?
declare @Unit varchar(30);
declare @Year int;
declare @Month int;
declare @paramdate datetime = datefromparts(@year, @month, 1);
/* --prior to sql server 2012
declare @paramdate datetime;
set @paramdate = convert(datetime,convert(char(4),@Year)
+right('0'+convert(varchar(2),@month),2)
+'01')
*/
select distinct unit
into #Units
from ReportingMonthlySales;
select
u.Unit
, New = sum(case when ccl.Subcategory = 'New' then rms.MonthlySales else 0 end)
, Assumed = sum(case when ccl.Subcategory = 'Assumed' then rms.MonthlySales else 0 end)
, Existing = sum(case when ccl.Subcategory = 'Existing' then rms.MonthlySales else 0 end)
, Organic = sum(case when ccl.Subcategory = 'Organic' then rms.MonthlySales else 0 end)
from #Units u
left join CustomerCategoryLog ccl
on u.Unit = ccl.Unit
and @paramdate >= ccl.begindate
and @paramdate <= ccl.enddate
left join ReportingMonthlySales rms
on u.Unit = rms.Unit
and rms.cyear = @year
and rms.cmonth = @month
group by u.unit;
来源:https://stackoverflow.com/questions/43056615/how-can-i-loop-through-a-table-within-a-stored-procedure