Reputation: 41
I would like to group (a,b) and (b,a) into one group (a,b) in SQL
For e.g the following set
SELECT 'a' AS Col1, 'b' AS Col2
UNION ALL
SELECT 'b', 'a'
UNION ALL
SELECT 'c', 'd'
UNION ALL
SELECT 'a', 'c'
UNION ALL
SELECT 'a', 'd'
UNION ALL
SELECT 'b', 'c'
UNION ALL
SELECT 'd', 'a'
should yield
Col1 | Col2
a b
c d
a c
a d
b c
Upvotes: 3
Views: 116
Reputation: 45096
select col1, col2 from table
except
select col2, col2 from table where col2 > col1
Upvotes: 0
Reputation: 7036
By value, (a, b) doesn't equal to (b, a). If you want to treat them the same, you're creating new key column(s) for each row. The overall logic would be
WITH TableWithNewKey
(
SELECT <original columns>, <new columns as key>
FROM originaltable
)
SELECT <new columns as key>, Aggregate(...)
FROM TableWithNewKey
GROUP BY <new columns as key>
In your case, <new columns as key>
is to convert (b, a) to (a, b). It can be case statement to swap a and b or other functions. This form applies to any number of columns and other equality comparison.
Upvotes: 0
Reputation: 32392
Group by a case statement that selects the pairs in alphabetical order:
select case when col1 < col2 then col1 else col2 end as col1,
case when col1 < col2 then col2 else col1 end as col2
from (
select 'a' as col1, 'b' as col2
union all
select 'b', 'a'
union all
select 'c', 'd'
union all
select 'a', 'c'
union all
select 'a', 'd'
union all
select 'b', 'c'
union all
select 'd', 'a'
) t group by case when col1 < col2 then col1 else col2 end,
case when col1 < col2 then col2 else col1 end
http://sqlfiddle.com/#!3/9eecb7db59d16c80417c72d1/6977
If you simply want unique values (as opposed to a grouping for aggregation) then you can use distinct
instead of group by
select distinct case when col1 < col2 then col1 else col2 end as col1,
case when col1 < col2 then col2 else col1 end as col2
from (
select 'a' as col1, 'b' as col2
union all
select 'b', 'a'
union all
select 'c', 'd'
union all
select 'a', 'c'
union all
select 'a', 'd'
union all
select 'b', 'c'
union all
select 'd', 'a'
) t
Upvotes: 4
Reputation: 350310
As an alternative, you could use a UNION
to achieve this:
WITH cte AS (
SELECT 'a' AS Col1, 'b' AS Col2
UNION ALL
SELECT 'b', 'a'
UNION ALL
SELECT 'c', 'd'
UNION ALL
SELECT 'a', 'c'
UNION ALL
SELECT 'a', 'd'
UNION ALL
SELECT 'b', 'c'
UNION ALL
SELECT 'd', 'a')
SELECT col1, col2 FROM cte WHERE col1 < col2 OR col1 IS NULL
UNION
SELECT col2, col1 FROM cte WHERE col1 >= col2 OR col2 IS NULL
ORDER BY 1, 2
Note that a UNION
removes duplicates.
If you don't have NULL
values, you can of course omit the OR
part in the WHERE
clauses.
Upvotes: 2