Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to string_agg an array in SQL?

Tags:

sql

postgresql

I want to aggregate rows using the string aggregate function, however one column is an array.

I have three columns: Employee, Year, Grades. The column Grade is an array. Example:

Row (1) : Employee: Tom | Year: 2019 | Grades: 11,33
Row (2) : Employee: Tom | Year: 2018 | Grades: 45,24,54

'Grade' column is an array. It represents grades for the different tests he took that year

select 
Employee, 
string_agg (distinct Year, ','),
string_agg (distinct Grades, ',')
from Employee_grades
group by 1

ERROR:

function string_agg(bigint[], unknown) does not exist Hint: No function matches the given name and argument types. You might need to add explicit type casts.

like image 832
Hamza Khalid Avatar asked Sep 13 '26 09:09

Hamza Khalid


2 Answers

You should use casting:

select Employee,
      string_agg(distinct Year::text, ','),
      string_agg(distinct Grades::text, ',') 
from Employee_grades 
group by Employee  -- GROUP BY 1 is a bad practice
like image 110
Lukasz Szozda Avatar answered Sep 16 '26 13:09

Lukasz Szozda


If you don't really care about removing duplicates, you can convert to a string using array_to_string():

select employee, array_agg(distinct year),
       string_agg(array_to_string(grades, ','), ',')
from (values ('Tom', 2019, array[11, 33]),
             ('Tom', 2018, array[10, 20, 30])
     ) v(employee, year, grades)
group by employee;

If you actually want to remove duplicates, this is a bit trickier. Unnesting and de-duping may be the only approach:

with t as (
      select *
      from (values ('Tom', 2019, array[11, 33]),
                   ('Tom', 2018, array[11, 20, 30])
           ) v(employee, year, grades)
     )
select t.*,
       (select array_agg(distinct grade)
        from t t2 cross join lateral
             unnest(grades) grade
        where t2.employee = t.employee
       ) as grades
from (select employee, array_agg(distinct year) as year
      from t
      group by t.employee
     ) t;

I prefer to leave the results as arrays, but the results can easily be converted to strings if you prefer.

like image 41
Gordon Linoff Avatar answered Sep 16 '26 13:09

Gordon Linoff



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!