【问题标题】:SQL Server 2008 R2 - Calculation referencing Previous RowSQL Server 2008 R2 - 计算引用上一行
【发布时间】:2016-03-29 10:59:06
【问题描述】:

我希望设计一个查询,其中计算将单元格中的值与同一列中前一个单元格中的值进行比较,另一个计算使用先前的计算结果来引用前一个单元格进行计算.数据将按以下示例图像中的以下顺序排列 - 材料、工厂和年周

Sample Data Image

从下图中,蓝色列标题代表原始数据,黄色列标题代表计算行。

计算行的公式如下:

  • 首先? = IF(AND(B2=B1,C2=C1),"否","第一个")
  • 实际可用 = IF(F2="First",D2-E2,G1-E2)

根据我的调查,LEAD 和 LAG 函数可以帮助实现这一点,但由于我仅限于 SQL Server 2008 R2,因此我无法使用它们。请找到创建表的查询。

    CREATE TABLE ZDAYS ([YearWeek] VARCHAR(7), 
    [Material] VARCHAR(3), [Plant] VARCHAR(3),
    [Inventory] INT, [Demand] INT)

    INSERT INTO ZDAYS VALUES ('2015-42', 'ABC', '101', 20, 5)
    INSERT INTO ZDAYS VALUES ('2015-43', 'ABC', '101', 20, 3)
    INSERT INTO ZDAYS VALUES ('2015-44', 'ABC', '101', 20, 2)
    INSERT INTO ZDAYS VALUES ('2015-42', 'ABC', '201', 30, 10)
    INSERT INTO ZDAYS VALUES ('2015-43', 'ABC', '201', 30, 8)
    INSERT INTO ZDAYS VALUES ('2015-44', 'ABC', '201', 30, 4)
    INSERT INTO ZDAYS VALUES ('2015-42', 'XYZ', '101', 10, 3)
    INSERT INTO ZDAYS VALUES ('2015-43', 'XYZ', '101', 10, 2)
    INSERT INTO ZDAYS VALUES ('2015-44', 'XYZ', '201', 20, 4)

最终数据输出

 YearWeek   Material    Plant   Inventory   Demand  First?  Actual Available
 2015-42    ABC          101        20        5     First         15             
 2015-43    ABC          101        20        3     No            12             
 2015-44    ABC          101        20        2     No            10
 2015-42    ABC          201        30        10    First         20
 2015-43    ABC          201        30        8     No            12
 2015-44    ABC          201        30        4     No            8
 2015-42    XYZ          101        10        3     First         7
 2015-43    XYZ          101        10        2     No            5
 2015-44    XYZ          201        20        4     First         16

【问题讨论】:

  • 您应该在问题中包含您想要的结果。问题不应依赖于外部网站。
  • 嗨@GordonLinoff,因为我是新来的,你能告诉我你想看到最终结果的格式吗?我附上了我所期望的示例图像,但我不知道如何在此处以行和列格式发布数据。
  • 您可以在一行的开头放置四个空格以获得表格或代码格式。或者,您可以突出显示几行并单击{}
  • 嗨@GordonLinoff,我已经添加了我想看到的最终输出。感谢您的帮助。

标签: sql excel tsql sql-server-2008-r2 excel-formula


【解决方案1】:

改编自答案“无连接和无分析函数”:

http://blog.sqlauthority.com/2011/11/24/sql-server-solution-to-puzzle-simulate-lead-and-lag-without-using-sql-server-2012-analytic-function/

declare  @ZDAYS TABLE ([YearWeek] VARCHAR(7), 
    [Material] VARCHAR(3), [Plant] VARCHAR(3),
    [Inventory] INT, [Demand] INT)

    INSERT INTO @ZDAYS VALUES ('2015-42', 'ABC', '101', 20, 5)
    INSERT INTO @ZDAYS VALUES ('2015-43', 'ABC', '101', 20, 3)
    INSERT INTO @ZDAYS VALUES ('2015-44', 'ABC', '101', 20, 2)
    INSERT INTO @ZDAYS VALUES ('2015-42', 'ABC', '201', 30, 10)
    INSERT INTO @ZDAYS VALUES ('2015-43', 'ABC', '201', 30, 8)
    INSERT INTO @ZDAYS VALUES ('2015-44', 'ABC', '201', 30, 4)
    INSERT INTO @ZDAYS VALUES ('2015-42', 'XYZ', '101', 10, 3)
    INSERT INTO @ZDAYS VALUES ('2015-43', 'XYZ', '101', 10, 2)
    INSERT INTO @ZDAYS VALUES ('2015-44', 'XYZ', '201', 20, 4);

WITH T1 (RowNum, UniqueID, YearWeek, Material, Plant, Inventory, Demand)
AS
    (SELECT Row_Number() OVER(ORDER BY z.Material,z.Plant,z.YearWeek ) N
        ,1.0 + floor(10000 * RAND(convert(varbinary, newid()))) as UniqueID 
        ,z.YearWeek
        ,z.Material
        ,z.Plant
        ,z.Inventory
        ,z.Demand
        FROM @ZDAYS z
    )
