繁体   English   中英

SQL - 更新列中两个值之间的行

[英]SQL - Update rows between two values in a column

我在SQL Server有如下数据集:

ROW_NUM  EMP_ID  DATE_KEY  TP_DAYS
1        U12345  20131003   1
2        U12345  20131004   0
3        U12345  20131005   0
4        U12345  20131006   0
5        U12345  20150627   1
6        U12345  20150628   0
1        U54321  20131003   1
2        U54321  20131004   0
3        U54321  20131005   0
4        U54321  20131006   0

我需要更新TP_DAYS列中的所有零,其中值增加 1 到前一个值。
所需的结果集如下:

ROW_NUM  EMP_ID  DATE_KEY  TP_DAYS
1        U12345  20131003   1
2        U12345  20131004   2
3        U12345  20131005   3
4        U12345  20131006   4
5        U12345  20150627   1
6        U12345  20150628   2
1        U54321  20131003   1
2        U54321  20131004   2
3        U54321  20131005   3
4        U54321  20131006   4

我尝试在 SQL 中使用LAGLEAD函数。 但是没有达到预期的效果。

有人可以帮助我实现它。

使用窗口函数( SUM/ROW_NUMBER因此它将与SQL Server 2008 ):

WITH cte AS
(
  SELECT *, s =  SUM(TP_DAYS) OVER(PARTITION BY EMP_ID ORDER BY ROW_NUM)
  FROM #tab
), cte2 AS
(
  SELECT *,
    tp_days_recalculated = ROW_NUMBER() OVER (PARTITION BY EMP_ID, s ORDER BY ROW_NUM)
  FROM cte
)
UPDATE cte2
SET TP_DAYS = tp_days_recalculated;

SELECT *
FROM #tab;

LiveDemo

输出:

╔═════════╦════════╦══════════╦═════════╗
║ ROW_NUM ║ EMP_ID ║ DATE_KEY ║ TP_DAYS ║
╠═════════╬════════╬══════════╬═════════╣
║       1 ║ U12345 ║ 20131003 ║       1 ║
║       2 ║ U12345 ║ 20131004 ║       2 ║
║       3 ║ U12345 ║ 20131005 ║       3 ║
║       4 ║ U12345 ║ 20131006 ║       4 ║
║       5 ║ U12345 ║ 20150627 ║       1 ║
║       6 ║ U12345 ║ 20150628 ║       2 ║
║       1 ║ U54321 ║ 20131003 ║       1 ║
║       2 ║ U54321 ║ 20131004 ║       2 ║
║       3 ║ U54321 ║ 20131005 ║       3 ║
║       4 ║ U54321 ║ 20131006 ║       4 ║
╚═════════╩════════╩══════════╩═════════╝   

#附录

原始 OP 问题和示例数据非常清楚, tp_days指标是01而不是任何其他值。

特别是对于Atheer Mostafa

检查这个例子作为证明: https : //data.stackexchange.com/stackoverflow/query/edit/423186

这应该是新问题,但我会处理这种情况:

;WITH cte AS
(
  SELECT *
   ,rn = s +  ROW_NUMBER() OVER(PARTITION BY EMP_ID, s ORDER BY ROW_NUM) -1
   ,rnk = DENSE_RANK() OVER(PARTITION BY EMP_ID ORDER BY s)
  FROM (SELECT *, s =  SUM(tp_days) OVER(PARTITION BY EMP_ID ORDER BY ROW_NUM)
        FROM #tab) AS sub
), cte2 AS
(
  SELECT c1.*,
   tp_days_recalculated = c1.rn - (SELECT COALESCE(MAX(c2.s),0)
                                   FROM cte c2
                                   WHERE c1.emp_id = c2.emp_id
                                     AND c2.rnk = c1.rnk-1)
  FROM cte c1
)
UPDATE cte2
SET tp_days = tp_days_recalculated;

LiveDemo2

输出:

╔═════════╦════════╦══════════╦═════════╗
║ row_num ║ emp_id ║ date_key ║ tp_days ║
╠═════════╬════════╬══════════╬═════════╣
║       1 ║ U12345 ║ 20131003 ║       2 ║
║       2 ║ U12345 ║ 20131004 ║       3 ║
║       3 ║ U12345 ║ 20131005 ║       4 ║
║       4 ║ U12345 ║ 20131006 ║       3 ║
║       5 ║ U12345 ║ 20150627 ║       4 ║
║       6 ║ U12345 ║ 20150628 ║       5 ║
║       1 ║ U54321 ║ 20131003 ║       2 ║
║       2 ║ U54321 ║ 20131004 ║       3 ║
║       3 ║ U54321 ║ 20131005 ║       1 ║
║       4 ║ U54321 ║ 20131006 ║       2 ║
╚═════════╩════════╩══════════╩═════════╝

它不应该将值 3,4,2 更改为 1 .... 就是这种情况。 当我有另一个通用答案时,我不需要您的解决方案,您没有告诉我该怎么做...谢谢

评论中提到的解决方案只不过是quirky update 是的,它会起作用,但可能很容易失败:

  • 首先,没有有序表本身这样的东西
  • 查询优化器可以以任何方式读取数据(特别是当数据集很大并且涉及并行执行时)。 没有ORDER BY你不能保证稳定的结果
  • 该行为未记录在案,今天可能有效,但将来可能会中断

相关文章:

  1. Robyn Page 的 SQL Server Cursor Workbench
  2. 计算运行总额/运行余额
  3. 没有安全带 - 没有 ORDER BY 的期待订单

让我假设 SQL Server 2012+。 您需要识别以 1 分隔的组。计算该组的一种简单方法是对 1 进行累计和。 然后可以使用row_number()计算新值。 您可以使用可更新的 CTE 来完成这项工作:

with toupdate as (
      select t.*,
             row_number() over (partition by empid, grp order by row_num) as new_tp_days
      from (select t.*, 
                   sum(tp_days) over (partition by emp_id order by row_num) as grp
            from t
           ) t
     )
update toupdate
    set tp_days = new_tp_days;

在早期版本的 SQL Server 中,您可以完成相同的事情(效率较低)。 一种方法使用outer apply

我有一个简单的代码,更简单的方法如下:

DECLARE @last int=0
UPDATE #Employees set @last=CASE WHEN TP_DAYS=0 THEN @last+1 ELSE TP_DAYS END,
TP_DAYS=CASE WHEN TP_DAYS=0 THEN @last ELSE TP_DAYS END

这可以在任何 SQL Server 引擎中运行 在此处查看演示

https://data.stackexchange.com/meta.stackoverflow/query/422955/sql-update-rows-between-two-values-in-a-column?opt.withExecutionPlan=true#resultSets

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM