【问题标题】:Listing duplicated records using T SQL使用 T SQL 列出重复记录
【发布时间】:2013-11-13 09:59:45
【问题描述】:

我有一个数据库,用于记录一家小型诊所的患者信息。我们使用 MS SQL Server 2008 作为后端。患者表包含以下列:

Id int identity(1,1), 
FamilyName varchar(30),
FirstName varchar (20), 
DOB datetime, 
AddressLine1 varchar (50), 
AddressLine2 varchar (50), 
State varchar (20), 
Postcode varchar (4), 
NextOfKin varchar (20), 
Homephone varchar (20), 
Mobile varchar (20)

有时,工作人员会为一名新患者登记,但并不知道该患者已经在系统中保存了记录。我们最终得到了数千条重复的记录。

我想做的是提供一份重复记录的患者列表,供工作人员在安静时间合并。如果 2 条记录具有完全相同的 FamilyName、FirstName 和 DOB,我们认为 2 条记录是重复的。我目前正在做的是使用子查询返回记录如下:

SELECT FamilyName, 
       FirstName, 
       DOB, 
       AddressLine1, 
       AddressLine2, 
       State, 
       Postcode, 
       NextOfKin, 
       HomePhone,
       Mobile 
FROM
Patients AS p1 
WHERE Id IN 
          ( 
            SELECT Max(Id) 
            FROM Patients AS p2, 
            COUNT(id) AS NumberOfDuplicate 
            GROUP BY    
            FamilyName, 
            FirstName, 
            DOB HAVING COUNT(Id) > 1
          )

这会产生结果,但性能很糟糕。有没有更好的方法呢?唯一的要求是我需要显示患者表中的所有字段,因为系统用户希望在决定是否合并记录之前查看所有详细信息。

【问题讨论】:

    标签: sql sql-server database sql-server-2008


    【解决方案1】:

    这将根据名字和姓氏输出每一行有重复的行

    SELECT DISTINCT t1.* 
    FROM Table AS t1 
        INNER JOIN Table AS t2
        ON t1.firstname = t2.firstname 
           AND t1.lastname = t2.lastname
           AND t1.id <> t2.id
    

    【讨论】:

    • 哇,这是一个优雅的解决方案。我从来没有想过这样做
    • 谢谢我最终使用了您的解决方案而不是 CTE 解决方案,因为 join 语句似乎提供了更好的性能。请问如何接受您的解决方案?
    【解决方案2】:

    我建议您在用于检测重复项的 3 个字段上建立索引, 然后试试这个查询:

    with Duplicates as
    ( 
        select FamilyName, FirstName, DOB
        from Patients 
        group by FamilyName, FirstName, DOB
        having count(*) > 1 
    )
    Select Patients.* 
    from Patients 
        inner join Duplicates
        on Patients.FamilyName = Duplicates.FamilyName 
           And Patients.FirstName= Duplicates.FirstName
           and Patients.DOB= Duplicates.DOB
    

    【讨论】:

    • 这将列出每个重复项的所有行
    • 谢谢。我已经在这 3 个字段上有了一个复合索引。明天我回来工作时,将按照您的建议尝试 CTE。只是想知道其他更具可读性,这是否意味着 CTE 在性能方面优于子查询?
    • 谢谢,您的解决方案有效,但我最终使用了 Join 方法,因为不知何故 CTE 比 JOin 稍慢。感谢您的帮助。
    【解决方案3】:
    WITH CTE 
    AS
    (
    SELECT Id, FamilyName, FirstName ,DOB
    ROW_NUMBER() OVER(PARTITION BY FamilyName, FirstName ,DOB ORDER BY Id) AS DuplicateCount
    FROM PatientTable
    )
    select * from CTE where DuplicateCount > 1
    

    【讨论】:

    • 如何更好?不是说不是,但你应该解释一下。
    • @itsbruce For start OP query will throw error ,其次你的问题涉及很多领域,所以简单地告诉哪个更好是不正确的,但是可以比较他们的执行计划。但如果你能摆脱请对此事有所了解。
    • @itsbruce 但是我想知道您的评论,我的查询如何更好?顺便说一句,感谢您提出一个好问题。
    【解决方案4】:

    如果我处于你的位置,我会做以下事情:

    1. 为 FamilyName、FirstName 和 DOB 添加索引
    2. 为您的子查询创建视图
    3. 修改查询如下

      Select p.* FROM Patients p INNER JOIN view_name v ON v.FirstName=p.Firstname AND ...

    【讨论】:

    • 这实际上是我计划做的下一步,因为跳转到预构建的 SQL 视图会有一些统计来源,可以提高性能。
    【解决方案5】:
     select FamilyName, FirstName, DOB 
       from Patients 
      group by FamilyName, FirstName, DOB 
     having count(*)>1
    

    将显示所有重复项。

    但是,请考虑名称的书写方式不同但相似。您可能想要查找主题“重复数据删除”和/或“记录链接”。我使用字符串相似性算法(修改 Jaro/Winkler 和 levenshtein)解决了这个问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-03-19
      • 2017-01-07
      • 1970-01-01
      • 2011-09-29
      • 1970-01-01
      • 2010-11-05
      • 2022-12-09
      相关资源
      最近更新 更多