SQL query to extract matching diagonal pairs in SQL Server database - sql

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

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.

Related

How to Batch select in oracle sql

i have one mock table table_a as below:
id a b c d
1 11 22 33 44
2 22 33 44 55
3 33 44 55 66
4 44 55 66 77
5 55 66 77 88
6 66 77 88 99
7 77 88 99 100
8 88 99 11 22
suppose the known info is c and d, if i want to get entry id 2 & 6, i can run
' select * from table_a where (c, d) in ((44,55), (88,99))'.
Here is my question. If this table has 1 million rows , and i want to get 1 thousand rows out , just by knowing their c and d values, is there any better way to do it? My concern to use above script to do it is performance. Thanks.
If you have an index on (c, d), then Oracle should use the index for the in query:
create index idx_table_a_c_d on table_a(c, d);

SQL Server : create new column category price according to price column

I have a SQL Server table with a column price looking like this:
10
96
64
38
32
103
74
32
67
103
55
28
30
110
79
91
16
71
36
106
89
87
59
41
56
89
68
32
80
47
45
77
64
93
17
88
13
19
83
12
76
99
104
65
83
95
Now my aim is to create a new column giving a category from 1 to 10 to each of those values.
For instance the max value in my column is 110 the min is 10. Max-min = 100. Then if I want to have 10 categories I do 100/10= 10. Therefore here are the ranges:
10-20 1
21-30 2
31-40 3
41-50 4
51-60 5
61-70 6
71-80 7
81-90 8
91-100 9
101-110 10
Desired output:
my new column called cat should look like this:
price cat
-----------------
10 1
96 9
64 6
38 3
32 3
103 10
74 7
32 3
67 6
103 10
55 5
28 2
30 3
110 10
79 7
91 9
16 1
71 7
36 3
106 10
89 8
87 8
59 5
41 4
56 5
89 8
68 6
32 3
80 7
47 4
45 4
77 7
64 6
93 9
17 1
88 8
13 1
19 1
83 8
12 1
76 7
99 9
104 10
65 6
83 8
95 9
Is there a way to perform this with T-SQL? Sorry if this question is maybe too easy. I searched long time on the web. So either the problem is not as simple as I imagine. Either I entered the wrong keywords.
Yes, almost exactly as you describe the calculation:
select price,
1 + (price - min_price) * 10 / (max_price - min_price + 1) as decile
from (select price,
min(price) over () as min_price,
max(price) over () as max_price
from t
) t;
The 1 + is because you want the values from 1 to 10, rather than 0 to 9.
Yes - a case statement can do that.
select
price
,case
when price between 10 and 20 then 1
when price between 21 and 30 then 2
when price between 31 and 40 then 3
when price between 41 and 50 then 4
when price between 51 and 60 then 5
when price between 61 and 70 then 6
when price between 71 and 80 then 7
when price between 81 and 90 then 8
when price between 91 and 100 then 9
when price between 101 and 110 then 10
else null
end as cat
from [<enter your table name here>]

How to divide a result set into equal parts?

I have a table new_table
ID PROC_ID DEP_ID OLD_STAFF NEW_STAFF
1 15 43 58 ?
2 19 43 58 ?
3 29 43 58 ?
4 31 43 58 ?
5 35 43 58 ?
6 37 43 58 ?
7 38 43 58 ?
8 39 43 58 ?
9 58 43 58 ?
10 79 43 58 ?
How I can select all proc_ids and update new_staff, for example
ID PROC_ID DEP_ID OLD_STAFF NEW_STAFF
1 15 43 58 15
2 19 43 58 15
3 29 43 58 15
4 31 43 58 15
5 35 43 58 23
6 37 43 58 23
7 38 43 58 23
8 39 43 58 28
9 58 43 58 28
10 79 43 58 28
15 - 4(proc_id)
23 - 3(proc_id)
28 - 3(proc_id)
58 - is busi
where 15, 23, 28 and 58 staffs in one dep
"how to divide equal parts"
Oracle has a function, ntile() which splits a result set into equal buckets. For instance this query puts your posted data into four buckets:
SQL> select id
2 , proc_id
3 , ntile(4) over (order by id asc) as gen_staff
4 from new_table;
ID PROC_ID GEN_STAFF
---------- ---------- ----------
1 15 1
2 19 1
3 29 1
4 31 2
5 35 2
6 37 2
7 38 3
8 39 3
9 58 4
10 79 4
10 rows selected.
SQL>
This isn't quite the solution you want but you need to clarify your requirements before it's possible to provide a complete answer.
update new_table
set new_staff='15'
where ID in('1','2','3','4')
update new_table
set new_staff='28'
where ID in('8','9','10')
update new_table
set new_staff='23'
where ID in('5','6','7')
Not sure if this is what you mean.

