【问题标题】:SQL Query Find Exact and Near DupesSQL 查询查找精确和近似重复
【发布时间】:2021-03-04 01:14:09
【问题描述】:

我有一个包含 FirstName、LastName、Add1 和其他字段的 SQL 表。我正在努力清理这些数据。有一些可能的欺骗实例 -

  1. 多于 1 条记录的所有 3 列完全相同
  2. First和Last相同,只有1个有地址,另一个是空白
  3. First 和 Last 相似(John | Doe 与 John C. | Doe)并且地址相同或一个为空白

我想生成一个可以提供给用户的查询,以便他们可以检查这些记录,比较他们的相关记录,然后删除他们不需要的记录。

我一直在研究相似函数、soundex 等,但这一切似乎都很复杂。有没有简单的方法可以做到这一点?

谢谢!


编辑:

所以这里有一些示例数据:

FirstName    |   LastName    |      Add1
John         |   Doe         |   1 Main St
John         |   Doe         |   
John A.      |   Doe         |   
Jane         |   Doe         |   2 Union Ave
Jane B.      |   Doe         |   2 Union Ave
Alex         |   Smith       |   3 Broad St
Chris        |   Anderson    |   4 South Blvd
Chris        |   Anderson    |   4 South Blvd

我真的很喜欢 Critical Error 用于识别所有不同类型的欺骗的查询。这会给我上面的示例数据,但不包括 Alex Smith 的结果,因为没有任何欺骗。

我想要做的是获取该结果集并确定哪些是 Jane Doe 的骗子。她应该只有2个骗子。 John Doe 有 3 个,Chris Anderson 有 2 个。我可以得到那个子结果集吗?


编辑:

我想通了!我会将严重错误的答案标记为解决方案,因为它完全让我到达了我需要去的地方。这是解决方案,以防它可能对其他人有所帮助。基本上,这就是我们正在做的事情。

  1. 从存在重复的表中选择记录
  2. 添加 WHERE EXISTS 子查询以在同一个表中查找确切的欺骗,其中主查询和子查询的 ID 不匹配
  3. 添加 WHERE EXISTS 子查询以在同一个表中查找类似的重复项,使用重复列之间的差异因子,其中主查询和子查询的 ID 不匹配
  4. 添加 WHERE EXISTS 子查询以在同一个表中查找 2 个字段的重复项,其中第 3 个可能为空的记录之一,其中主查询和子查询的 ID 不匹配
  5. 每个子查询都用 OR 连接,以便找到任何类型的重复项
  6. 在每个子查询的末尾添加一个嵌套要求,即主查询或子查询是您要识别重复项的记录的 ID。
    DECLARE @CID AS INT
    
    SET ANSI_NULLS ON
    
        SET NOCOUNT ON;
        SET @CID = 12345
    BEGIN
    
    
    SELECT
        *
    FROM @Customers c
    WHERE
        -- Exact duplicates.
        EXISTS (
    
            SELECT * FROM @Customers x WHERE
                x.FirstName = c.FirstName 
                AND x.LastName = c.LastName 
                AND x.Add1 = c.Add1 
                AND x.Id <> c.Id
                AND (x.ID = @CID OR c.ID = @CID)
        
        )
        -- Match First/Last name are same/similar and the address is same.
        OR EXISTS (
        
            SELECT * FROM @Customers x WHERE
                DIFFERENCE( x.FirstName, c.FirstName ) = 4 
                AND DIFFERENCE( x.LastName, c.LastName ) = 4
                AND x.Add1 = c.Add1
                AND x.Id <> c.Id
                AND (x.ID = @CID OR c.ID = @CID)
    
        )
        -- Match First/Last name and one address exists.
        OR EXISTS (
        
            SELECT * FROM @Customers x WHERE
                x.FirstName = c.FirstName 
                AND x.LastName = c.LastName
                AND x.Id <> c.Id
                AND (
                    x.Add1 IS NULL AND c.Add1 IS NOT NULL
                    OR
                    x.Add1 IS NOT NULL AND c.Add1 IS NULL
                )
                AND (x.ID = @CID OR c.ID = @CID)
        );

【问题讨论】:

  • 请提供样本数据和期望的结果。你想做什么还很不清楚。
  • 只需使用 HAVING COUNT(*) > 1 进行 GROUP BY FirstName, LastName, Add1 将解决您的第一种情况,第二种情况类似,对于第三种情况,我敢打赌,在您的表中,您除了“相似的名字”之外,还有更多用于查找欺骗的指示字段,有些人的名字可以相同,但这并不表明他们是同一个人......

标签: sql sql-server duplicates similarity fuzzy-comparison


【解决方案1】:

假设你在记录之间有一个唯一的 id,你可以试试这个:

DECLARE @Customers table ( FirstName varchar(50), LastName varchar(50), Add1 varchar(50), Id int IDENTITY(1,1) );
INSERT INTO @Customers ( FirstName, LastName, Add1 ) VALUES
    ( 'John', 'Doe', '123 Anywhere Ln' ),
    ( 'John', 'Doe', '123 Anywhere Ln' ),
    ( 'John', 'Doe', NULL ),
    ( 'John C.', 'Doe', '123 Anywhere Ln' ),
    ( 'John C.', 'Doe', '15673 SW Liar Dr' );

SELECT
    *
FROM @Customers c
WHERE
    -- Exact duplicates.
    EXISTS (

        SELECT * FROM @Customers x WHERE
            x.FirstName = c.FirstName 
            AND x.LastName = c.LastName 
            AND x.Add1 = c.Add1 
            AND x.Id <> c.Id
    
    )
    -- Match First/Last name are same/similar and the address is same.
    OR EXISTS (
    
        SELECT * FROM @Customers x WHERE
            DIFFERENCE( x.FirstName, c.FirstName ) = 4 
            AND DIFFERENCE( x.LastName, c.LastName ) = 4
            AND x.Add1 = c.Add1
            AND x.Id <> c.Id

    )
    -- Match First/Last name and one address exists.
    OR EXISTS (
    
        SELECT * FROM @Customers x WHERE
            x.FirstName = c.FirstName 
            AND x.LastName = c.LastName
            AND x.Id <> c.Id
            AND (
                x.Add1 IS NULL AND c.Add1 IS NOT NULL
                OR
                x.Add1 IS NOT NULL AND c.Add1 IS NULL
            )
    );

返回

+-----------+----------+-----------------+----+
| FirstName | LastName |      Add1       | Id |
+-----------+----------+-----------------+----+
| John      | Doe      | 123 Anywhere Ln |  1 |
| John      | Doe      | 123 Anywhere Ln |  2 |
| John      | Doe      | NULL            |  3 |
| John C.   | Doe      | 123 Anywhere Ln |  4 |
+-----------+----------+-----------------+----+

初始结果集:

+-----------+----------+------------------+----+
| FirstName | LastName |       Add1       | Id |
+-----------+----------+------------------+----+
| John      | Doe      | 123 Anywhere Ln  |  1 |
| John      | Doe      | 123 Anywhere Ln  |  2 |
| John      | Doe      | NULL             |  3 |
| John C.   | Doe      | 123 Anywhere Ln  |  4 |
| John C.   | Doe      | 15673 SW Liar Dr |  5 |
+-----------+----------+------------------+----+

【讨论】:

  • 这太棒了!谢谢你。我现在要试着把它放在一起,看看效果如何。我会回帖,一旦我这样做。
猜你喜欢
  • 1970-01-01
  • 2016-10-11
  • 2021-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-25
相关资源
最近更新 更多