根据前一行的数字覆盖列

时间:2013-12-23 12:41:25

标签: sql sql-server

我在SQL Server中的下表:

**Table: Volpartition**

Year    Item    Week    Vol Part1   Part2 
2013     1  wk20    0   0       0
2013     1  wk21    0   0       0
2013     1  wk22    300 300     0
2013     1  wk23    30  30      0
2013     1  wk24    400 400     0
2013     1  wk25    500 500     0
2013     1  wk26    60  60      0
2013     1  wk27    60  60      0
2013     2  wk20    0   0       0
2013     2  wk21    0   0       0
2013     2  wk22    300 300     0
2013     2  wk23    30  30      0
2013     2  wk24    400 400     0
2013     2  wk25    500 500     0
2013     2  wk26    60  60      0
2013     2  wk27    60  60      0

注意:part1和part2是vol。

的分区

我想覆盖当前的表格,所需的结果应如下所示:

Year    Item    Week    Vol Part1   Part2 
2013     1  wk20    0   0       0
2013     1  wk21    0   0       0
2013     1  wk22    300 300     0
2013     1  wk23    30  30      0
2013     1  wk24    400 400     0
2013     1  wk25    500 0       500
2013     1  wk26    60  0       60
2013     1  wk27    60  0       60
2013     2  wk20    0   0       0
2013     2  wk21    0   0       0
2013     2  wk22    300 300     0
2013     2  wk23    30  30      0
2013     2  wk24    400 400     0
2013     2  wk25    500 0       500
2013     2  wk26    60  0       60
2013     2  wk27    60  0       60

逻辑是这样的:如果我有vol=0 the week before那么可以拥有vol=part1,然后最多可以持续3周。在此期间vol=part2

之后

我希望你能理解表格列,我无法插入图片。

非常感谢任何建议!

2 个答案:

答案 0 :(得分:0)

你的问题不明确,所以让我猜一下。在MSSQL中,您可以使用LAG()函数与当前行的偏移量。 如果您需要选择,请尝试:

WITH CTE AS
(
select t.*,
       LAG(Vol,3) OVER (ORDER BY Week) as L3,
       LAG(Vol,2) OVER (ORDER BY Week) as L2,
       LAG(Vol,1) OVER (ORDER BY Week) as L1
FROM t
)
SELECT 
[Item],[Week],[Vol],
CASE WHEN L1=0 OR L2 = 0 OR L3 =0 
THEN [Part1]
ELSE 0
END as PART1,
CASE WHEN L1=0 OR L2 = 0 OR L3 =0 
THEN 0
ELSE Vol
END as PART2

FROM CTE
ORDER BY Week

SQLFiddle demo

如果您需要更新表格,请:

WITH CTE AS
(
select t.*,
       LAG(Vol,3) OVER (ORDER BY Week) as L3,
       LAG(Vol,2) OVER (ORDER BY Week) as L2,
       LAG(Vol,1) OVER (ORDER BY Week) as L1
FROM t
)
UPDATE CTE 
SET 
PART1 = 
CASE WHEN L1=0 OR L2 = 0 OR L3 =0 
THEN [Part1]
ELSE 0
END,
PART2=
CASE WHEN L1=0 OR L2 = 0 OR L3 =0 
THEN 0
ELSE Vol
END

WHERE Vol<>0;

SQLFiddle demo

<强> UPD:    而不是ORDER BY WEEK我认为您应该提取周数并将其投放到Int,以便为wk1wk100制作正确的订单。像这样:

ORDER BY CAST(SUBSTRING(Week,3,1000) as INT)

<强> UPD2:   如果您的SQLServer版本不支持LAG()功能,则可以计算以下字段,然后将L1,L2,L3替换为CASE WHEN LI=0 OR L2=0 OR L3 = 0

,而不是计算CASE WHEN flag = 0
ISNULL((SELECT MIN(Vol) FROM t as t1 
 where 
   CAST(SUBSTRING(t.Week,3,1000) as INT)-
   CAST(SUBSTRING(t1.Week,3,1000) as INT) 
   between 1 and 3
),0) as flag

答案 1 :(得分:0)

对于SQL Server 2008,这是一个没有LAG的变体。它使用几个公用表表达式来获取可以正常的周数列表,然后使用一个简单的CASE来设置正确的值更新。

WITH cte AS (
  SELECT *, ROW_NUMBER() OVER (ORDER BY week) rn FROM Table1
), cte2 AS (
  SELECT c1.week FROM cte c1, cte c2
  WHERE c2.vol=0 AND c1.rn IN (c2.rn+1, c2.rn+2, c2.rn+3)
)
UPDATE Table1
SET Part1 = CASE WHEN Week IN (SELECT * FROM cte2) THEN Vol ELSE 0 END,
    Part2 = CASE WHEN Week IN (SELECT * FROM cte2) THEN 0 ELSE Vol END;

An SQLfiddle to test with

请注意,此查询目前不需要考虑年份,因为它不在您提供的示例数据中。

编辑:这是一个将项目和年份考虑在内的版本;

WITH cte AS (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY item ORDER BY year, week) rn
  FROM volpartition
), cte2 AS (
  SELECT DISTINCT c1.item, c1.year, c1.week
  FROM cte c1 JOIN cte c2 ON c1.item=c2.item 
   AND c1.rn IN (c2.rn+1, c2.rn+2, c2.rn+3)
  WHERE c2.vol=0
)
UPDATE v
SET Part1 = CASE WHEN c.item IS NULL THEN 0 ELSE Vol END,
    Part2 = CASE WHEN c.item IS NULL THEN Vol ELSE 0 END
FROM volpartition v
LEFT JOIN cte2 c ON v.item = c.item AND v.year = c.year AND v.week = c.week;

Another SQLfiddle to test with