如何在存储过程中循环遍历表?

时间:2017-03-27 21:14:39

标签: sql-server tsql subquery sqlparameters sql-subselect

这个问题是从this one演变而来的。

我有两个表需要查询并收集一些计算的总和;我需要一个基于单位的结果集 - 每个单元一行,计算出的数据折叠到该行。

这两个表包含以下相关成员:

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)

对于每个单元(两个表中有很多行,每个MemberNo有一行,但结果集中包含一行),我需要填充四列:New,Assumed,Existing和Organic。这些值是该单位所有成员的总和,基于属于相应的"子类别"领域。 CustomerCategoryLog表的BeginDate / EndDate值用于确定在评估的月/年中单位/成员所属的子类别。

因此,结果集的简化形式如下所示:

Unit    New  Assumed        Existing    Organic     Total
----    ---  -------        --------    -------     -----
Abuelos $22  $44            $33         $11         $110
Gramps  $12  $23            $1          $34         $70
. . .

要用英语解决问题,可以这样:

给定用户提供的月份和年份(例如" 1"月份(1月)和" 2016年"年份),找出每个单位在该月内每个子类别的MonthlySales中有多少$(其中BeginDate小于或等于用户提供的月/年日期且EndDate大于或等于提供的月/年日期)。

因此,似乎我需要从Year / Month参数创建一个Date,以便与CustomerCategoryLog表中的BeginDate和EndDate值进行比较(另一个选项是更改CustomerCategoryLog表,以便它具有BeginDateMonth, BeginDateYear,EndDateMonth和EndDateYear整数;但我认为必须有一种直接的方法从提供的年/月参数创建日期。

我的问题是如何在TSQL中实际构建它。我不是一个SQLhead,而我最好的(pseudosql)就是:

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专家/ jr来说已经足够清楚了。提醒读者理解我需要做什么/我想做什么。

更新

以下是查询的两个表中的一些示例数据:

CustomerCategoryLog表:

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表:

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 个答案:

答案 0 :(得分:4)

这看起来像是一条很长的转轴方式。

这样的事情怎么样?

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;