SQL Server中根据其他列对应更新列时遇到的问题求助
解决SQL Server中按规则更新KeepTime列的问题
首先看你遇到的问题,核心是要根据BookUsed的连续值来更新KeepTime——连续的1要分配同一个递增的编号,0则对应0。先帮你排查原语句的问题,再给出两种可靠的解决方案:
原语句的问题
- 语法错误:你的
LEFT JOIN条件没写完,应该是ON book1.BookId - 1 = book2.BookId,否则会直接报语法错误。 - 行处理顺序不确定:SQL Server的
UPDATE默认不会按固定顺序处理行,如果不强制指定ORDER BY,查询优化器可能乱序处理,导致@time变量的赋值完全不符合预期(比如先处理后面的行,再处理前面的,编号会彻底混乱)。 - 逻辑可以简化:原CASE嵌套可以合并
NULL和0的判断,让代码更易读。
解决方案1:修正变量赋值的UPDATE语句
如果想保留变量赋值的方式,需要补全JOIN条件并强制按BookId顺序处理行,确保@time的赋值是按数据插入顺序进行的:
-- 先初始化表和数据(你的原代码) CREATE TABLE BookRecord ( BookId INT IDENTITY(1, 1), BookUsed INT ) INSERT INTO BookRecord VALUES (1), (1), (0), (0), (1), (1), (0), (1) ALTER TABLE BookRecord ADD KeepTime INT -- 修正后的UPDATE语句 DECLARE @time INT = 0; UPDATE book1 SET @time = KeepTime = CASE WHEN book1.BookUsed = 1 THEN -- 合并判断:上一行不存在或为0时,@time加1,否则保持 CASE WHEN ISNULL(book2.BookUsed, 0) = 0 THEN @time + 1 ELSE @time END ELSE 0 -- BookUsed为0时,KeepTime设为0 END FROM BookRecord book1 LEFT JOIN BookRecord book2 ON book1.BookId - 1 = book2.BookId ORDER BY book1.BookId; -- 强制按BookId升序处理,保证变量赋值顺序正确
解决方案2:使用窗口函数(推荐)
变量赋值的方式依赖行处理顺序,在复杂场景下可能不稳定。更推荐用窗口函数的集合式方法,完全不需要变量,逻辑更清晰且可靠:
-- 初始化表和数据同上,这里直接写UPDATE逻辑 WITH BookGroups AS ( SELECT BookId, BookUsed, -- 计算连续1的分组编号:每当遇到一个新的连续1起始行(上一行是0或不存在),分组号+1 SUM( CASE WHEN BookUsed = 1 AND ISNULL(LAG(BookUsed) OVER (ORDER BY BookId), 0) = 0 THEN 1 ELSE 0 END ) OVER (ORDER BY BookId ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS GroupNum FROM BookRecord ) UPDATE bg SET KeepTime = CASE WHEN bg.BookUsed = 1 THEN bg.GroupNum ELSE 0 END FROM BookGroups bg;
验证结果
执行任意一种方案后,查询表数据:
SELECT * FROM BookRecord;
会得到预期的结果:
| BookId | BookUsed | KeepTime |
|---|---|---|
| 1 | 1 | 1 |
| 2 | 1 | 1 |
| 3 | 0 | 0 |
| 4 | 0 | 0 |
| 5 | 1 | 2 |
| 6 | 1 | 2 |
| 7 | 0 | 0 |
| 8 | 1 | 3 |
内容的提问来源于stack exchange,提问作者V.Deep
相关产品推荐
相关产品推荐

