如何将四个计算值添加到存储过程 (TSQL) 的结果集中?

How can I add four calculated values to a result set from a Stored Proc (TSQL)?

我需要扩展现有的存储过程(即,在旧存储过程的基础上创建一个新的 SP)以包含一些额外的计算数据。需要四个额外的列来提供从 SP 结果生成的报告:

简而言之,该报告显示 MonthlySales,另外四个列根据该行中指定的 "Unit" 的 Category.Subcategory 值填充货币值(每个单位都有其在结果集和报告中拥有自己的行)。

新列是四个类别:New.New、New.Assumed、Existing.Existing 和 Existing.Organic

因此,结果集中的每一行都包含一个单位的数据,并且该单位属于所报告时间段的 Category.Subcategory 值之一(换句话说,这四个包中只有一个会有每行一个值)。

三个 table 参与检索此数据:

MasterUnitProjSales,每个单位都有一个 "NewBiz" 标志(如果为真,则它属于 "New" 系列的两个值;否则,它属于 "Existing" 系列的两个值;因此,Category.Subcategory 值的类别部分可以由此值确定)。

ReportingMonthlySales,每个 Unit/MemberNo 以及年和月数据都有一个 MonthlySales(金钱)字段。

CustomerCategoryLog,其中有 Unit/MemberNo 对,以及 Category 和 Subcategory 字段,以及 BeginDate 和 EndDate 字段,记录在什么 Subcategory.Category Unit/Member 是在 Begin/End 时间范围内。

旧版 SP 的工作方式是将一年的数据存储到临时文件 table,然后将前一年的数据存储到第二个临时文件 table,然后组合它们,然后 return就是这样。

有了这个额外的皱纹,我的想法(伪-SQL,我不是 [T]-SQL-head)是:

("CombinedYears" 是一个 table,它是前两个温度 tables、"CurrentYear" 和 "PriorYear")

Select * from #CombinedYears CY,
NewNew = select MonthlySales from ReportingMonthlySales RMS where Category = 'New' and Subcategory = 'New' and
RMS.Unit = CY.Unit
left join CustomerCategoryLog CCL on RMS.Unit = CCL.Unit,
NewAssumed = select MonthlySales from ReportingMonthlySales RMS where Category = 'New' and Subcategory = 'Assumed' and
RMS.Unit = CY.Unit
left join CustomerCategoryLog CCL on RMS.Unit = CCL.Unit,
ExistingExisting = select MonthlySales from ReportingMonthlySales RMS where Category = 'Existing' and Subcategory = 'Existing' and
RMS.Unit = CY.Unit
left join CustomerCategoryLog CCL on RMS.Unit = CCL.Unit,
ExistingOrganic = select MonthlySales from ReportingMonthlySales RMS where Category = 'Existing' and Subcategory = 'Organic' and
RMS.Unit = CY.Unit
left join CustomerCategoryLog CCL on RMS.Unit = CCL.Unit

我知道那是错误的、尴尬的和笨拙的,但也许它可以帮助您理解 table 等之间的联系。

注意:这个问题与我的问题 部分相关,但就提供上下文或背景信息而言,这可能没有帮助。

更新

我尝试了 Charles Bretana 的想法,但不得不对其进行调整以使其在 LINQPad 中达到 "compile"。关于 table 的确切性质,我可能误导了您。我将在下面包含它们,然后显示我在 LINQPad 中尝试的更改后的查询。

CustomerCategoryLog
-------------------
MemberNo (VarChar)
Unit (VarChar)
Custno (VarChar)
Category (VarChar)
Subcategory (VarChar)
BeginDate (DateTime)
EndDate (DateTime)
ChangedBy (VarChar)
ChangedOn (DateTime)

MasterUnitProjSales
-------------------
Unit (VarChar)
CYear (Int)
CSDirector (VarChar)
ProjectedSales (Money)
NewBiz (Int)
Category (VarChar) <= this is not directly connected to the "Category" I need, and should be ignored
Segment (VarChar)

ReportingMonthlySales
---------------------
AutoID (Int)
Unit (VarChar)
MemberNo (VarChar)
NumUnits (Int)
MonthlySales (Money)
CYear (Int)
Cmonth (Int)
CreateDate (DateTime)

以下(由我修改,但基于 Bretana 的)试图在 LINQPad 中生成一些数据,但采用 "forever":

DECLARE @CYear  INT
SET @CYear = 2016

DECLARE @Cmonth INT
SET @Cmonth = 4

