ordering the query output based on the data division - sql

SELECT col2,col3 FROM (
select * from (
select * from A
MINUS
select * from A where col3 LIKE '63%'
) ORDER BY CASE WHEN col3 like '63%' THEN 2 ELSE 1 END
)
This gives the output rows as,
col1 col2 col3
---- ---- ----
1. x b 123
2. a y 247
3. n m 634
4. l o 639
Basically the output is divided into two parts as the part that shows col3 NOT like '63%' (Rows 1 and 2) and col3 like '63%' (Rows 3 and 4)
Now I need to sort each part by col1. i.e. Sort rows 1 and 2 and rows 3 and 4. So the output should be,
col1 col2 col3
---- ---- ----
1. a y 247
2. x b 123
3. l o 639
4. n m 634
someone help me in what should added to the query please.
Edit: Well I am not sure and clear about this idea but does the group by is help ful in this scenario
Thanks

You can order by any set of expressions. Separate them by ','
SELECT col2,col3
FROM a
ORDER BY (CASE WHEN col1 like '63%' THEN 2 ELSE 1 END), col1

Well I'm not sure if I
SELECT col2,col3
FROM ( select *
from ( select * from A
MINUS
select * from A where col1 LIKE '63%'
)
ORDER BY CASE WHEN col1 like '63%' THEN 2 ELSE 1 END
)
Can give you this result:
col1 col2 col3
---- ---- ----
1. x b 123
2. a y 247
3. n m 634
4. l o 639
As in the original query the output is only two columns (select col2,col3 from).
And your query can be simplified a bit, like
SELECT col1, col2, col3
FROM A
WHERE col1 NOT LIKE '63%'
ORDER BY CASE WHEN col3 like '63%' THEN 2 ELSE 1 END
Now you can append another rule to ORDER BY:
SELECT col1, col2, col3
FROM A
WHERE col1 NOT LIKE '63%'
ORDER BY CASE WHEN col3 like '63%' THEN 2 ELSE 1 END, col1
HTH

Related

How can I find groups with more than one rows and list the rows in each such group?

I have a table "mytable" in a database.
Given a subset of the columns of the table, I would like to group by the subset of the columns, and find those groups with more than one rows:
For example, if the table is
col1 col2 col3
1 1 1
1 1 2
1 2 1
2 2 1
2 2 3
2 1 1
I am interested in finding groups by col1 and col2 with more than one rows, which are:
col1 col2 col3
1 1 1
1 1 2
and
col1 col2 col3
2 2 1
2 2 3
I was wondering how to write a SQL query for that purpose?
Is the following the best way to do that?
First get the col1 and col2 values of such groups:
SELECT col1 col2 COUNT(*)
FROM mytable
GROUP BY col1, col2
HAVING COUNT(*) > 1
Then based on the output of the previous query, manually write a query for each group:
SELECT *
FROM mytable
WHERE col1 = val1 AND col2 = val2
If there are many such groups, then I will have to manually write many queries, which can be a disadvantage.
I am using SQL Server.
Thanks.
This is a common problem. One solution is to get the "keys" in a derived table and join to that to get the rows.
declare #test as table (col1 int, col2 int, col3 int)
insert into #test values (1,1,1),(1,1,2),(1,2,1),(2,2,1),(2,2,3),(2,1,1)
select t.*
from #test t
inner join (
select col1, col2
from #test
group by col1, col2
having count(*) > 1
) k
on k.col1 = t.col1 and k.col2 = t.col2
col1 col2 col3
----------- ----------- -----------
1 1 1
1 1 2
2 2 1
2 2 3
The window function sum() over() may help here
Example
with cte as (
Select *
,Cnt = sum(1) over (partition by Col1,Col2)
From YourTable
)
Select *
From cte
Where Cnt>=2
Results
Another option (less performant)
Select top 1 with ties *
From YourTable
Order By case when sum(1) over (partition by Col1,Col2) > 1 then 1 else 2 end
Results

Sort columns in a row after numeric value

