How to get number of false in every column of a table? - sql

I have a table say T_myTable it has 5 columns and all have some values either true or false.
--------------------------------
col1 | col2 | col3 | col4 | col5
--------------------------------
true | false|false|true |false
false| true |false|false|false
true | false|false|true |false
false| false|false|true |false
I want to get result as:-
col1 | col2 | col3 | col4 | col5
--------------------------------
2 | 3 |4 |1 |4
Where these numbers here are numbers of false.
Also true and false are varchar.

This:
SELECT SUM(CASE WHEN Col1 = 'false' THEN 1 ELSE 0 END) AS Col1
, SUM(CASE WHEN Col2 = 'false' THEN 1 ELSE 0 END) AS Col2
, SUM(CASE WHEN Col3 = 'false' THEN 1 ELSE 0 END) AS Col3
, SUM(CASE WHEN Col4 = 'false' THEN 1 ELSE 0 END) AS Col4
, SUM(CASE WHEN Col5 = 'false' THEN 1 ELSE 0 END) AS Col5
FROM T_myTable

Try this:
SELECT SUM(CASE col1 WHEN 'false' THEN 1 ELSE 0 END),
SUM(CASE col2 WHEN 'false' THEN 1 ELSE 0 END),
SUM(CASE col3 WHEN 'false' THEN 1 ELSE 0 END),
SUM(CASE col4 WHEN 'false' THEN 1 ELSE 0 END),
SUM(CASE col5 WHEN 'false' THEN 1 ELSE 0 END)
FROM T_myTable

One of the most interesting way is to:
unpivot data to be able to filter data
pivot data again to get count of 'false'
Check this:
SELECT [col1],[col2],[col3],[col4],[col5]
FROM (
SELECT MyVal, ColName
FROM (
SELECT *
FROM T_myTable
) AS pvt
UNPIVOT(MyVal FOR ColName IN ([col1],[col2],[col3],[col4],[col5])) AS unpvt
WHERE MyVAl = 'false'
) As DT
PIVOT (COUNT(MyVal) FOR ColName IN ([col1],[col2],[col3],[col4],[col5])) AS PT
Result:
col1 col2 col3 col4 col5
2 3 4 1 4

Related

Update row in a table based on a column in the same table

How can I update rows in a table based on values in a column in the same table?
TableA:
col1 col2 col3 total col_num
NULL NULL NULL 100 1
NULL NULL NULL 200 2
NULL NULL NULL 300 3
Result after update:
TableA:
col1 col2 col3 total col_num
100 NULL NULL 100 1
NULL 200 NULL 200 2
NULL NULL 300 300 3
Unless you resort to somehow dynamically constructing the SQL statement, you can't do this generically. However, for a closed set of columns, you could use a bunch of case expressions:
UPDATE tableA
SET col1 = CASE col_num WHEN 1 THEN total ELSE col1 END,
col2 = CASE col_num WHEN 2 THEN total ELSE col2 END,
col3 = CASE col_num WHEN 3 THEN total ELSE col3 END
You can use case expressions:
update tablea
set
col1 = case when col_num = 1 then total end,
col2 = case when col_num = 2 then total end,
col3 = case when col_num = 3 then total end
You would possibly include some logic to update only non-null columns
update tablea
set
col1 = case when col1 is null and col_num = 1 then total end,
col2 = case when col2 is null and col_num = 2 then total end,
col3 = case when col3 is null and col_num = 3 then total end
where
(col1 is null and col_num = 1)
or (col2 is null and col_num = 2)
or (col3 is null and col_num = 3)

PostgreSQL query rows with least null value on columns