Select  CSDirector,
        Category,
        Segment,
        r1.unit,
        NumUnits=isnull((Select sum(NumUnits) from ReportingMonthlySales where unit=r1.unit and cyear=r1.cyear and 
        cmonth = @Cmonth),0),    
        MonthSales=isnull((Select sum(MonthlySales) from ReportingMonthlySales where unit=r1.unit and cyear=r1.cyear 
and cmonth = @Cmonth),0.00), 
        YTDSales = (Select sum(MonthlySales) From  ReportingMonthlySales where unit=r1.unit and cyear=r1.cyear and 
cmonth <= @Cmonth),
        ProjSales =  (Select ProjectedSales from MasterUnitsProjSales where UNit = r1.Unit and Cyear=r1.cyear),
        YTDProjSales = (Select ProjectedSales from MasterUnitsProjSales where UNit = r1.Unit and Cyear=r1.cyear) / 12 
* @Cmonth,
        YTDBudgetPerc = (Select sum(MonthlySales) From  ReportingMonthlySales where unit=r1.unit and cyear=r1.cyear 
and cmonth <= @Cmonth) / 
            case when (Select ProjectedSales from MasterUnitsProjSales where UNit = r1.Unit and Cyear=r1.cyear) = 
0 then 1 else ((Select ProjectedSales from MasterUnitsProjSales where UNit = r1.Unit and Cyear=r1.cyear) / 12 * @Cmonth) end
into #CombinedYears2
From    MasterUnitsProjSales r1 
where r1.Cyear=@CYear
order by r1.NewBiz,r1.Unit

Select cy.*, 
   rms.MonthlySales newnew,
   rms.MonthlySales NewAssumed,
   rms.MonthlySales ExistingExisting,
   rms.MonthlySales ExistingOrganic
from #CombinedYears2 CY 
   left join ReportingMonthlySales rms
     on rms.Unit = cy.Unit
   join CustomerCategoryLog n
     on n.Category = 'New' 
        and n.Subcategory = 'New' 
        and n.Unit = cy.Unit
   left join CustomerCategoryLog a
      on a.Category = 'New' 
        and a.Subcategory = 'Assumed' 
        and a.Unit = CY.Unit
   left join CustomerCategoryLog e
      on e.Category = 'Existing' 
        and e.Subcategory = 'Existing' 
        and e.Unit = CY.Unit
   left join CustomerCategoryLog o
      on o.Category = 'Existing' 
        and o.Subcategory = 'Organic' 
        and o.Unit = CY.Unit

更新 2

在完成其他 things/setting 之后,再回到它并重新攻击它,这是我的新伪 sql:

DECLARE @Unit varchar(30); 
DECLARE @Year Int;
DECLARE @Month Int;

SELECT MonthlySales
INTO #NewSales
FROM ReportingMonthlySales RMS
JOIN CustomerCategoryLog CCL ON RMS.Unit = CCL.Unit
WHERE RMS.Unit = @Unit AND RMS.CYear = @Year AND RMS.Cmonth = @Month AND CCL.Subcategory = 'New'

SELECT MonthlySales
INTO #AssumedSales
FROM ReportingMonthlySales RMS
JOIN CustomerCategoryLog CCL ON RMS.Unit = CCL.Unit
WHERE RMS.Unit = @Unit AND RMS.CYear = @Year AND RMS.Cmonth = @Month AND CCL.Subcategory = 'Assumed'

SELECT MonthlySales
INTO #ExistingSales
FROM ReportingMonthlySales RMS
JOIN CustomerCategoryLog CCL ON RMS.Unit = CCL.Unit
WHERE RMS.Unit = @Unit AND RMS.CYear = @Year AND RMS.Cmonth = @Month AND CCL.Subcategory = 'Existing'

SELECT MonthlySales
INTO #OrganicSales
FROM ReportingMonthlySales RMS
JOIN CustomerCategoryLog CCL ON RMS.Unit = CCL.Unit
WHERE RMS.Unit = @Unit AND RMS.CYear = @Year AND RMS.Cmonth = @Month AND CCL.Subcategory = 'Organic'

将这四个临时 table 合并为一个,将 MonthlySales 放入适当的 Category.Subcategory 列,return 将其作为结果集用于生成报告。

如果您的原始存储过程尚未执行 INSERT ... EXEC 语句,一个非常简单的方法如下:

原始存储过程:

create procedure myproc as
begin
    select 1 as id union all select 2;
end
GO

"Extending" 存储过程:

create proc myproc2 as
begin

    create table #temp (id int);
    -- Get the results of the original s.p.
    insert #temp exec myproc;

    -- Add more columns:
    alter table #temp add double_id int;

    -- Populate the new columns
    update #temp set double_id = 2*id;

    -- Return the extended data set
    select * from #temp;
end
GO