I have a task where I need to order the results of query in a way, that the highest of 3 values gets displayed in the first column after the ID, the second highest in the middle one and the smallest in the last column.
The tables look like this:
ID
Col1
Col2
Col3
1234
30
50
40
2345
40
30
60
3456
60
50
40
And the result should look like this:
ID
Col1
Col2
Col3
1234
50
40
30
2345
60
40
30
3456
60
50
40
The values are package dimensions which need to be in order to be processed.
Thank you in advance :)
This is pretty simple using apply:
select t.*, v.*
from t outer apply
(select max(case when seqnum = 1 then col end) as col1,
max(case when seqnum = 2 then col end) as col2,
max(case when seqnum = 3 then col end) as col3
from (select v.col,
row_number() over (order by v.col desc) as seqnum
from (values (t.col1), (t.col2), (t.col3)
) v(col)
) v
) v;
SQL Server is quite efficient when using APPLY within a single row. I would expect the performance to be comparable to a bunch of complex case expressions. In addition, this gives more flexibility if any of the values are NULL.
And, it is much easier to expand to more columns!
Unfortunately, there is no simple and short way of achieving this.
Try below query:
select
case when col1 > col2 and col1 > col3 then col1
else case when col2 > col1 and col2 > col3 then col2
else col3 end end,
case when (col1 > col2 and col1 < col3) or (col1 < col2 and col1 > col3) then col1
else case when (col2 > col1 and col2 < col3) or (col2 < col1 and col2 > col3) then col2
else col3 end end,
case when col1 < col2 and col1 < col3 then col1
else case when col2 < col1 and col2 < col3 then col2
else col3 end end
from tbl
SQL fiddle
You may also unpivot it, sort the value and then pivot it back
SELECT *
FROM
(
SELECT t.id, v.col,
col_no = row_number() over (partition by t.id order by v.col desc)
FROM yourtable t
CROSS APPLY
(
VALUES (col1), (col2), (col3)
) v (col)
) d
PIVOT
(
MAX(col)
for col_no in ([1], [2], [3])
) p
the question is not clear but you can use a temp table. First, read the top 3 of data with ordering highest, secondly do it same again with offset value 3, 6 and third times order by lowest.
push the results after each step
read the temp table

select query to fetch rows corresponding to all values in a column

Consider this example table "Table1".
Col1 Col2
A 1
B 1
A 4
A 5
A 3
A 2
D 1
B 2
C 3
B 4
I am trying to fetch those values from Col1 which corresponds to all values (in this case, 1,2,3,4,5). Here the result of the query should return 'A' as none of the others have all values 1,2,3,4,5 in Col2.
Note that the values in Col2 are decided by other parameters in the query and they will always return some numeric values. Out of those values the query needs to fetch values from Col1 corresponding to all in Col2. The values in Col2 could be 11,12,1,2,3,4 for instance (meaning not necessarily in sequence).
I have tried the following select query:
select distinct Col1 from Table1 where Col1 in (1,2,3,4,5);
select distinct Col1 from Table1 where Col1 exists (select distinct Col2 from Table1);
and its different variations. But the problem is that I need to apply an 'and' for Col2 not an 'or'.
like Return a value from Col1 where Col2 'contains' all values between 1 and 5.
Appreciate any suggestion.
You could use analytic ROW_NUMBER() function.
SQL FIddle for a setup and working demonstration.
SELECT col1
FROM
(SELECT col1,
col2,
row_number() OVER(PARTITION BY col1 ORDER BY col2) rn
FROM your_table
WHERE col2 IN (1,2,3,4,5)
)
WHERE rn =5;
UPDATE As requested by OP, some explanation about how the query works.
The inner sub-query gives you the following resultset:
SQL> SELECT col1,
2 col2,
3 row_number() OVER(PARTITION BY col1 ORDER BY col2) rn
4 FROM t
5 WHERE col2 IN (1,2,3,4,5);
C COL2 RN
- ---------- ----------
A 1 1
A 2 2
A 3 3
A 4 4
A 5 5
B 1 1
B 2 2
B 4 3
C 3 1
D 1 1
10 rows selected.
PARTITION BY clause will group each sets of col1, and ORDER BY will sort col2 in each group set of col1. Thus the sub-query gives you the row_number for each row in an ordered way. now you know that you only need those rows where row_number is at least 5. So, in the outer query all you need ot do is WHERE rn =5 to filter the rows.
You can use listagg function, like
SELECT Col1
FROM
(select Col1,listagg(Col2,',') within group (order by Col2) Col2List from Table1
group by Col1)
WHERE Col2List = '1,2,3,4,5'
You can also use below
SELECT COL1
FROM TABLE_NAME
GROUP BY COL1
HAVING
COUNT(COL1)=5
AND
SUM(
(CASE WHEN COL2=1 THEN 1 ELSE 0
END)
+
(CASE WHEN COL2=2 THEN 1 ELSE 0
END)
+
(CASE WHEN COL2=3 THEN 1 ELSE 0
END)
+
(CASE WHEN COL2=4 THEN 1 ELSE 0
END)
+
(CASE WHEN COL2=5 THEN 1 ELSE 0
END))=5

