如何识别重复记录的唯一标识符?

3
我在表格中发现了重复的记录。我需要找到唯一标识符,以便从表格中删除它。
我知道有重复记录的唯一方法是通过列“subject”和“description”,因此如果至少有两个相同的主题和相同的描述,我需要删除一个并留下一个。
所以我已经得到了重复记录的列表,但是我无法获得唯一标识符以便删除它。
以下是我用来识别重复记录的方法。
SELECT 
    p.accountid, p.subject, p.description, count(*) AS total
FROM
    activities AS p 
WHERE     
    (p.StateCode = 1) AND p.createdon >= getdate()-6
GROUP BY 
    p.accountid, p.subject, p.description
HAVING 
    count(*) > 1
ORDER BY 
    p.accountid

有一列 record_id 保存每条记录的唯一标识符。但是,如果我在选择语句中添加了 record_id ,那么我将得不到任何结果,因为不可能有重复的唯一标识符。

如何在 SQL Server 中获取 record_id

注意:record_id 不是整数,而是类似于“D32B275B-0B2F-4FF6-8089-00000FDA9E8E”这样的字符串。

谢谢

4个回答

4

我喜欢 SQL Server 的一个很好的特性是可以在 updatedelete 语句中使用 CTE。

如果你要查找重复记录,并且想保留最低或最高的 record_id,可以使用 CTE 和窗口函数来获取计数和要保留的 id:

with todelete as (
    SELECT p.accountid, p.subject, p.description,
           COUNT(*) over (partition by p.accountid, p.subject, p.description) as total,
           MIN(record_id) over (partition by p.accountid, p.subject, p.description) as IdToKeep
    FROM activities AS p 
    WHERE (p.StateCode = 1) AND p.createdon >= getdate()-6
   )
delete from todelete
    where total > 1 and record_id <> IdToKeep;

最终的where子句只是使用逻辑来选择要删除的正确行。
我应该补充一下,如果你只想要将要被删除的列表,你可以使用类似的查询:
with todelete as (
    SELECT p.accountid, p.subject, p.description,
           COUNT(*) over (partition by p.accountid, p.subject, p.description) as total,
           MIN(record_id) over (partition by p.accountid, p.subject, p.description) as IdToKeep
    FROM activities AS p 
    WHERE (p.StateCode = 1) AND p.createdon >= getdate()-6
   )
select *
from todelete
 where total > 1 and record_id <> IdToKeep;

over函数表示一个函数被用作窗口函数。这个想法很简单。Count(*) over返回具有相同partition子句中字段值的所有记录的计数。它类似于聚合函数,但你可以在每一行上获得该值。这类函数非常强大,我建议你学习更多关于它们的知识。


谢谢您的回答,但是record_id不是整数,它类似于"D32B275B-0B2F-4FF6-8089-00000FDA9E8E"。我在第二段代码中遇到了这个错误:操作数数据类型uniqueidentifier对于min运算符无效。 - Mike
@Mike . . . 在这种情况下,您可以使用 MIN(cast(record_id as varchar(255))) over . . .MIN()将返回一个任意值以保留。这是个问题吗?如果是,您会如何选择要保留的记录ID之一? - Gordon Linoff
非常感谢,那个起作用了,但是你能否解释一下 over 和 partition by 是做什么的吗?谢谢。 - Mike
窗口函数创建一个窗口,以便可以进行多个计数。分区告诉它每个计数要按什么分组。您还可以在窗口函数中包含 order by 以处理其他情况,例如我在回答此问题时提到的 row_number。 - liebs19

0

或许可以像这样?

SELECT max(p.record_id), p.accountid, p.subject, p.description, count(*) AS total
FROM activities AS p 
WHERE (p.StateCode = 1) AND p.createdon >= getdate()-6
GROUP BY p.accountid, p.subject, p.description
HAVING count(*) > 1
ORDER BY p.accountid

0

看起来你需要先进行内部查询,然后再与较大的表进行连接以获得你想要的结果。

SELECT ALL
    *
FROM (SELECT p.accountid
  FROM activities AS p
  WHERE p.statecode = 1 AND p.createdon >= getdate()-6
  GROUP BY p.accountid
  HAVING count(*) > 1) AS x
JOIN activities AS a ON x.accountid = a.accountid
ORDER BY p.accountid

0

试试这个:

;with recordsToDelete as (
SELECT 
     recordId
    ,Row_Number() OVER(partition p.subject, p.description) as rowNum
FROM activities AS p 
)

select
*
from recordsToDelete
where rowNum > 1

如果看起来正确,您可以将 select 替换为:
delete from recordsToDelete
    where rowNum > 1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接