我想知道如何实现这一目标。
假设我有一个包含两列的表(IU(uniqueidentifier),(ID(int),SEL(char(1))
ID列在每行中具有以下值(按IU排序):
0,1,2,2,0,0,1,2,2,2,0,0,4,2,2,0,0,1,2,0,0
对于属于该组的行,我需要使用“Y”更新列SEL: 1,2,2,2 ...... (从1开始,在下一行中是2的。(第4组,第2组,2不正确)。
所以在这个示例列中:SEL应该是:
null,Y,Y,Y,null,null,Y,Y,Y,Y,null,null,4,2,2,null,null,Y,Y,null,null
谢谢!
答案 0 :(得分:2)
这是一种基于集合的方法。
DDL&样本数据:
DECLARE @atable TABLE (
UI uniqueidentifier DEFAULT NEWSEQUENTIALID(),
ID int,
SEL char(1)
);
INSERT INTO @atable (ID)
SELECT 0 UNION ALL
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 2 UNION ALL
SELECT 0 UNION ALL
SELECT 0 UNION ALL
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 2 UNION ALL
SELECT 2 UNION ALL
SELECT 0 UNION ALL
SELECT 0 UNION ALL
SELECT 4 UNION ALL
SELECT 2 UNION ALL
SELECT 2 UNION ALL
SELECT 0 UNION ALL
SELECT 0 UNION ALL
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 0 UNION ALL
SELECT 0;
UPDATE语句:
WITH marked AS (
SELECT
*,
grp = CASE ID WHEN 0 THEN 0 ELSE 1 END
FROM @atable
),
grouped AS (
SELECT
*,
grpID = ROW_NUMBER() OVER (ORDER BY UI)
- ROW_NUMBER() OVER (PARTITION BY grp ORDER BY UI)
FROM marked
),
ranked AS (
SELECT
*,
rnk = ROW_NUMBER() OVER (PARTITION BY grp, grpID ORDER BY UI)
FROM grouped
)
UPDATE g
SET SEL = CASE r.ID
WHEN 0 THEN NULL
WHEN 1 THEN 'Y'
ELSE CAST(g.ID AS varchar)
END
FROM grouped g
INNER JOIN ranked r ON g.grp = r.grp AND g.grpID = r.grpID
WHERE r.rnk = 1;
更新后SELECT * FROM @atable
的结果:
UI ID SEL
------------------------------------ ----------- ----
A4095E70-A0CC-E011-813B-20CF30905E89 0 NULL
A5095E70-A0CC-E011-813B-20CF30905E89 1 Y
A6095E70-A0CC-E011-813B-20CF30905E89 2 Y
A7095E70-A0CC-E011-813B-20CF30905E89 2 Y
A8095E70-A0CC-E011-813B-20CF30905E89 0 NULL
A9095E70-A0CC-E011-813B-20CF30905E89 0 NULL
AA095E70-A0CC-E011-813B-20CF30905E89 1 Y
AB095E70-A0CC-E011-813B-20CF30905E89 2 Y
AC095E70-A0CC-E011-813B-20CF30905E89 2 Y
AD095E70-A0CC-E011-813B-20CF30905E89 2 Y
AE095E70-A0CC-E011-813B-20CF30905E89 0 NULL
AF095E70-A0CC-E011-813B-20CF30905E89 0 NULL
B0095E70-A0CC-E011-813B-20CF30905E89 4 4
B1095E70-A0CC-E011-813B-20CF30905E89 2 2
B2095E70-A0CC-E011-813B-20CF30905E89 2 2
B3095E70-A0CC-E011-813B-20CF30905E89 0 NULL
B4095E70-A0CC-E011-813B-20CF30905E89 0 NULL
B5095E70-A0CC-E011-813B-20CF30905E89 1 Y
B6095E70-A0CC-E011-813B-20CF30905E89 2 Y
B7095E70-A0CC-E011-813B-20CF30905E89 0 NULL
B8095E70-A0CC-E011-813B-20CF30905E89 0 NULL
答案 1 :(得分:1)
表格中的行没有inherent order,因此您的分组(1,2,2,2)完全是任意的。我们无法保证您的ID始终按此顺序排列:
0, 1, 2, 2, 0, 0, 1, 2, 2, 2, 0, 0, 4, 2, 2, 0, 0, 1, 2, 0, 0
可能是他们完全按照其他顺序进行。因此,您需要指定ORDER BY
子句来获取订单。由于您的表中没有其他字段,但SEL和ID,我认为这是不可能的。
答案 2 :(得分:1)
我真的希望有人提出比这更好的东西,因为我讨厌这个答案。
create table #test (
IU int identity primary key,
id int,
sel varchar(1)
)
insert into #test(id)
values (0), (1), (2), (2), (0), (0), (1), (2), (2), (2), (0), (0), (4), (2), (2), (0), (0), (1), (2), (0), (0)
DECLARE myCur CURSOR FORWARD_ONLY
FOR
select t.ID
from #test t
order by t.IU
FOR UPDATE OF t.sel
DECLARE @ID int, @lagSel varchar(1)
OPEN myCur
FETCH myCur INTO @ID
WHILE (@@FETCH_STATUS = 0) BEGIN
SET @lagSel = CASE
WHEN @lagSel = 'Y' AND @ID in (1,2) THEN 'Y'
WHEN @ID = 1 THEN 'Y'
ELSE NULL
END
UPDATE #test
SET sel = @lagSel
WHERE CURRENT OF myCur
FETCH myCur INTO @ID
END
CLOSE myCur
DEALLOCATE myCur
有几点需要注意:
我首先尝试使用滞后连接执行此操作,但无法完全实现此目的。这是我的工作,万一其他人可以做得更好:
select main.IU, main.id,
CASE
WHEN main.id = 1 THEN 'Y'
WHEN main.id = 2 AND lag.id in (1, 2) THEN 'Y'
ELSE NULL
END as new_sel
from #test main left outer join
#test lag on main.IU = lag.IU + 1
答案 3 :(得分:0)
我认为你在这里遇到了设计错误。 MS SQL Server对“下一行”和“上一行”一无所知。如果您尝试选择记录,则可以不时更改记录的顺序,除非您使用ORDER BY语句指定顺序。 我认为你需要先改变表格的结构。
编辑:正如我所见,你有这个领域,可以订购你的记录。现在,您可以使用CURSOR实现目标。 简而言之,您可以创建CURSOR FOR SELECT IU, ID ORDER BY IU ASC
。
循环遍历光标记录,可以检查ID字段值的顺序,当序列完全等效时,可以更新相应的记录。