Element-wise quotient of two columns in SQL

How can I combine the columns returned by two SELECT statements to give their element-wise quotient?
Query 1:
SELECT COUNT(*) AS count
FROM table1
WHERE col2 = 1 AND col3 > 5
GROUP BY col4
ORDER BY col4
Query 2:
SELECT COUNT(*) AS count
FROM table1
WHERE col2 = 1
GROUP BY col4
ORDER BY col4
So if they return something like:
Query 1 Query 2
count count
-----------------------
1 5
2 4
I will get:
quotient
-------
0.2
0.5
With the 4-column version of the question, we can assume that the quotient is between groups with the same value in col4. So, the answer becomes:
SELECT col4, SUM(CASE WHEN col3 > 5 THEN 1 ELSE 0 END) / COUNT(*) AS quotient
FROM table1
WHERE col2 = 1
GROUP BY col4;
I've retained col4 in the output because I don't think the ratios (quotients) will be useful without something to identify which quotient is associated with which values, though theoretically, the answer doesn't want that column in the output.
In this case, you don't need two separate queries at all:
SELECT SUM(col3 > 5) / COUNT(*)
FROM table1
WHERE col2 = 1
GROUP BY col4
ORDER BY col4
In case your actual queries cannot be simplified as per the other answers, you can join the subqueries, like this:
select j1.count / j2.count as quotient
from (
SELECT col4, COUNT(*) AS count
FROM table1
WHERE col2 = 1 AND col3 > 5
GROUP BY col4
) j1
join (
SELECT col4, COUNT(*) AS count
FROM table1
WHERE col2 = 1
GROUP BY col4
) j2 on j1.col4=j2.col4

How to figure out which column/value the COALESCE operator successfully selected?

I have a table that I wish to find the first non-null value from 3 (and only 3) columns for each ID starting with Col1 then to Col2 then to Col3
Note: Col3 is NEVER NULL
ID Col1 Col2 Col3
------------------------------
1 A B X
2 NULL C X
3 NULL NULL X
4 D NULL X
To get the correct column for each value I use the following SQL Select
SELECT ID,
COALESCE(Col1, Col2, Col3) AS Col
FROM MyTable
which returns the following and works just fine
ID Col
-------------
1 A
2 C
3 X
4 D
What I want is a third column returned indicating which column the coalesce was successful on. The following is the result set that I wish to produce:
ID Col Source
-----------------------
1 A Col1
2 C Col2
3 X Col3
4 D Col1
Perhaps this will work?
SELECT ID,
COALESCE(Col1, Col2, Col3) AS Col,
CASE COALESCE(Col1, Col2, Col3)
WHEN Col1 THEN 'Col1'
WHEN Col2 THEN 'Col2'
WHEN Col3 THEN 'Col3'
ELSE 'Unknown'
END AS Source
FROM MyTable