SQL query about self join - sql

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

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)

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

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

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 Compare grouped values

If we have a table like:
col1 | col2
-----------
A | 1
B | 2
A | 1
C | 16
B | 3
How it can be determined if the all rows for given value in col1 are the same?
For example, here whe have only '1's for A, but for B we have '2' and '3'.
Something like:
A | true
B | false
C | true
select col1, case when count(distinct col2) = 1
then 'true'
else 'false'
end as same_col2_results
from your_table
group by col1
I have a preference for using min() and max() for this purpose, rather than count(distinct):
select col1,
(case when min(col2) = max(col2) then 'true' else 'false' end) as IsCol2Same
from table t
group by col1;
Then comes the issue of NULL values. If you want to ignore them (so a column could actually have two values, NULL and another value), then the above is fine (as is count(distinct)). If you want to treat NULL the same way as other values, then you need some additional tests:
select col1,
(case when min(col2) is null then 'true' -- All NULL
when count(col2) <> count(*) then 'false' -- Some NULL
when min(col2) = max(col2) then 'true' -- No NULLs and values the same
else 'false'
end) as IsCol2Same
from table t
group by col1;
Select distinct(t1.col1), case when t1.col2=t2.col2 then TRUE else FALSE end
from table t1, table t2 where t1.col1=t2.col2