Interval of consecutive numbers with Oracle SQL and JOINS

I'm trying to display the intervals of consecutive elevations in Iceland, per row, in a form like this:
ELEVATION
0 27
29 33
35
37 40
42 46
48
51 63
For now, I only managed to track the gaps, I have something in mind like:
If the (count of the values in columnB until columnC='GAP') equals
that value of columnB where columnC='GAP' THEN we have a consecutive interval
between the value of columnA and column B
Can anyone give me some tips ?
current code
with x as (
SELECT distinct elevation
FROM CITIES
WHERE iso = 'IS' AND iso IS NOT NULL
),y as (
SELECT a.ELEVATION as "A",B.ELEVATION as "B",C.ELEVATION as "C"
FROM x a
JOIN x b ON b.ELEVATION > a.ELEVATION
LEFT JOIN x c ON c.ELEVATION > b.ELEVATION AND c.ELEVATION < b.ELEVATION + 2
)select y.A,y.B,y.C,case when y.C is null then 'GAP' else ' ' end GAPZ from y
order by 1,2
output
A B C GAP
------------------
0 1 2
0 2 3
0 3 4
...
...
...
0 25 26
0 26 27
0 27 GAP
0 29 30
0 30 31
0 31 32
0 32 33
0 33 GAP
0 35 GAP
0 37 38
0 38 39
0 39 40
0 40 GAP
0 42 43
0 43 44
0 44 45
0 45 46
0 46 GAP
0 48 GAP
0 51 52
0 52 53
...
...
...
0 61 62
0 62 63
0 63 GAP
0 65 66
0 66 67
0 67 68
0 68 69
0 69 GAP
0 71 72
...
...
...
You're halfway there! You need to flag either end of the gap, then select only those rows.
Select x,
Case lead(x,x) over(order by x)
When x+1 then null
Else x
End as endpoint,
Case lag(x,x) over(order by x)
When x-1 then null
Else x
End as startpoint
From table
This will show whether a row is a start or endpoint. Let's call that Q1. Now we just select what we need from that.
Select Q1.startpoint,
(Select min(endpoint)
From Q1 as endp
Where endp.endpoint >= Q1.x) as endpoint
From Q1
Where Q1.startpoint is not null

trying to get user assign to under another user

I am trying to write a sql query in which I want all the list of uid assigned under another uid from the below given table
uid rid assTo
1 1 NULL
2 2 1
3 1 2
6 11 3
7 11 1
17 11 1
18 11 1
19 11 1
21 11 1
22 2 1
23 11 22
24 2 22
25 10 24
26 10 24
27 11 26
28 11 26
29 10 24
30 11 3
31 11 29
32 11 29
33 11 29
34 11 29
35 11 29
36 11 29
37 11 29
38 11 29
39 11 29
40 11 29
41 11 29
47 11 2
48 11 2
50 11 26
51 11 2
52 11 26
53 11 29
55 11 1
56 11 1
57 11 652
68 11 652
70 11 652
71 11 652
72 11 2
74 1 1
75 11 2
76 11 652
80 11 652
86 11 652
87 11 1
88 11 26
89 11 29
I want all the list of uid assigned to another uid i.e. designated in assto column in above table
How can I implement it?
My query
select u1.assignto 'assignto',u2.userid 'userid'
from users u1 join users u2
on u1.assignto=u2.userid
My desired output is that when i search uid = 1
i should the list of the uid available in the above table.
IN solution:
select * from tablename
where uid in (select assTo from tablename)
Self JOIN solution:
select distinct t1.*
from tablename t1
JOIN tablename t2 ON t1.uid= t2.assTo
EXISTS solution (similar to IN):
select *
from tablename t1
where exists (select 1 from tablename t2
where t2.assTo = t1.uid)