Counting the number of values per column - sql

Assume the following table
---------------------------------------------
ID Col1 Col2 Col3 Col4 ... ColN
--------------------------------------------
1 bla foo abc
2 foo abc
3 bar
4 baz
5 baz bar cuz
6 123 foo
7 123
8 oof
--------------------------------------------
Is there a way to list to count the number of values per column without having to make a separate query for each column?
So output would be like:
----------
Col Hits
----------
Col1 4
Col2 3
Col3 5
Col4 0
...
ColN 2
----------
Any push into the right direction would be great!

You can unpivot and aggregate:
select v.which, count(v.col)
from t cross apply
(values ('col1', col1), ('col2', col2), . . . ('coln', coln)
) v(which, col)
group by v.which;

Related

UNPIVOT - DB2 SQL

I have data like below
ROW_ID Col0 Col1 Col2 Col3
1 05/22/2020 123 ABC 1
2 05/12/2020 DEF 1 2
3 06/13/2020 PRR N1 4
I am looking for the output where data will transformed very little and then will be un-pivoted as shown below
ROW_ID COLUMN_NAME VALUE
1 Col0 05/22/2020
1 Drv_Col0 May-2020
1 Col1 123
1 Col2 ABC
1 Col3 1
1 Sum_Col3 3
2 Col0 05/12/2020
2 Drv_Col0 May-2020
2 Col1 DEF
2 Col2 1
2 Col3 2
2 Sum_Col3 3
3 Col0 06/13/2020
3 Drv_Col0 Jun-2020
3 Col1 PRR
3 Col2 N1
3 Col3 4
3 Sum_Col3 4
You can use a lateral join. Assuming that the columns all have the same type:
select t.row_id, v.*
from t cross join lateral
(values ('Col0', col0),
('Drv_Col0', to_char(col0, 'MON-YYYY'),
('Col1', col1),
('Col2', col2),
('Col3', col3),
('Sum_Col3', ???)
) v(column_name, value);
Note: You may need to cast the columns so they are all strings.
The question does not specify how sum_col3 is defined and the definition is not obvious. But some expression can go there.

Get column name where values differ between two rows

I have a table with lots of columns. Sometimes I need to find differences between two rows. I can do it just by scrolling through screen but it is dull. I'm looking for a query that will do this for me, something like
SELECT columns_for_id_1 != columns_for_id_2
FROM xyz
WHERE id in (1,2)
Table:
id col1 col2 col3 col4
1 qqq www eee rrr
2 qqq www XXX rrr
Result:
"Different columns: id, col3"
Is there a simple way to do this?
UPDATE
Another example as wanted:
What I have (table has more than 50 column, not only 7):
Id| Col1 | Col2 | Col3 | Col4 | Col5 | Col6 |
==============================================
1 | aaa | bbb | ccc | ddd | eee | fff |
----------------------------------------------
2 | aaa | XXX | ccc | YYY | eee | fff |
Query:
SELECT *
FROM table
WHERE Id = 1 OR Id = 2
AND "columns value differs"
Query result: "Id, Col2, Col4"
OR something like:
Id|Col2 |Col4 |
===============
1 |bbb |ddd |
---------------
2 |XXX |YYY |
Right now I have to scroll through more than 50 columns to see if rows are the same, it's not efficient and prone to mistakes. I don't want any long query like
SELECT (COMPARE Id1.Col1 with Id2.Col1 if different then print "Col1 differs", COMPARE Id1.Col2 with Id2.Col2...) because I will compare the rows myself faster ;)
Something like this:
SELECT col, MIN(VAL) AS val1, MAX(val) AS val2
FROM (
SELECT id, val, col
FROM (
SELECT id, [col1], [col2], [col3], [col4]
FROM mytable
WHERE id IN (1,2)) AS src
UNPIVOT (
val FOR col IN ([col1], [col2], [col3], [col4])) AS unpvt ) AS t
GROUP BY col
HAVING MIN(val) <> MAX(val)
Output:
col val1 val2
================
col3 eee XXX
Try this simple query, may be help you
SELECT (CASE WHEN a.col1 <> b.col1 THEN 'Different Col1'
WHEN a.col2 <> b.col2 THEN 'Different Col2'
...
ELSE 'No Different' END) --You can add only required columns here
FROM xyz AS a
INNER JOIN xyz AS b ON b.id = 1 --First Record
WHERE a.id = 2 --Second record to compare
If you are on SQL Server 2012 then you can also use LEAD/LAG windowed funuction to do this. MSDN Reference is here - https://msdn.microsoft.com/en-us/library/hh213125.aspx
select
id,
col1,
col2,
col3,
col4,
stuff(diff_cols,len(diff_cols-1),1,'') diff_cols
from
(
SELECT
id,
col1,
col2,
col3,
col4,
concat
(
'Different columns:',
CASE
WHEN LEAD(id, 1,0) OVER (ORDER BY id) <> id THEN 'id,'
WHEN LEAD(col1, 1,0) OVER (ORDER BY id) <> col1 THEN 'col1,'
WHEN LEAD(col2, 1,0) OVER (ORDER BY id) <> col2 THEN 'col2,'
WHEN LEAD(col3, 1,0) OVER (ORDER BY id) <> col3 THEN 'col3,'
WHEN LEAD(col4, 1,0) OVER (ORDER BY id) <> col4 THEN 'col4,'
) diff_cols
FROM xyz
) tmp

Need help in Sql query joining operation

I have below test table with data:
Create table test
(
col1 int,
col2 int
)
Sample data:
col1 col2
-------------
1 4
1 5
2 4
3 5
3 4
Now I want all the col1 which have col2 value 4 and 5
o/p 1,3 since it contain 4 as well as 5 col2 value
SELECT *
FROM TestTable
WHERE col1 IN
(
SELECT col1
FROM TestTable
WHERE col2 = 4
)
AND col2 = 5
If you only need col1 value, you can do
of course, the value in the having clause (2 in this case) depends on the numbers of elements in the IN clause (so if you have 3, 4, 5, you'll need to put 3 in the having clause)
select col1 from test t1
where col2 in (4, 5)--take only results with 4 and 5 in col2
group by col1
having count(distinct col2) = 2 --be sure there's at least a 4 and a 5

ordering the query output based on the data division

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

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