Search code examples
sql-servert-sqljoinsql-delete

SQL: Delete only one row if join returns multiple matches


I have an SQL table that looks as follows:

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

As you can see there are rows where both columns col1 and col2 are inverted. What I mean is that in the first row the values a and b are in both columns and in row 2 the values are also there, but the other way round.

I now want to delete one row of each of these pairs. I do not care which side of the pair is deleted. So either row 1 and row 3 or row 2 and row 4 should be deleted.

The result should looks as follows:

col1   col2
a      b
c      d
f      g

or

col1   col2
b      a
d      c
f      g

I achieved this with the following query that creates two artificial columns that contain the values in a sorted order and then applies a GROUP BY, but I assume there should be a nicer looking solution.

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

Solution

  • I think you can simplify your query by adding conditions to the join:

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