我认为这应该可行...您有太多不必要的联接。

Select cy.*, 
   n.MonthlySales newnew,
   a.MonthlySales NewAssumed,
   e.MonthlySales ExistingExisting,
   o.MonthlySales ExistingOrganic
from #CombinedYears CY 
   left join CustomerCategoryLog ccl
     on ccl.Unit = cy.Unit
   join ReportingMonthlySales n
     on n.Category = 'New' 
        and n.Subcategory = 'New' 
        and n.Unit = cy.Unit
   left join ReportingMonthlySales a
      on a.Category = 'New' 
        and a.Subcategory = 'Assumed' 
        and a.Unit = CY.Unit
   left join ReportingMonthlySales e
      on e.Category = 'Existing' 
        and e.Subcategory = 'Existing' 
        and e.Unit = CY.Unit
   left join ReportingMonthlySales o
      on o.Category = 'Existing' 
        and o.Subcategory = 'Organic' 
        and o.Unit = CY.Unit

这可能会对您有所帮助。该代码未经测试(因为我没有您的数据库 ;)),但我希望它能让事情变得不那么混乱。

最后;您正在尝试加入 CustomerCategoryLog table,但您没有在查询中引用任何其他 table。因此,您无法完成连接,这很可能是您无法编译的原因。

DECLARE @CYear INT = 2016;
DECLARE @Cmonth INT = 4;

WITH myDerivedData (unit, cyear, cmonth, NumUnits, MonthlySales, YTDBudgetPerc, YTDSales) AS (
    SELECT rms.unit
          ,rms.cyear
          ,rms.cmonth
          ,COALESCE(SUM(rms.NumUnits), 0) AS NumUnits
          ,COALESCE(SUM(rms.MonthlySales), 0) AS MonthlySales
          ,CASE WHEN mups2.ProjectedSales = 0 THEN 1
                ELSE mups2.ProjectedSales / 12 * @Cmonth
                END AS YTDBudgetPerc
          ,COALESCE(SUM(rms2.MonthlySales), 0) AS YTDSales
      FROM ReportingMonthlySales AS rms
      LEFT OUTER JOIN ReportingMonthlySales AS rms2
              ON rms2.unit = rms.unit
             AND rms2.cyear = rms.cyear
             AND rms2.cmonth = rms.cmonth
             AND rms2.cmonth <= @Cmonth
      LEFT OUTER JOIN MasterUnitsProjSales AS mups
              ON mups.unit = rms.unit
             AND mups.cyear = rms.cyear
      LEFT OUTER JOIN MasterUnitsProjSales AS mups2
              ON mups2.unit = rms.unit
             AND mups2.cyear = rms.cyear
     WHERE rms.cyear = @Cmonth
       AND rms.cyear = @Cyear
     GROUP BY rms.Unit, rms.cyear, rms.cmonth
)
SELECT mups.CSDirector,
      ,mups.[Category]
      ,mups.[Segment]
      ,mups.unit
      ,mdd.NumUnits
      ,mdd.MonthlySales
      ,mdd.YTDSales
      ,SUM(mups.ProjectedSales) AS ProjSales
      ,SUM(mups.ProjectedSales) / 12 * @Cmonth AS YTDProjSales
      ,mdd.YTDBudgetPerc
  INTO #CombinedYears2
  FROM MasterUnitsProjSales AS mups
 INNER JOIN myDerivedData AS mdd
         ON mdd.unit = mups.unit
        AND mdd.cyear = mups.cyear
        AND mdd.cmonth = mups.cmonth
 WHERE mups.Cyear = @CYear
 GROUP BY mups.Unit, mups.CSDirector, mups.[Category], mups.[Segment], mdd.NumUnits, mdd.MonthlySales, mdd.YTDSales, mdd.YTDBudgetPerc
 ORDER BY mups.NewBiz, mups.Unit;

SELECT cy.*, 
   rms.MonthlySales newnew,
   rms.MonthlySales NewAssumed,
   rms.MonthlySales ExistingExisting,
   rms.MonthlySales ExistingOrganic
  FROM #CombinedYears2 AS CY 
  LEFT OUTER JOIN ReportingMonthlySales AS rms
          ON rms.Unit = cy.Unit
  INNER JOIN CustomerCategoryLog AS n  /* What is this? You can't join a table like this, as it's not joined with any other table */
          ON n.Category = 'New';

在 Sql 服务器 2012 中,

CREATE procedure myproc @orderid int
as
begin
    select 1 as id union all select @orderid;
end
GO

EXEC .myproc @orderid = 43671
WITH RESULT SETS
(
  (
    id        INT      NOT NULL

  )
);