select T1.*,
CASE WHEN RowNum%2=1 THEN MAX(CASE WHEN RowNum%2=0 THEN UniqueID END) OVER (Partition BY (RowNum+1)/2) ELSE MAX(CASE WHEN RowNum%2=1 THEN UniqueID END) OVER (Partition BY RowNum/2) END LeadValUniqueID,
CASE WHEN RowNum%2=1 THEN MAX(CASE WHEN RowNum%2=0 THEN UniqueID END) OVER (Partition BY RowNum/2) ELSE MAX(CASE WHEN RowNum%2=1 THEN UniqueID END) OVER (Partition BY (RowNum+1)/2) END LagValUniqueID
FROM T1
ORDER BY T1.Material, T1.Plant, T1.YearWeek
GO

或者,相同的逻辑是将 Lead() 和 Lag() 行连接起来进行标识,而不是生成唯一的 id。

declare  @ZDAYS TABLE ([YearWeek] VARCHAR(7), 
    [Material] VARCHAR(3), [Plant] VARCHAR(3),
    [Inventory] INT, [Demand] INT)

    INSERT INTO @ZDAYS VALUES ('2015-42', 'ABC', '101', 20, 5)
    INSERT INTO @ZDAYS VALUES ('2015-43', 'ABC', '101', 20, 3)
    INSERT INTO @ZDAYS VALUES ('2015-44', 'ABC', '101', 20, 2)
    INSERT INTO @ZDAYS VALUES ('2015-42', 'ABC', '201', 30, 10)
    INSERT INTO @ZDAYS VALUES ('2015-43', 'ABC', '201', 30, 8)
    INSERT INTO @ZDAYS VALUES ('2015-44', 'ABC', '201', 30, 4)
    INSERT INTO @ZDAYS VALUES ('2015-42', 'XYZ', '101', 10, 3)
    INSERT INTO @ZDAYS VALUES ('2015-43', 'XYZ', '101', 10, 2)
    INSERT INTO @ZDAYS VALUES ('2015-44', 'XYZ', '201', 20, 4);

-- LAG and LEAD result rows concatenated
WITH T1 (RowNum,  YearWeek, Material, Plant, Inventory, Demand)
AS
    (SELECT Row_Number() OVER(ORDER BY z.Material,z.Plant,z.YearWeek ) N
        ,z.YearWeek
        ,z.Material
        ,z.Plant
        ,z.Inventory
        ,z.Demand
        FROM @ZDAYS z
    )
select T1.*,
CASE WHEN RowNum%2=1 THEN MAX(CASE WHEN RowNum%2=0 THEN YearWeek + ' ' + Material + ' ' + Plant + ' ' + cast(Inventory as varchar(5)) + ' ' + cast(Demand as varchar(5)) END) OVER (Partition BY (RowNum+1)/2) ELSE MAX(CASE WHEN RowNum%2=1 THEN YearWeek + ' ' + Material + ' ' + Plant + ' ' + cast(Inventory as varchar(5)) + ' ' + cast(Demand as varchar(5)) END) OVER (Partition BY RowNum/2) END LeadRowValues,
CASE WHEN RowNum%2=1 THEN MAX(CASE WHEN RowNum%2=0 THEN YearWeek + ' ' + Material + ' ' + Plant + ' ' + cast(Inventory as varchar(5)) + ' ' + cast(Demand as varchar(5)) END) OVER (Partition BY RowNum/2) ELSE MAX(CASE WHEN RowNum%2=1 THEN YearWeek + ' ' + Material + ' ' + Plant + ' ' + cast(Inventory as varchar(5)) + ' ' + cast(Demand as varchar(5)) END) OVER (Partition BY (RowNum+1)/2) END LagRowValues
FROM T1
ORDER BY T1.Material, T1.Plant, T1.YearWeek
GO

【讨论】:

  • @Shantanu 如果此解决方案对您有用,请标记为已解决。
  • 嗨,Shep,我尝试了您的解决方案,它确实模拟了滞后和领先功能,但这不是我正在寻找的最终解决方案。检查我的最新编辑以查看我期望的输出,即“实际可用”列。
【解决方案2】:

在 SQL Server 的早期版本中,您可以使用apply

select z.yearweek, z.material, z.plant, z.inventory, z.demand,
       (case when seqnum = 1 then 'Yes' else 'No' end) as isFirst,
       (inventory - cume.demand) as ActualAvailable
from (select z.*,
             row_number() over (partition by material, plant order by yearweek) as seqnum
      from zdays z
     ) z outer apply
     (select sum(z2.demand) as demand
      from zdays z2
      where z2.material = z.material and z2.plant = z.plant and
            z2.yearweek <= z.yearweek
     ) cume

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多