[英]Find difference between two table in SQL and append back result to source table & update column values only for newly inserted rows
[英]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 中使用LAG
和LEAD
函数。 但是没有达到预期的效果。
有人可以帮助我实现它。
使用窗口函数( 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;
输出:
╔═════════╦════════╦══════════╦═════════╗
║ 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
指标是0
和1
而不是任何其他值。
特别是对于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;
输出:
╔═════════╦════════╦══════════╦═════════╗
║ 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
你不能保证稳定的结果相关文章:
让我假设 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 引擎中运行 在此处查看演示
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.