2013-10-28 26 views
1

我有两个表:
如何保留外键在另一个表中的行并删除其他重复的行?

A: 
id code 
1  A1 
2  A1 
3  B1 
4  B1 
5  C1 
6  C1 

=====================

B: 
id Aid 
1  1 
2  4 

B不含Aid其链接到code C1

让我解释一下整个流程:
我想让每一行table A有不同的代码(通过删除重复的),和我はnt保留Aid,我可以在table B找到。如果Aid不保存在table B,我保留id更大一个。

,所以我不能只是做一些事情如下:

DELETE FROM A 
WHERE id NOT IN (SELECT MAX(id) 
        FROM A 
        GROUP BY code, 
) 

我可以通过下面的SQL语句获取每个duplicate_code_groups:

SELECT code 
FROM A 
GROUP BY code 
HAVING COUNT(*) > 1 

有SQL中的一些代码,就像

for (var ids in duplicate_code_groups){ 
    for (var id in ids) { 
     if (id in B){ 
      return id 
     } 
    } 

    return max(ids) 
} 

并将返回ID置入idtable ??我只是不知道如何在sql中编写这样的代码。

然后我可以做

DELETE FROM A 
WHERE id NOT IN idtable 
+1

您的编辑更改了要求。首先,您想从A中删除具有重复代码的所有行(除了具有最高ID的行),现在您还想从A删除所有行,并且只会出现一次代码。你知道这个改变的要求吗? –

+0

另外:如果您的第一个DELETE语句是您想要执行的语句(但排除外键约束禁止删除的行),那么您的问题的其余部分只是模糊处理(因为它与第一个DELETE语句冲突)。 –

+0

@Werner Henze让我解释一下总体流程:我想让'table A'中的每一行都有不同的'code',并且我想保留'table B'中可以找到的'Aid'.If'Aid '不能保存在'表B'中,我保留这个id大一个。 – Mithril

回答

1

使用ROW_NUMBER()内CTE(或子查询),你可以为每个Code根据您的订购指定的编号,然后就加入将结果集与您的表A进行删除。

WITH CTE AS 
(
    SELECT A.*, ROW_NUMBER() OVER (PARTITION BY A.Code ORDER BY COALESCE(B.ID,0) DESC, A.ID desc) RN 
    FROM A 
    LEFT JOIN B ON A.ID = B.Aid 
) 
DELETE A FROM A 
INNER JOIN CTE C ON A.ID = C.ID 
WHERE RN > 1; 

SELECT * FROM A; 

SQLFiddle DEMO

0

尝试这种解决方案

DELETE FROM A 
    WHERE NOT id IN 
    (
    SELECT MAX(B.AId) 
    FROM A INNER JOIN B ON A.id = B.aId 
    ) 
+0

这条语句将删除'Aid',它不保存在'table:B'中 – Mithril

1

的第一选择给你所有A.id是B中 - 你不想删除它们。第二个选择需要A,选择所有没有出现在B中的ID的代码,并从这个子集取最大的id。这两组ID是你想要保留的,所以删除删除不在组中的那些。

DELETE from A where A.id not in 
(
    select aid from B 
    union 
    select MAX(A.id) from A left outer join B on B.Aid=A.id group by code having COUNT(B.id)=0 
) 

MS SQL Server 2008 R2上的实际执行计划显示此解决方案表现相当好,比Nenad解决方案快5-6倍:)。

相关问题