How can I query rows where the output would be the rows with least null value on the columns?
My data is:
ID | col1 | col2 | col3 | col4
-----------+----------+-----------+-----------+-----------
1 | Null |Null | with value| with value
2 |with value|Null | with value| with value
3 |with value|Null | Null | Null
where the result would be:
ID | col1 | col2 | col3 | col4
-----------+----------+-----------+-----------+-----------
2 |with value|Null | with value| with value
Because id 2 is the record with fewest null values.
Any help will be greatly appreciated. Thanks
You can:
Order rows by number of nulls (ascending)
Limit rows to 1 ( LIMIT 1 )
Your code:
SELECT *
FROM your_table
ORDER BY
CASE WHEN col1 IS NULL THEN 1 ELSE 0 END +
CASE WHEN col2 IS NULL THEN 1 ELSE 0 END +
CASE WHEN col3 IS NULL THEN 1 ELSE 0 END +
CASE WHEN col4 IS NULL THEN 1 ELSE 0 END
LIMIT 1
If you want only one row, then you can do:
select t.*
from t
order by ( (col1 is null)::int + (col2 is null)::int +
(col3 is null)::int + (col4 is null)::int
) asc
fetch first 1 row only;
If you want all such rows, I think I would do:
select t.*
from (select t.*,
dense_rank() over
(order by (col1 is null)::int + (col2 is null)::int +
(col3 is null)::int + (col4 is null)::int
) as null_ranking
from t
) t
where null_ranking = 1;

Concatenate SQL table rows with conditions in single text

I have a SQL table like this
col1 col2 col3
1 0 1
1 1 1
0 1 1
1 0 0
0 0 0
I am expecting output as like this
col1 col2 col3 NewCol
1 0 1 SL,PL
1 1 1 SL,EL,PL
0 1 1 EL,PL
1 0 0 SL
0 0 0 NULL
The condition for this is if col1>0 then SL else ' ', if col2>0 EL else ' ', if col3>0 PL else ' '
I tried to use Concatenate many rows into a single text string? but didn't able to achieve the desired result properly
I have tried It is working fine with a message
Invalid length parameter passed to the LEFT or SUBSTRING function.
WITH CTE AS (
SELECT col1, col2, col3,
CASE WHEN col1 > 0 THEN 'SL,' ELSE '' END +
CASE WHEN col2 > 0 THEN 'EL,' ELSE '' END +
CASE WHEN col3 > 0 THEN 'PL,' ELSE '' END AS NewCol
FROM Employee
)
SELECT col1, col2, col3,
substring(NewCol, 1, len(NewCol) - 1) AS NewCol
FROM CTE
But again my last condition is not matching if all columns is 0 then I have to show NULL as per desired output.
Find the attach fiddle http://sqlfiddle.com/#!6/2bd6a/1
The issue with your code example is that when all columns are 0 then the length is 0 and the substring function will throw an error.
Use nullif to fix it: substring(NewCol, 1, len(nullif(NewCol,'')) - 1) AS NewCol
You could also change to appending the delimiter on the front and use STUFF.
STUFF('',1,1,'') will return NULL rather than an error.
WITH
Employee(col1, col2, col3) AS (
SELECT 1,1,1 UNION ALL
SELECT 0,0,0
),
CTE AS (
SELECT col1, col2, col3,
CASE WHEN col1 > 0 THEN ',SL' ELSE '' END +
CASE WHEN col2 > 0 THEN ',EL' ELSE '' END +
CASE WHEN col3 > 0 THEN ',PL' ELSE '' END AS NewCol
FROM Employee
)
SELECT col1,
col2,
col3,
STUFF(NewCol, 1, 1, '')
FROM CTE
Returns
+------+------+------+------------------+
| col1 | col2 | col3 | (No column name) |
+------+------+------+------------------+
| 1 | 1 | 1 | SL,EL,PL |
| 0 | 0 | 0 | NULL |
+------+------+------+------------------+
You have to check with NULLIF to do this trick
Two ways
SELECT col1, col2, col3,
nullif(CASE WHEN col1 = 1 THEN 'SL,' ELSE '' END +
CASE WHEN col2 = 1 THEN 'EL,' ELSE '' END +
CASE WHEN col3 = 1 THEN 'PL,' ELSE '' END,'') AS NewCol
FROM Employee
OR
SELECT
col1,
col2,
col3,
substring(nullif(NewCol,''), 1, len(NewCol) - 1) AS NewCol
FROM
CTE

