How to flatten a SQL statement

Viewed 40

I have a case statement

Select customer, group, case when group = one then 'A' else 'B' end as Indicator FROM TABLE1

How do I "flatten" the indicator so for each customer I have 2 column for each indicator type (Goal Table)

Current Table:

Customer Group Indicator
Joh One A
Joh Two B
Jane One A
Jane Two B

Goal Table:

Customer Indicator1 Indicator2
Joh A B
Jane A B
2 Answers

Since values are being hard-coded ('A','B') for indicator column, we can use max, as it will yield one value only -

with data_cte(Customer,Group_1,Indicator) as(
select * from values
('Joh','One','A'),
('Joh','Two','B'),
('Jane','One','A'),
('Jane','Two','B')
)select d.customer
,max(case when d.group_1 = 'One' then 'A' end) as indicator1
,max(case when d.group_1 = 'Two' then 'B' end) as indicator2
from data_cte d
group by d.customer;

The form of Pankaj's answer is good if you have fixed group's, but his code has the indicator values hard coded, this it should look like:

with data_cte(Customer, Group_1, Indicator) as (
    select * 
    from values
        ('Joh','One','A'),
        ('Joh','Two','B'),
        ('Jane','One','A'),
        ('Jane','Two','B')
)
select 
    d.customer
    ,max(case when d.group_1 = 'One' then d.indicator end) as indicator1
    ,max(case when d.group_1 = 'Two' then d.indicator end) as indicator2
from data_cte as d
group by 1;

The CASE in the MAX can be swapped for a IFF in the form

MAX(IFF(d.group_1 = 'One` then d.indicator, null)) as indicator1

This works as MAX takes the larest value, so if you only have one matching group_1 per customer, the other will be null and those are not larger so the wanted value is taken.

If you have many, you will want to somehow rank then, and then FIRST_VALUE with a partition on customer, and ordered by something like a date..

anyways, if you have unkown/dynamic columns this can be solve using Snowflake Scripting to double query the data.

create or replace table table1 as 
  select column1 customer, column2 as _group, column3 as indicator
  from values
    ('Joh',1,'A'),
    ('Joh',2,'B'),
    ('Jane',1,'C'),
    ('Jane',3,'E'),
    ('Jane',2,'D');
declare
  sql string;
  res resultset;
  c1 cursor for select distinct _group as key from table1 order by key;
begin
  sql := 'select customer ';
  for record in c1 do
    sql := sql || ',max(iff(_group = '|| record.key ||', indicator, null)) as col_' || record.key::text;
  end for;
  sql := sql || ' from table1 group by 1  order by 1';
  
  res := (execute immediate :sql);
  return table (res);
end;

gives:

CUSTOMER COL_1 COL_2 COL_3
Jane C D E
Joh A B null
Related