SQL 查询查找准确和接近的重复项
SQL Query Find Exact and Near Dupes
我有一个 SQL table,其中包含 FirstName、LastName、Add1 和其他字段。我正在努力清理这些数据。有几个可能被骗的例子 -
- 超过 1 条记录的所有 3 列完全相同
- First和Last一样,只有1个有地址,另一个是空白
- 第一个和最后一个相似(John | Doe vs 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 用于识别所有不同类型的骗子的查询。这将给我上面的样本数据,不包括亚历克斯·史密斯的结果,因为没有骗子。
我想做的是获取该结果集并确定哪些是 Jane Doe 的骗子。她应该只有两个骗子。 John Doe 有 3 个,Chris Anderson 有 2 个。我可以得到那个子结果集吗?
编辑:
我想通了!我会将 Critical Error 的答案标记为解决方案,因为它完全让我到达了我需要去的地方。这是解决方案,以防它可能对其他人有所帮助。基本上,这就是我们正在做的。
- 从table中选择有重复的记录
- 添加 WHERE EXISTS 子查询以在相同的 table 中查找完全相同的重复项,其中主查询和子查询的 ID 不匹配
- 添加 WHERE EXISTS 子查询以在相同的 table 中查找类似的重复项,使用重复列之间的差异因子,其中主查询和子查询的 ID 不匹配
- 添加 WHERE EXISTS 子查询以在相同的 table 中查找 2 个字段上的重复项,其中第 3 个字段对于其中一个记录可能为空,其中来自主查询和子查询的 ID不匹配
- 每个子查询都与一个 OR 连接,因此可以找到任何类型的重复项
- 在每个子查询的末尾添加一个嵌套要求,即主查询或子查询是您要为其识别重复项的记录的 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)
);
假设你在记录之间有一个唯一的 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
)
);
Returns
+-----------+----------+-----------------+----+
| 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 |
+-----------+----------+------------------+----+
我有一个 SQL table,其中包含 FirstName、LastName、Add1 和其他字段。我正在努力清理这些数据。有几个可能被骗的例子 -
- 超过 1 条记录的所有 3 列完全相同
- First和Last一样,只有1个有地址,另一个是空白
- 第一个和最后一个相似(John | Doe vs 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 用于识别所有不同类型的骗子的查询。这将给我上面的样本数据,不包括亚历克斯·史密斯的结果,因为没有骗子。
我想做的是获取该结果集并确定哪些是 Jane Doe 的骗子。她应该只有两个骗子。 John Doe 有 3 个,Chris Anderson 有 2 个。我可以得到那个子结果集吗?
编辑:
我想通了!我会将 Critical Error 的答案标记为解决方案,因为它完全让我到达了我需要去的地方。这是解决方案,以防它可能对其他人有所帮助。基本上,这就是我们正在做的。
- 从table中选择有重复的记录
- 添加 WHERE EXISTS 子查询以在相同的 table 中查找完全相同的重复项,其中主查询和子查询的 ID 不匹配
- 添加 WHERE EXISTS 子查询以在相同的 table 中查找类似的重复项,使用重复列之间的差异因子,其中主查询和子查询的 ID 不匹配
- 添加 WHERE EXISTS 子查询以在相同的 table 中查找 2 个字段上的重复项,其中第 3 个字段对于其中一个记录可能为空,其中来自主查询和子查询的 ID不匹配
- 每个子查询都与一个 OR 连接,因此可以找到任何类型的重复项
- 在每个子查询的末尾添加一个嵌套要求,即主查询或子查询是您要为其识别重复项的记录的 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)
);
假设你在记录之间有一个唯一的 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
)
);
Returns
+-----------+----------+-----------------+----+
| 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 |
+-----------+----------+------------------+----+