如何在存储过程中循环遍历 table?
How can I loop through a table within a stored procedure?
这个问题从演变而来。
我有两个 table 需要查询并从中收集一些计算总和;我需要一个基于单位的结果集——每个单位一行,并将它们的计算数据折叠到该行中。
两个 table 包含以下相关成员:
CustomerCategoryLog:
Unit varchar(25)
MemberNo varchar(10)
Category varchar(50)
Subcategory varchar(50)
BeginDate Datetime
EndDate Datetime
报告每月销售额:
Unit (VarChar)
MemberNo (VarChar)
MonthlySales (Money)
CYear (Int)
Cmonth (Int)
对于每个单元(在两个 table 中都有很多行,每个 MemberNo 一个,但在结果集中包含一行),我需要填充四列:新的、假设的、现有的和有机。这些值是基于属于相应 "Subcategory" 字段的那些单位的所有成员的总和。 CustomerCategoryLog table 的 BeginDate/EndDate 值用于确定 Unit/Member 在 month/year 评估期间属于哪个子类别。
结果集的简化形式如下所示:
Unit New Assumed Existing Organic Total
---- --- ------- -------- ------- -----
Abuelos 0
Gramps
. . .
把问题用英文写成这样:
给定用户提供的月份和年份参数(例如“1”代表月份(一月),“2016”代表年份),找出每个单位有多少美元在该月内每个子类别的 MonthlySales 中(其中 BeginDate 小于或等于用户提供的 Month/Year 日期并且 EndDate 大于或等于提供的 Month/Year 日期)。
所以我似乎需要从 Year/Month 参数创建一个日期,以便与 CustomerCategoryLog table 中的 BeginDate 和 EndDate 值进行比较(另一种选择是更改 CustomerCategoryLog table,因此它具有 BeginDateMonth、BeginDateYear、EndDateMonth 和 EndDateYear 整数;但我认为必须有一种从提供的 Year/Month 参数创建日期的简单方法。
我的问题是如何在 TSQL 中实际构造它。我不是 SQL 头脑,我最好的(伪 SQL)是:
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
我知道这不太正确,甚至可能不太正确,但希望它足够清楚 SQL expert/jr。介意 reader 了解我需要 do/am 尝试做的事情。
更新
下面是查询的两个 table 的一些示例数据:
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 = 8.82
CYear = 2016
Cmonth = 1
Unit = FOODBUY HMS
MemberNo = 029
MonthlySales = ,479.28
CYear = 2017
Cmonth = 3
这看起来像是一个漫长的转折点。
这样的怎么样?
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;
这个问题从
我有两个 table 需要查询并从中收集一些计算总和;我需要一个基于单位的结果集——每个单位一行,并将它们的计算数据折叠到该行中。
两个 table 包含以下相关成员:
CustomerCategoryLog:
Unit varchar(25)
MemberNo varchar(10)
Category varchar(50)
Subcategory varchar(50)
BeginDate Datetime
EndDate Datetime
报告每月销售额:
Unit (VarChar)
MemberNo (VarChar)
MonthlySales (Money)
CYear (Int)
Cmonth (Int)
对于每个单元(在两个 table 中都有很多行,每个 MemberNo 一个,但在结果集中包含一行),我需要填充四列:新的、假设的、现有的和有机。这些值是基于属于相应 "Subcategory" 字段的那些单位的所有成员的总和。 CustomerCategoryLog table 的 BeginDate/EndDate 值用于确定 Unit/Member 在 month/year 评估期间属于哪个子类别。
结果集的简化形式如下所示:
Unit New Assumed Existing Organic Total
---- --- ------- -------- ------- -----
Abuelos 0
Gramps
. . .
把问题用英文写成这样:
给定用户提供的月份和年份参数(例如“1”代表月份(一月),“2016”代表年份),找出每个单位有多少美元在该月内每个子类别的 MonthlySales 中(其中 BeginDate 小于或等于用户提供的 Month/Year 日期并且 EndDate 大于或等于提供的 Month/Year 日期)。
所以我似乎需要从 Year/Month 参数创建一个日期,以便与 CustomerCategoryLog table 中的 BeginDate 和 EndDate 值进行比较(另一种选择是更改 CustomerCategoryLog table,因此它具有 BeginDateMonth、BeginDateYear、EndDateMonth 和 EndDateYear 整数;但我认为必须有一种从提供的 Year/Month 参数创建日期的简单方法。
我的问题是如何在 TSQL 中实际构造它。我不是 SQL 头脑,我最好的(伪 SQL)是:
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
我知道这不太正确,甚至可能不太正确,但希望它足够清楚 SQL expert/jr。介意 reader 了解我需要 do/am 尝试做的事情。
更新
下面是查询的两个 table 的一些示例数据:
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 = 8.82
CYear = 2016
Cmonth = 1
Unit = FOODBUY HMS
MemberNo = 029
MonthlySales = ,479.28
CYear = 2017
Cmonth = 3
这看起来像是一个漫长的转折点。
这样的怎么样?
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;