I have a database table (mytable
) with 2 columns x
and y
as shown below, from which I intend to extract rows with matching diagonal pairs of (x,y) and (y,x) e.g., 4 21 and 21 4
x y 86 86 27 27 45 45 95 95 11 11 18 8 85 85 2 2 77 77 91 91 15 15 84 84 51 51 32 32 35 35 8 8 92 92 67 67 62 62 33 33 13 13 15 11 18 18 3 3 38 38 80 80 34 34 6 6 72 72 14 12 44 44 4 22 90 90 47 47 78 78 23 3 42 42 56 56 79 79 55 55 65 65 17 17 64 64 4 4 28 28 19 19 17 9 36 36 25 25 81 81 60 60 48 48 5 5 88 88 7 19 21 21 29 29 52 52 9 17 9 9 13 13 16 10 1 1 31 31 46 46 7 7 58 58 23 23 87 87 83 83 66 66 93 93 24 2 98 98 53 53 20 6 61 61 20 20 96 96 99 99 73 73 2 24 14 14 71 71 5 21 22 4 75 75 6 20 97 97 41 41 26 26 22 22 8 18 74 74 40 40 21 5 94 94 76 76 49 49 11 15 59 59 89 89 68 68 24 24 37 37 12 12 63 63 43 43 16 16 100 100 39 39 25 1 69 69 54 54 50 50 30 30 10 10
I have tried the accepted code on stackoverflow here (enter link description here) on my mytable which gives me the expected results on Oracle DB.
select least(x, y) as x, greatest(x, y) as y from mytable group by least(x, y), greatest(x, y) having count(*) = 2 union all select x, y from mytable where not exists (select 1 from mytable mytable2 where mytable2.y = mytable.x and mytable2.x = mytable2.y) order by x asc;
Now I need to execute the same query on MS SQL DB but according to my understanding MS SQL DB does not support the least and greatest functions. I have tried to use the case conditions, for instance for the first part of the SQL query on the link provided, I am considering the below but so far I cannot replicate similar results:
select x,y,z from ( select x, y, case when (x < y) then x when (y > x) then y end as z from mytable group by x, y ) as t
Any suggestions on what I need to consider to complete the query in SQL Server database, so that I produce the final output as below?
It would also be great if somebody has an idea on how I can use SQL’s lag()
function to assist me in achieving the same result. For instance I am trying something like below.
;with t1 as ( select x as x1, y as y1, lag(x,1) over(order by x asc) as z1 from mytable ), t2 as ( select x as x2, y as y2, lag(y,1) over(order by x asc) as z2 from mytable ) select t1.*,t2.* from t1 full outer join t2 on t1.x1 = t2.x2
Expected output:
x y 2 24 4 22 5 21 6 20 8 18 9 17 11 15 13 13
Advertisement
Answer
The equivalent of the functions LEAST()
and GREATEST()
is to use CASE
expressions:
SELECT CASE WHEN x < y THEN x ELSE y END AS x, CASE WHEN x > y THEN x ELSE y END AS y FROM mytable GROUP BY CASE WHEN x < y THEN x ELSE y END, CASE WHEN x > y THEN x ELSE y END HAVING COUNT(*) = 2 -- change to COUNT(*) > 1 if each combination may exist more than twice ORDER BY x, y;
The above query will return a row for a combination of (x, y)
that exists twice even if (y, x)
does not exist.
If this is not what you want, use a self join and UNION ALL
:
SELECT DISTINCT t1.* FROM mytable t1 INNER JOIN mytable t2 ON t2.x = t1.y AND t2.y = t1.x WHERE t1.x < t1.y UNION ALL SELECT x, y FROM mytable WHERE x = y GROUP BY x, y HAVING COUNT(*) > 1 ORDER BY x, y;
See the demo.