如何更新引用重复记录的 table?
How do I update a table that references duplicate records?
我有两个 SQL table。一个从另一个 table 获取参考值,后者存储模块列表及其 ID。但这些描述并不是唯一的。我正在尝试删除 Table A 的重复项,但我不确定如何更新 Table B 以仅引用单个值。
示例:
Table A: Table B:
-------------------------------- ------------------------------------
ID Description RefID ID Name
-------------------------------- ------------------------------------
1 Test 1 2 1 QuickReports
-------------------------------- ------------------------------------
2 Test 2 1 2 QuickReports
-------------------------------- ------------------------------------
我希望结果如下:
Table A: Table B:
-------------------------------- ------------------------------------
ID Description RefID ID Name
-------------------------------- ------------------------------------
1 Test 1 1 1 QuickReports
-------------------------------- ------------------------------------
2 Test 2 1
--------------------------------
我使用下面的代码设法从 table B 中删除了重复项,但我无法更新 Table A 中的记录。每个 table 都有超过 500 条记录每个。
WITH cte AS(
SELECT
Name,
ROW_NUMBER() OVER (
PARTITION BY
Name
ORDER BY
Name
)row_num
FROM ReportmodulesTest
)
DELETE FROM cte
WHERE row_num > 1;
您需要先更新 table A,然后再从 table B 中删除。
您标记了您的问题 MySQL 但该数据库不支持您显示的 delete
语句。我怀疑你是 运行 SQL 服务器,所以这是在 that 数据库中的操作方法:
update a
set refid = b.minid
from tablea
inner join (select name, id, min(id) over(partition by name) minid from tableb) b
on b.id = a.id and b.minid <> a.id
在 MySQL 中,您可以将相同的查询表述为:
update tablea a
from tablea
inner join (select name, id, min(id) over(partition by name) minid from tableb) b on b.id = a.id
set a.refid = b.minid
where b.minid <> a.id
您可以更新第一个 table 使用:
update a join
(select b.*,
min(id) over (partition by name) as min_id
from b
) b
on a.refid = b.id
set a.refid = b.min_id
where a.refid <> b.min_id;
然后,您可以使用类似的逻辑删除第二个 table 中的行:
delete b
from b join
(select b.*,
min(id) over (partition by name) as min_id
from b
) bb
on bb.id = b.id
where b.id <> bb.min_id;
我找到了一个使这个过程更容易的解决方案。我首先使用 Row_Number
在 Table A 和 SELECT INTO
中查找重复项 table.
SELECT
a.Id
, a.Name
, ROW_NUMBER() OVER(PARTITION BY Name ORDER BY Id DESC) RN
INTO
#TestTable
FROM
TableA a WITH(NOLOCK)
然后我 JOIN
Table A 和 Table B 查看 ID 的匹配位置并确定我需要保留的 ID 和需要删除的 ID:
SELECT
b.Id
, b.Name
, b.RefId
, ToKeep.Id KeepId
, ToDelete.Id DeleteId
FROM
#TestTable ToDelete
JOIN TableB b WITH(NOLOCK)
ON b.RefId = ToDelete.Id
JOIN #TestTable ToKeep
ON ToDelete.Name = ToKeep.Name
AND ToKeep.RN = 1
WHERE ToDelete.RN > 1
然后使用类似的语句,我只是更新记录:
UPDATE b
SET
b.RefId = ToKeep.Id,
FROM #TestTable ToDelete
JOIN TableB b WITH(NOLOCK)
ON b.RefId = ToDelete.Id
JOIN #TestTable ToKeep
ON ToDelete.Name = ToKeep.Name
AND ToKeep.RN = 1
WHERE
ToDelete.RN > 1
最后,我现在可以删除重复记录了:
DELETE a
FROM #TestTable b
INNER JOIN TableA a
ON b.Id = a.Id
WHERE
b.RN > 1
在此之后,您可以使用相同的第一个SELECT
语句来确保删除所有重复项。只需删除 SELECT INTO
语句。
感谢我的一位匿名同事提供此解决方案,希望这对其他人有所帮助。
我有两个 SQL table。一个从另一个 table 获取参考值,后者存储模块列表及其 ID。但这些描述并不是唯一的。我正在尝试删除 Table A 的重复项,但我不确定如何更新 Table B 以仅引用单个值。
示例:
Table A: Table B:
-------------------------------- ------------------------------------
ID Description RefID ID Name
-------------------------------- ------------------------------------
1 Test 1 2 1 QuickReports
-------------------------------- ------------------------------------
2 Test 2 1 2 QuickReports
-------------------------------- ------------------------------------
我希望结果如下:
Table A: Table B:
-------------------------------- ------------------------------------
ID Description RefID ID Name
-------------------------------- ------------------------------------
1 Test 1 1 1 QuickReports
-------------------------------- ------------------------------------
2 Test 2 1
--------------------------------
我使用下面的代码设法从 table B 中删除了重复项,但我无法更新 Table A 中的记录。每个 table 都有超过 500 条记录每个。
WITH cte AS(
SELECT
Name,
ROW_NUMBER() OVER (
PARTITION BY
Name
ORDER BY
Name
)row_num
FROM ReportmodulesTest
)
DELETE FROM cte
WHERE row_num > 1;
您需要先更新 table A,然后再从 table B 中删除。
您标记了您的问题 MySQL 但该数据库不支持您显示的 delete
语句。我怀疑你是 运行 SQL 服务器,所以这是在 that 数据库中的操作方法:
update a
set refid = b.minid
from tablea
inner join (select name, id, min(id) over(partition by name) minid from tableb) b
on b.id = a.id and b.minid <> a.id
在 MySQL 中,您可以将相同的查询表述为:
update tablea a
from tablea
inner join (select name, id, min(id) over(partition by name) minid from tableb) b on b.id = a.id
set a.refid = b.minid
where b.minid <> a.id
您可以更新第一个 table 使用:
update a join
(select b.*,
min(id) over (partition by name) as min_id
from b
) b
on a.refid = b.id
set a.refid = b.min_id
where a.refid <> b.min_id;
然后,您可以使用类似的逻辑删除第二个 table 中的行:
delete b
from b join
(select b.*,
min(id) over (partition by name) as min_id
from b
) bb
on bb.id = b.id
where b.id <> bb.min_id;
我找到了一个使这个过程更容易的解决方案。我首先使用 Row_Number
在 Table A 和 SELECT INTO
中查找重复项 table.
SELECT
a.Id
, a.Name
, ROW_NUMBER() OVER(PARTITION BY Name ORDER BY Id DESC) RN
INTO
#TestTable
FROM
TableA a WITH(NOLOCK)
然后我 JOIN
Table A 和 Table B 查看 ID 的匹配位置并确定我需要保留的 ID 和需要删除的 ID:
SELECT
b.Id
, b.Name
, b.RefId
, ToKeep.Id KeepId
, ToDelete.Id DeleteId
FROM
#TestTable ToDelete
JOIN TableB b WITH(NOLOCK)
ON b.RefId = ToDelete.Id
JOIN #TestTable ToKeep
ON ToDelete.Name = ToKeep.Name
AND ToKeep.RN = 1
WHERE ToDelete.RN > 1
然后使用类似的语句,我只是更新记录:
UPDATE b
SET
b.RefId = ToKeep.Id,
FROM #TestTable ToDelete
JOIN TableB b WITH(NOLOCK)
ON b.RefId = ToDelete.Id
JOIN #TestTable ToKeep
ON ToDelete.Name = ToKeep.Name
AND ToKeep.RN = 1
WHERE
ToDelete.RN > 1
最后,我现在可以删除重复记录了:
DELETE a
FROM #TestTable b
INNER JOIN TableA a
ON b.Id = a.Id
WHERE
b.RN > 1
在此之后,您可以使用相同的第一个SELECT
语句来确保删除所有重复项。只需删除 SELECT INTO
语句。
感谢我的一位匿名同事提供此解决方案,希望这对其他人有所帮助。