我有一个SQL问题,就是从表中删除一些行。表的结构就像成对的行。它可以用以下SQL表示:
create table #test
(
col1 int, col2 int, col3 int, id char(1), dtime datetime
)
insert into #test
values
(1,1,1,'a','2015-02-01 1:00:00')
,(1,1,1,'b','2015-02-01 1:00:01')
,(2,1,1,'a','2015-02-01 1:00:00')
,(2,1,1,'b','2015-02-01 1:00:01')
,(3,1,3,'b','2015-02-01 1:00:00') -- Remove this row
,(3,1,3,'a','2015-02-01 1:00:03')
,(3,1,3,'b','2015-02-01 1:00:04')
,(4,2,1,'a','2015-02-01 3:00:00')
,(4,2,1,'b','2015-02-01 3:00:01')
,(5,3,1,'a','2015-02-01 4:00:00')
,(5,3,1,'b','2015-02-01 4:00:01')
,(5,6,3,'b','2015-02-01 4:00:00') -- Remove this row
,(5,6,3,'a','2015-02-01 4:00:03')
,(5,6,3,'b','2015-02-01 4:00:04')
select *
from #test
order by col1,col2,col3
drop table #test
抱歉,我必须说清楚。这个问题来自真实的数据流。数据是关于工作流程步骤的。它有一个开始时间和一个完整的时间。每个步骤可能有多行(因为该步骤被多次调用)。当我选择开始时间和结束时间来获取数据流时,您可以预期在完整时间切换一些步骤而不是我想要的开始时间。
查询是删除以完整时间开头的未配对行。
如您所见,每两行应包含一列'a'和'b',并以'a'开头 - 开始时间。但是要删除的那两行(实际上我们不知道它们有多少)以'b'开头 - 完整的时间。
答案 0 :(得分:1)
使用主键可以更轻松地删除。添加一个将是理想的解决方案。
如果没有主键或其他一些唯一约束,则可能存在重复的行。 datetime列不保证数据是唯一的。
如果有重复项,您是否希望删除所有重复的行?如果是这样,您可以删除它们,指定所有列:
delete from #Test
where col 1 = 3
and col2 = 1
and col3 = 3
and id = 'b'
and dtime = '2015-02-01 1:00:00'
delete from #Test
where col 1 = 5
and col2 = 6
and col3 = 3
and id = 'b'
and dtime = 2015-02-01 4:00:00'
如果您希望删除除一个潜在重复项之外的所有重复项,则必须对它们进行编号并删除第一行之后的所有匹配行。
答案 1 :(得分:0)
您无法删除具有非唯一值的特定行。 因此,您必须添加id-column(主键!)
答案 2 :(得分:0)
如上所述,如果没有主键设置,则必须告诉它每个使其与其他值不同的值。在这种情况下:
DELETE FROM #test WHERE dtime ='2015-02-01 1:00:00' AND id = 'b' AND col1 = 3 AND col2 = 1 AND col3 = 3
但我警告你这不是一个好习惯。你应该按照你已经说过的那样设置一个主键。
答案 3 :(得分:0)
WITH Ordered AS
(
SELECT Col1, col2, col3, id, dtime,
ROW_NUMBER() OVER(PARTITION BY col1, col2, col3, id ORDER BY dtime DESC) AS Pos
FROM #test
)
--SELECT a.*, b.Pos
DELETE a
FROM #test AS a
INNER JOIN Ordered AS b ON a.col1 = b.col1 AND a.col2 = b.col2 AND a.col3 = b.col3
AND a.ID = b.ID AND a.dtime = b.dtime
AND b.Pos <> 1
这将删除除最新的每个副本之外的所有副本。