2017-02-23 65 views
-2

如何删除dateupdated最少更新的行?删除日期最少更新的行

我的表是

Name Dateupdated ID status 
john 1/02/17  JHN1  A 
john 1/03/17  JHN2  A 
sally 1/02/17  SLLY1 A 
sally 1/03/17  SLLY2 A 
Mike 1/03/17  MK1  A 
Mike 1/04/17  MK2  A 

我想留下的数据取出后,在以下几点:

Name Date  ID status 
john 1/03/17 JHN2  A 
sally 1/03/17 SLLY2 A 
Mike 1/04/17 MK2  A 
+1

请告诉我们你已经尝试什么,以及为什么它没有工作。 – JiggsJedi

+0

你是如何从结果中删除Mike的?他不是重复的名字,他没有更新'1/02/17',而是'1/03/17'。 – SqlZim

+1

@SqlZim我已编辑帖子。 – sam

回答

2

这将删除行,其中的name是重复的,并删除所有但最新的每行name。这与你陈述的问题不同。

使用common table expression (cte)row_number()

;with cte as (
    select * 
    , rn = row_number() over (
      partition by Name 
      order by Dateupdated desc 
      ) 
    from t 
) 
/* ------------------------------------------------ 
-- Remove duplicates by deleting rows 
-- where the row number (rn) is greater than 1 
-- leaving the first row for each partition 
------------------------------------------------ */ 

delete 
    from cte 
    where cte.rn > 1 

select * from t 

rextester:http://rextester.com/HZBQ50469

回报:

+-------+-------------+-------+--------+ 
| Name | Dateupdated | ID | status | 
+-------+-------------+-------+--------+ 
| john | 2017-01-03 | JHN2 | A  | 
| sally | 2017-01-03 | SLLY2 | A  | 
| Mike | 2017-01-04 | MK2 | A  | 
+-------+-------------+-------+--------+ 

不使用它可以写成的CTE:

delete d 
    from (
    select * 
     , rn = row_number() over (
       partition by Name 
       order by Dateupdated desc 
      ) 
     from t 
) as d 
    where d.rn > 1 
3

如果你真的想“删除dateupdated最少更新的行”,那么一个简单的单行子查询应该可以做到。

DELETE MyTable 
WHERE Date = (SELECT MIN(Date) From MyTable) 

如果在另一方面,你只是想删除与最早的日期行每人(通过其ID),你可以使用:

DELETE MyTable 
FROM MyTable a 
JOIN (SELECT ID, MIN(Date) MinDate FROM MyTable GROUP BY ID) b 
ON a.ID = b.ID AND a.Date = b.MinDate 

这里的想法是你创建一个聚合查询,返回包含与要删除的行相匹配的列的行,然后加入到该行中。因为它是内连接,所以不符合标准的行将被排除。

如果人们唯一由别的标识(如Name那么你可以替换,对于上面我的例子ID

我在想,虽然你不希望任何的这些事情。我想你要删除的除了每个人的最新行的一切。如果是这样的话,试试这个:。

DELETE MyTable 
WHERE EXISTS (SELECT 0 FROM MyTable b WHERE b.ID = MyTable.ID AND b.Date > MyTable.Date) 

这里的想法是您检查具有相同ID和以后的日子另一个数据行的存在,如果存在是以后的记录,请删除这个。

最后一个例子的好处是你可以一遍又一遍地运行,每个人仍然只剩下一行。其他两个查询,如果一遍又一遍地运行,则会在表中一直读取,直到它为空。

P.S.由于这些解决方案明显不同,我建议您花费一些努力来学习如何阐明明确的要求。对于任何开发者来说,这是一项非常重要的技能

+0

+1,或者非常相同的方法DELETE FROM [MyTable] WHERE [Date] =(SELECT TOP 1 [Date] FROM [MyTable] ORDER BY [Date] ASC); – Juozas

+0

ouch ...这将删除所有内容,如果您运行两次,并使用日期进行匹配,则会删除具有单个条目的任何人,其中任何人在较小行上具有相同日期。 -1 – JiggsJedi

1

这应该做的伎俩:

delete 
from MyTable a 
where not exists (
    select top 1 1 
    from MyTable b 
    where b.name = a.name 
    and b.DateUpdated < a.DateUpdated 
) 

即删除该表针对其存在与比早先记录的日期相同的名称没有记录被删除的任何条目。

+1

@SqlZim正确...我会假设'Mik2'是'Mike'的一个错字(如果纠正意味着我只删除1个“MK”);否则没有合理的方法来选择要删除的记录;除非我们只是检查子字符串/模式,或类似的东西? – JohnLBevan

0

你的名字栏有Mike和Mik2,它们是彼此不同的。 所以,如果你没有犯错,标准列分组必须是没有最后一个数字的ID列。 我认为如果你没有弄错,以下是更准确的。

delete a 
from MyTable a 
    inner join 
    (select substring(ID, 1, len(ID) - 1) as ID, min(Dateupdated) as MinDate 
    from MyTable 
    group by substring(ID, 1, len(ID) - 1) 
    ) b 
    on substring(a.ID, 1, len(a.ID) - 1) = b.ID and a.Dateupdated = b.MinDate 

您可以在SQLFiddle测试:http://sqlfiddle.com/#!6/9c440/1