2

I have following table in Postgres

| phone | group   | spec   |
| 1     | 1       | 'Lock' |
| 1     | 2       | 'Full' |
| 1     | 3       | 'Face' | 
| 2     | 1       | 'Lock' | 
| 2     | 3       | 'Face' | 
| 3     | 2       | 'Scan' | 

Tried this

SELECT phone, string_agg(spec, ', ')
FROM mytable
GROUP BY phone;

Need this ouput for each phone where there is empty string for missing group.

| phone | spec 
| 1     | Lock, Full, Face
| 2     | Lock, '' , Face
| 3     | '', Scan ,''
2
  • 1
    Why 3 members in the list for 4 distinct values? Commented Aug 10, 2019 at 18:21
  • because there are three distinct groups, phone 2 doesn't have group '2' value and phone 3 doesn't have groups '1' and '3' Commented Aug 10, 2019 at 18:59

3 Answers 3

1

You need a CTE which returns all possible combinations of phone and group and a left join to the table so you can group by phone:

with cte as (
  select * 
  from (
    select distinct phone from mytable   
  ) m cross join (
    select distinct "group" from mytable  
  ) g 
)  
select c.phone, string_agg(coalesce(t.spec, ''''''), ',') spec
from cte c left join mytable t
on t.phone = c.phone and t."group" = c."group"
group by c.phone

See the demo.
Results:

| phone | spec           |
| ----- | -------------- |
| 1     | Lock,Full,Face |
| 2     | Lock,'',Face   |
| 3     | '',Scan,''     |
Sign up to request clarification or add additional context in comments.

Comments

0

You can use conditional aggregation:

select phone,
       (max(case when group = 1 then spec else '''''' end) || ', ' ||
        max(case when group = 2 then spec else '''''' end) || ', ' ||
        max(case when group = 3 then spec else '''''' end) 
       ) as specs
from mytable t
group by phone;

Alternatively, you can general all the groups using generate_series() and then aggregation:

select p.phone,
       string_agg(coalesce(t.spec, ''''''), ', ') as specs
from (select distinct phone from mytable) p cross join
     generate_series(1, 3, 1) gs(grp) left join
     mytable t
     on t.phone = p.phone and t.group = gs.grp
group by p.phone

Comments

0

You can consider using a self - (RIGHT/LEFT)JOIN with all three distinct groups (which's stated within the subquery just after RIGHT JOIN keywords ) and a correlated query for your table :

WITH mytable1 AS
(
SELECT distinct t1.phone, t2."group", 
      ( SELECT spec FROM mytable WHERE phone = t1.phone AND "group"=t2."group" )
  FROM mytable t1
  RIGHT JOIN ( SELECT distinct "group" FROM mytable ) t2
    ON t2."group" = coalesce(t2."group",t1."group")
)
SELECT phone, string_agg(coalesce(spec,''''''), ', ') as spec
  FROM mytable1
 GROUP BY phone;

Demo

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.