How to deal with duplicate rows in SQL?

The table has duplicate IDs from a large table. I want to get one output for each ID. What's the best way to do it?
MyTable
ID Col1 Col2
1 X A
1 Y B
1 Z C
2 X D
2 Y E
3 Z F
3 W G
If Col1 = 'X' and Col2 ='A', then 'Y' is the output for ID1
If Col1 = 'X' and Col2 !='A', then 'N' is the output for ID2
If Col1 != 'X', then 'Y' is the output for ID3
If Col1 = 'X' and Col2 ='A', then 'Y' is the output for ID1
If Col1 = 'X' and Col2 !='A', then 'N' is the output for ID2
If Col1 != 'X', then 'Y' is the output for ID3
I assume the conditions above need to be true for only 1 row per id. You can use conditional aggregation to check whether the condition applies to at least 1 row per group:
select id,
case when count(case when Col1 = 'X' and Col2 = 'A' then 1 end) > 0 then 'Y'
when count(case when Col1 = 'X' and Col2 <> 'A' then 1 end) > 0 then 'N'
when count(case when Col1 = 'X' then 1 end) > 0 then 'Y'
else '?'
end as output
from mytable
group by id

SQL query about self join

I have a sql in db2 as below:
SELECT distinct KEY_COL, MY_TYPE1,
CASE WHEN MY_TYPE2 = 'ONE' THEN COL1 ELSE '' END AS NEWCOL1,
CASE WHEN MY_TYPE2 = 'ONE' THEN COL2 ELSE '' END AS NEWCOL2,
CASE WHEN MY_TYPE2 = 'TWO' THEN COL1 ELSE '' END AS NEWCOL3,
CASE WHEN MY_TYPE2 = 'TWO' THEN COL2 ELSE '' END AS NEWCOL4
FROM MYSCHEMA.MYTABLE
As clear from above query, based on MY_TYPE2 colums in MYSCHEMA.MYTABLE, the new column values are decided.
If the MY_TYPE2 is one, col1 and col2 goes to newcol1 and newcol2 respectively for given key and MY_TYPE1 column. But if the MY_TYPE2 is two for same key and MY_TYPE1, then col1 and col2 goes to newcol3 and newcol4.
The output table looks something like below:
KEY_COL | MY_TYPE1 | NEWCOL1 | NEWCOL2 | NEWCOL3 | NEWCOL4
=========================================================
1 T1 1 2
1 T1 4 3
1 T2 2 3
1 T2 4 1
========================================================
However, I want a single row based on MY_TYPE1 column as below:
KEY_COL | MY_TYPE1 | NEWCOL1 | NEWCOL2 | NEWCOL3 | NEWCOL4
=========================================================
1 T1 1 2 4 3
1 T2 2 3 4 1
========================================================
How to modify the query to achieve above result ?
Thanks for reading!
select key_col, my_type1, max(newcol1), max(newcol2), max(newcol3), max(newcol4)
from
(
SELECT distinct KEY_COL, MY_TYPE1,
CASE WHEN MY_TYPE2 = 'ONE' THEN COL1 ELSE '' END AS NEWCOL1,
CASE WHEN MY_TYPE2 = 'ONE' THEN COL2 ELSE '' END AS NEWCOL2,
CASE WHEN MY_TYPE2 = 'TWO' THEN COL1 ELSE '' END AS NEWCOL3,
CASE WHEN MY_TYPE2 = 'TWO' THEN COL2 ELSE '' END AS NEWCOL4
FROM MYSCHEMA.MYTABLE
) definedTable
group by key_col, my_type1
select KEY_COL ,max(MY_TYPE1),max(NEWCOL1),max(NEWCOL2),max(NEWCOL3),max(NEWCOL4)
from table
group by KEY_COL