sqlsql-serverazure-synapsestring-aggregationconditional-aggregation

Concatenate multiple strings ordered (PIVOT)


I'm trying to concatenate the names of multiple Employees (ordered) based on their hierarchical level, which ranges between 0 and 4, without duplicates. The issue itself is fairly easy to solve (although I used Group By when a PIVOT would most likely be ideal), however, when I try to use STRING_AGG with ordering statements, Synapse Analytics says I cannot order by all of these, I get the error:

Multiple ordered aggregate functions in the same scope have mutually incompatible orderings.

For instance, consider the following data:

Department  | Employee Name  | Level
----------------------------------------
     A        |     John          |   0
     A        |    Andrew         |   0
     A        |   McKenzee        |   1
     A        |    Alissa         |   2
     B        |   Catherine       |   0
     B        |      Jack         |   1
     B        |      Jack         |   1
     B        |      Luanne       |   1
     B        |      Abigail      |   2

The expected output would be:

Department    |     Level 0           | Level 1           | Level 2
--------------------------------------------------------------------
     A        |     Andrew, John      |   McKenzee        | Alissa
     B        |     Catherine         |   Jack, Luanne    | Abigail

However, doing so results in the error above:

select
    ...
from
(
select
    department
    ,STRING_AGG(level_0, ',') WITHIN GROUP (ORDER BY level_0) level_0
    ,STRING_AGG(level_1, ',') WITHIN GROUP (ORDER BY level_1) level_1
    ,STRING_AGG(level_2, ',') WITHIN GROUP (ORDER BY level_2) level_2
    ,STRING_AGG(level_3, ',') WITHIN GROUP (ORDER BY level_3) level_3
  from
  (
    select
      department
      ,case 
        when employee_level = 0 then employee_name
      end level_0
      ,case 
        when employee_level = 1 then employee_name
      end level_1
      ,case 
        when employee_level = 2 then employee_name
      end level_2
      ,case 
        when employee_level = 3 then employee_name
      end level_3
      ,case 
        when employee_level = 4 then employee_name
      end level_4
    from
      employee_records
    group by
         department
  ) base_
  group by
    department
) le_subquery

Note: Since this is actually a subquery within a higher query I cannot use the Order By statement.


Solution

  • You can just use conditional aggregation in a STRING_AGG

    SELECT
      Department,
      STRING_AGG(CASE WHEN Level = 0 THEN Employee END, ',') WITHIN GROUP (ORDER BY Employee) level_0,
      STRING_AGG(CASE WHEN Level = 1 THEN Employee END, ',') WITHIN GROUP (ORDER BY Employee) level_1,
      STRING_AGG(CASE WHEN Level = 2 THEN Employee END, ',') WITHIN GROUP (ORDER BY Employee) level_2,
      STRING_AGG(CASE WHEN Level = 3 THEN Employee END, ',') WITHIN GROUP (ORDER BY Employee) level_3
    FROM @tbl
    GROUP BY Department;
    

    db<>fiddle