我如何构建一个存储过程,该存储过程将 return 包含许多计算值的结果集?

How can I construct a Stored Procedure that will return a result set containing many calculated values?

这些是我需要从存储过程中 return 的值:

Description
Week 1 Usage
Week 2 Usage
Usage Variance
Week 1 Price
Week 2 Price
Price Variance
% of Price Variance

名称中带有"Variance"的三个字段是根据其他值计算的字段,"Week"分区必须根据日期参数计算。因此,驻留在数据库 table 中的实际(最相关的)字段是:

Description
Usage
Price
InvoiceDate

用户提供的参数为:

Unit
DateBegin
DateEnd

我认为需要在存储过程中声明的变量是:

DECLARE 
@Week1Begin datetime, 
@Week1End datetime, 
@Week2Begin datetime, 
@Week2End datetime, 
@Week1Usage varchar(30),
@Week2Usage varchar(30),
@Week1Price varchar(30),
@Week2Price varchar(30),
@UsageVariance varchar(30),
@PriceVariance varchar(30),
@PercentageOfPriceVariance varchar(30)

Week1BeginWeek1End 必须根据用户在 DateBegin 参数中提供的值进行计算(例如,如果 DateBegin 是 12/27 /15,Week1Begin 将是 2015 年 12 月 27 日,而 Week1End 将是 2016 年 1 月 2 日);

Week2BeginWeek2End 是相似的,但它们的跨度可能少于 7 天,如果超过 7 天最多(Week2End 将是 "reduced" 根据需要提前到日期)。

因此,尽管正在进行大量计算,但原始数据非常稀少。基本上就是上面提到的四个字段(Description、Usage、Price 和 InvoiceDate),可以从 InvoiceDetail table.

我最大的难题是这些数据中的大部分是 return 从现有的存储过程中编辑出来的,可能最好复制和扩展,但我无论如何都不是 SQL 专家 - 我可以编写简单的 SELECTUPDATE 等语句,但与临时 table 共舞以及这种关系旋转几乎超出了我的范围。

因此,基于现有的存储过程创建新的存储过程似乎充满了危险; OTOH,我想知道是否可以使用一个相当小的存储过程和一个包含多个子选择的复杂查询语句来检索我需要的数据。

同样,复杂的 SQL 无论如何都不是我的强项,所以我可能在这里 "way off",但这是我的伪 SQL:

CREATE Procedure [dbo].[myFunkySP]
    @Unit varchar(25),
    @BegDate datetime,
    @EndDate datetime
As

// Create a mostly-empty-for-now temp table
Select  Description,
    Week1Begin,
    Week1End,
    Week2Begin,
    Week2End,
    Week1Usage,
    Week2Usage,
    Week1Price,
    Week2Price,
    UsageVariance,
    PriceVariance
    PercentageOfPriceVariance
    Into    #TempItems
    From    InvoiceDetail Ind
    Where   Ind.Unit = @Unit
    and Ind.InvoiceDate Between @BegDate and @EndDate


begin

    Update #TempItems set 
    Week1Begin = // val from@BegDate
    Week1End = // do some date math to determine; maybe a Function called GetEndOfWeek(Week1Begin)? 
    Week2Begin = // do some date math to determine (1 day beyond Week1End val)
    Week2End = // val from@EndDate
    Week1Usage = SELECT SUM(USAGE) FROM InvoiceDetail WHERE UNIT = @UNIT, DATE BETWEEN Week1Begin AND Week1End 
    Week2Usage = SELECT SUM(USAGE) FROM InvoiceDetail WHERE UNIT = @UNIT, DATE BETWEEN Week2Begin AND Week2End 
    Week1Price = SELECT SUM(PRICE) FROM InvoiceDetail WHERE UNIT = @UNIT, DATE BETWEEN Week1Begin AND Week1End
    Week2Price = SELECT SUM(PRICE) FROM InvoiceDetail WHERE UNIT = @UNIT, DATE BETWEEN Week2Begin AND Week2End
    UsageVariance = (Week2Usage - Week1Usage)
    PriceVariance = (Week2Price - Week1Price)
    PercentageOfPriceVariance = (PriceVariance div week2Price)

    // now select * from the temp table to return everything?

否则(如果上面的方法不起作用或不可行),我在想我可能不得不做一些被 beaucoup 子查询污染的 9-X-Uglier-than-a-bag-of-butts 查询,类似于:

