SQL: join returns 多个匹配只删除一行

SQL: Delete only one row if join returns multiple matches

我有一个 SQL table,如下所示:

col1   col2
a      b
b      a
c      d
d      c
f      g

如您所见,有些行的 col1col2 列都被反转了。我的意思是,在第一行中,值 ab 都在两列中,而在第 2 行中,值也在那里,但反过来。

我现在想删除每一对中的一行。我不在乎这对的哪一边被删除了。因此,应该删除第 1 行和第 3 行或第 2 行和第 4 行。

结果应如下所示:

col1   col2
a      b
c      d
f      g

col1   col2
b      a
d      c
f      g

我通过以下查询实现了这一点,该查询创建了两个人工列,其中包含按排序顺序排列的值,然后应用 GROUP BY,但我认为应该有一个更好看的解决方案。

DELETE t1
FROM testtable t1
INNER JOIN (
    SELECT CASE WHEN col1 < col2 THEN col1 ELSE col2 END AS first, 
    CASE WHEN col1 < col2 THEN col2 ELSE col1 END AS second
    FROM testtable
    GROUP BY CASE WHEN col1 < col2 THEN col1 ELSE col2 END, CASE WHEN col1 < col2 THEN col2 ELSE col1 END
    ) t2 ON t2.first = t1.col1 AND t2.second = t1.col2

您可以使用 exists & not exists :

select t.*
from testtable t 
where exists (select 1 
              from testtable t1 
              where t1.col1 > t.col1 and t1.col1 = t.col2
             ) or
      not exists (select 1 
                  from testtable t1 
                  where t1.col1 < t.col1 and t1.col1 = t.col2
                 );

如果你想删除不需要的记录,你可以这样做:

delete t
from testtable t 
where not exists (select 1 
                  from testtable t1 
                  where t1.col1 > t.col1 and t1.col1 = t.col2
                 ) and
       exists (select 1 
               from testtable t1 
               where t1.col1 < t.col1 and t1.col1 = t.col2
              );

我认为您可以通过向联接添加条件来简化查询:

    DELETE T1
    FROM #testable T1
        INNER JOIN #testable T2 ON T1.col1 = T2.col2 AND T1.col2 = T2.col1 AND T1.col1 > T1.col2

假设没有实际重复,我会这样做:

delete t from testtable t
    where col1 > col2 and
          exists (select 1
                  from testtable t2
                  where t2.col1 = t.col2 and t2.col2 = t.col1
                 );

也就是说,删除 col1 > col2 所在的行,但前提是 "paired" 行已经存在于 table.