SQL Server删除特定行

时间:2015-03-03 16:39:53

标签: sql sql-server

我有一个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'开头 - 完整的时间。

4 个答案:

答案 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

这将删除除最新的每个副本之外的所有副本。