我希望设计一个查询,其中计算将单元格中的值与同一列中前一个单元格中的值进行比较,另一个计算使用先前的计算结果来引用先前的单元格进行计算。数据将按以下顺序从下面的示例图片 - Material,Plant和YearWeek
开始从下图中,蓝色列标题表示原始数据,黄色列标题表示计算行。
计算行的公式如下:
从我的调查来看,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
答案 0 :(得分:1)
改编自答案'无联合和无分析功能'于:
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
答案 1 :(得分:0)
在早期版本的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