SELECT DESCRIPTION, 
    (SELECT SUM(USAGE) FROM InvoiceDetail
        WHERE UNIT = @UNIT, InvoiceDate BETWEEN :firstWeekBegin AND :firstWeekEnd as Week1Usage), 
    (SELECT SUM(USAGE) FROM InvoiceDetail
        WHERE UNIT = @UNIT, InvoiceDate BETWEEN :secondWeekBegin AND :secondWeekEnd as Week2Usage), 
    SELECT PRICE FROM InvoiceDetail 
        WHERE UNIT = @UNIT, InvoiceDate = firstWeekBegin as Week1Price), 
    (SELECT PRICE FROM InvoiceDetail    
        WHERE UNIT = @UNIT, InvoiceDate = secondWeekBegin as Week2Price), 
FROM InvoiceDetail
WHERE UNIT = @UNIT, InvoiceDate BETWEEN @BEGDATE AND @ENDATE ORDER BY PRODUCTS

说它不是这样的,乔!

即使那个复杂的查询有点可行,它仍然没有给我需要的计算值(UsageVariance、PriceVariance 和 PercentageOfPriceVariance)。

那么我需要做什么来创建一个存储过程来 return 我需要的结果?

您应该创建一个 returns table.

的函数

https://technet.microsoft.com/en-us/library/ms191165(v=sql.105).aspx

扩展评论,不是答案
不需要 UPDATE 部分。首先你需要在 SP 的 bigining 计算 week1end 和 week2bigin。在此之后,SELECT 语句非常简单 –

    DECLARE @Week1End datetime ,@Week2begin datetime

    Select  Description,
    @BegDate  BegDate,
    @Week1End Week1End,
    @Week1End Week2Begin,
    @EndDate EndDate,
    SUM(CASE WHEN Ind.InvoiceDate BETWEEN @BegDate AND @Week1End THEN Ind.Usage ELSE 0 END) Week1Usage,
    SUM(CASE WHEN Ind.InvoiceDate BETWEEN @Week2Begin AND @EndDate THEN Ind.Usage ELSE 0 END) Week2Usage,
    SUM(CASE WHEN Ind.InvoiceDate BETWEEN @BegDate AND @Week1End THEN Ind.Price ELSE 0 END) Week1Price,
    SUM(CASE WHEN Ind.InvoiceDate BETWEEN @Week2Begin AND @EndDate THEN Ind.Price ELSE 0 END) -
   SUM(CASE WHEN Ind.InvoiceDate BETWEEN @BegDate AND @Week1End THEN Ind.Usage ELSE 0 END) UsageVariance,
    SUM(CASE WHEN Ind.InvoiceDate BETWEEN @Week2Begin AND @EndDate THEN Ind.Usage ELSE 0 END)  -
    SUM(CASE WHEN Ind.InvoiceDate BETWEEN @BegDate AND @Week1End THEN Ind.Price ELSE 0 END) PriceVariance,
    (SUM(CASE WHEN Ind.InvoiceDate BETWEEN @Week2Begin AND @EndDate THEN Ind.Usage ELSE 0 END)  -
    SUM(CASE WHEN Ind.InvoiceDate BETWEEN @BegDate AND @Week1End THEN Ind.Price ELSE 0 END) )
    /     SUM(CASE WHEN Ind.InvoiceDate BETWEEN @BegDate AND @Week1End THEN Ind.Price ELSE 0 END)     
    PercentageOfPriceVariance
    From    InvoiceDetail Ind
    Where   Ind.Unit = @Unit
    AND @Ind.InvoiceDate BETWEEN @BegDate AND @EndDate

按照lad2025的建议可以找到答案

基本上,像这样在 table 创建中定义它们:

USAGEVARIANCE   AS WEEK2USAGE - WEEK1USAGE,
PRICEVARIANCE   AS WEEK2PRICE - WEEK1PRICE,
PRICEVARIANCEPERCENTAGE  AS (WEEK2PRICE - WEEK1PRICE) / WEEK1PRICE

...更多上下文:

WEEK1USAGE DECIMAL(18,10),
WEEK1PRICE DECIMAL(18,10),
WEEK2USAGE DECIMAL(18,10),
WEEK2PRICE DECIMAL(18,10),
USAGEVARIANCE   AS WEEK2USAGE - WEEK1USAGE,
PRICEVARIANCE   AS WEEK2PRICE - WEEK1PRICE,
PRICEVARIANCEPERCENTAGE  AS (WEEK2PRICE - WEEK1PRICE) / WEEK1PRICE

此后,您不必在 INSERT 语句中考虑它们 - 计算值会在添加它们所依赖的值时自动添加。