Postgresql answer.
Re: How can I selet rows which have 2 columns values cross equal?
Solution by PFC:
What are your conditions on a and b ? Can a be equal to b on a row ? If
so, do you want this row ?
If you want to avoid duplicates, I suggest first removing them, then
adding a constraint CHECK( a < b ) for instance. Then, from you r
application (or in an ON INSERT trigger), swap a and b if a>b.
I added some values to your table for completeness :
SELECT * FROM test;
a | b | id
-----+-----+----
100 | 101 | 1
101 | 100 | 2
100 | 3 | 3
20 | 30 | 4
11 | 13 | 5
3 | 33 | 6
30 | 20 | 7
666 | 666 | 8
666 | 666 | 9
500 | 666 | 10
666 | 500 | 11
123 | 123 | 12
456 | 789 | 13
456 | 789 | 14
Try :
[sql]SELECT x.id AS xid, y.id AS yid, x.a AS xa, x.b AS xb, y.a AS ya, y.b AS yb
FROM test x, test y
WHERE x.a=y.b AND x.b=y.a;[/sql]
xid | yid | xa | xb | ya | yb
-----+-----+-----+-----+-----+-----
1 | 2 | 100 | 101 | 101 | 100
2 | 1 | 101 | 100 | 100 | 101
4 | 7 | 20 | 30 | 30 | 20
7 | 4 | 30 | 20 | 20 | 30
8 | 9 | 666 | 666 | 666 | 666
8 | 8 | 666 | 666 | 666 | 666
9 | 9 | 666 | 666 | 666 | 666
9 | 8 | 666 | 666 | 666 | 666
10 | 11 | 500 | 666 | 666 | 500
11 | 10 | 666 | 500 | 500 | 666
12 | 12 | 123 | 123 | 123 | 123
You'll get 2 rows for each match. You can add a condition to remove the
dupes :
[sql]SELECT x.id AS xid, y.id AS yid, x.a AS xa, x.b AS xb, y.a AS ya, y.b AS yb
FROM test x, test y
WHERE x.a=y.b AND x.b=y.a AND x.id[=y.id;[/sql]
xid | yid | xa | xb | ya | yb
-----+-----+-----+-----+-----+-----
1 | 2 | 100 | 101 | 101 | 100
4 | 7 | 20 | 30 | 30 | 20
8 | 9 | 666 | 666 | 666 | 666
8 | 8 | 666 | 666 | 666 | 666
9 | 9 | 666 | 666 | 666 | 666
10 | 11 | 500 | 666 | 666 | 500
12 | 12 | 123 | 123 | 123 | 123
If you don't want the rows with a=b, replace x.id<=y.id with x.id<y.id
[sql]SELECT x.id AS xid, y.id AS yid, x.a AS xa, x.b AS xb, y.a AS ya, y.b AS yb
FROM test x, test y
WHERE x.a=y.b AND x.b=y.a AND x.id<y.id;[/sql]
xid | yid | xa | xb | ya | yb
-----+-----+-----+-----+-----+-----
1 | 2 | 100 | 101 | 101 | 100
4 | 7 | 20 | 30 | 30 | 20
8 | 9 | 666 | 666 | 666 | 666
10 | 11 | 500 | 666 | 666 | 500
It is going to be slow, though. Basically a full self join. Let's hack
this :
[sql]CREATE AGGREGATE array_accum (
sfunc = array_append,
basetype = anyelement,
stype = anyarray,
initcond = '{}'
);[/sql]
I'll leave this one as an exercice to the reader ;)))
[sql]SELECT array_accum(id), CASE WHEN a<b THEN a ELSE b END AS low, CASE WHEN a<b THEN b ELSE a END AS high
FROM test GROUP BY low, high
HAVING
sum(sign(a-b)) = 0 AND count(*)]1;[/sql]
array_accum | low | high
-------------+-----+------
{10,11} | 500 | 666
{4,7} | 20 | 30
{1,2} | 100 | 101
{8,9} | 666 | 666
|