Order by statement - two columns - sql

I have a SQL select query from table x. In this query, I get BpName from table x and BpName2 from scalar function. I want to order by BpName2 if BpName is null and by BpName if is not null. Is it possible?
Example:
These are my rows:
Id BpName BpName2
------------------------
1 NULL 'C'
2 'A' NULL
3 NULL 'B'
I want to order them like this:
Id BpName BpName2
------------------------
2 'A' NULL
3 NULL 'B'
1 NULL 'C'

You could order by the coalesced result of the columns:
SELECT *
FROM mytable
ORDER BY COALESCE(BpName, BpName2)

Related

How can I partially transpose a table?

I have a table like this:
id
source
score
1
a
10
1
b
15
2
a
20
2
c
25
In this table, id and source make up a unique key. source can be one of 'a', 'b' or 'c'.
I want to transform it into this:
id
score_a
score_b
score_c
1
10
15
0
2
20
0
25
I don't mind if the 0s are nulls instead, if that would make it easier.
The target table should be the result of the following steps:
for every row in the table:
if source = 'a', add or update a row with id and score_a = score
if source = 'b', add or update a row with id and score_b = score
if source = 'c', add or update a row with id and score_c = score
I tried the following statement:
select id, score as score_a, null as score_b, null as score_c from tbl where source = 'a'
union all
select id, null as score_a, score as score_b, null as score_c from tbl where source = 'b'
union all
select id, null as score_a, null as score_b, score as score_c from tbl where source = 'c'
But it gave me this result instead:
id
score_a
score_b
score_c
1
10
null
null
2
20
null
null
1
null
15
null
2
null
null
25
How can I get a table like the one I want (with distinct id)?
You just need to use CASE to implement your logic and then flatten the result with some aggregation (I used MAX())
SELECT id,
MAX(CASE WHEN source='a' THEN score END) as score_a,
MAX(CASE WHEN source='b' THEN score END) as score_b,
MAX(CASE WHEN source='c' THEN score END) as score_c
FROM Tbl
GROUP BY id
DEMO
You indicated that null was OK, but if you have to have zeroes instead add COALESCE()

Keep multiple rows during PIVOT in Snowflake

I would like to transpose rows into columns in Snowflake.
Suppose I have the following table BASE
ID
value
type
1
100
'A'
1
200
'B'
1
300
'B'
2
400
'A'
The output should be as follows:
ID
A
B
1
100
200
1
100
300
2
400
NULL
Currently I am pivoting the table with
SELECT ID,
CASE WHEN TYPE = 'A' THEN VALUE ELSE NULL AS A,
CASE WHEN TYPE = 'B' THEN VALUE ELSE NULL AS B
FROM BASE
For now the GROUP BY statement is missing. Typically I would GROUP BY ID, but that does not account for keeping one row per each value on the same TYPE and ID.
Any ideas how to achieve this?
Cheers,
P
You can use conditional aggregation. You can use row_number() to get multiple rows:
SELECT ID,
MAX(CASE WHEN TYPE = 'A' THEN VALUE END) AS A,
MAX(CASE WHEN TYPE = 'B' THEN VALUE END) AS B
FROM (SELECT B.*,
ROW_NUMBER() OVER (PARTITION BY ID, TYPE ORDER BY VALUE) as seqnum
FROM BASE B
) B
GROUP BY ID, seqnum;
This would work, too:
select *
from base_table
pivot(sum(value) for type in ('A','B')) as p
order by id;

How would I transpose SQL: Sum Case Script in Redshift and is it possible to Join to information table?

I currently have a script that counts the number of null records in each column. The script is below
select sum(case when id is null then 1 else 0 end)id , sum(case when createddate is null then 1 else 0 end)createddate from schema_name.Table_name
The results come over like
|id|createddate|
|0 | 5 |
Is there a way to transpose this to get the results like
|id | 0 |
|created date| 5|
Lastly, if this is possible would I be able to join this to the information table (SVV_TABLE_INFO)
You can use union all:
select 'id', count(*)
from t
where id is null
union all
select 'createddate', count(*)
from t
where createddate is null;
You would use union all:
select 'id' as what, count(*) as cnt from table_name where id is null
union all
select 'createddate', count(*) from table_name where createddate is null
If you have a situation where both columns are never both null on the same row, you can use aggregation:
select case when id is null then 'id' else 'createddate' end as what, count(*)
from mytable t
where id is null or createddate is null
group by case when id is null then 'id' else 'createddate' end

Select rows where all values within group are NULL

How to:
Select rows where all rows within group are NULL. Below group is defined by id. I
wish to select rows where all values are NULL.
Id Var1
1 NULL
1 NULL
1 NULL
2 10
2 20
2 30
3 NULL
3 30
What I have tried:
select id
from table
where all var1 is null
group by id
Desired result:
id var1
1 NULL
1 NULL
1 NULL
Use having instead of where. It filters after aggregation:
select id
from table
group by id
having max(var1) is null;
A similar method uses:
having count(var1) = 0
You can try with this query:
select id,Var1
from table1 as a
where not exists (select id
from table1 as b
where a.id=b.id and b.Var1 is not null)
The subquery get the id that have values not null, so you don get them in the main query

Oracle SQL - Keep null value if it's the only one, else avoid null value

I have this table :
Table1
-----------------
ID VAL
-----------------
1 A
1 B
1 null
2 null
3 B
3 null
4 B
4 C
5 null
I want to get this result :
If the only value is null then return null, else return non null
values
Table1
-----------------
ID VAL
-----------------
1 A
1 B
2 null
3 B
4 B
4 C
5 null
I tried using Over Partition By with a Case but my statement became too complicated with several subqueries, if think there should be a simple way to do this.
The COUNT( value ) OVER ( PARTITION BY id ) analytic function will count the rows where value is not-NULL for each id. You can use it to filter the rows like this:
SELECT id, value
FROM (
SELECT t.*,
COUNT( value ) OVER ( PARTITION BY id ) AS num_values
FROM yourtable t
)
WHERE value IS NOT NULL
OR num_values = 0;
If the only value is null then return null, else return non null values
If you want to ensure that NULL is only returned if there is exactly one row for the id then:
SELECT id, value
FROM (
SELECT t.*,
COUNT( * ) OVER ( PARTITION BY id ) AS num_rows
FROM yourtable t
)
WHERE value IS NOT NULL
OR num_rows = 1;
Try this:
SELECT *
FROM yourtable t1
WHERE val IS NOT NULL OR
NOT EXISTS (SELECT 'VALUED'
FROM yourtable t2
WHERE t2.id = t1.id
AND t2.val IS NOT NULL)