Проблема с группой с агрегацией списка - PullRequest
0 голосов
/ 05 сентября 2018

В запросе с listagg() я пытаюсь добавить предложение для split_rep: существование user_id с profile_type='Split' и для multi_rep: существование user_id с более чем одним ap.id.

Упрощенный запрос (где - это то, что я пытаюсь сделать):

select distinct r.user_id,
listagg(distinct ap.rep_code, ', ') within group (order by ap.bill_rate) as rep_code_list
--,case when max(ap.profile_type) over (partition by r.user_id)='Split' then 1 else 0 end has_split_rep_code
--,case when count(ap.id) over (partition by r.user_id)>1 then 1 else 0 end has_multi_rep_code 
from representatives r
join profiles ap on r.user_id=ap.user_id
group by r.user_id

Это выдает ошибку, что profile_type и id должны быть в group by - однако, если добавлено, это даст неправильный вывод. Не уверен, почему оконная функция не поддерживается с listagg, но есть идеи, как это обойти?

Пример данных:

user_id   id   profile_type   rep_code
A         A    Self           AAA
A         B    Self           AAB
B         C    Self           AAC
C         D    Self           AAD
C         E    Split          AAE
D         F    Split          AAF

Желаемый вывод:

user_id   rep_code    split_rep_code   multi_rep_code
A         AAA, AAB    0                1
B         AAC         0                0
C         AAD, AAE    1                1
D         AAF         1                0

Ответы [ 2 ]

0 голосов
/ 05 сентября 2018

Я думаю, что вы путаете цель select distinct, когда используете его с group by. Каждый из них может делать похожие вещи в зависимости от контекста. Я использую выражение CASE ниже для вычисления столбца split_rep_code, и я также добавил логику для столбца multi_rep_code.

select
    r.user_id,
    listagg(ap.rep_code, ', ') within group (order by ap.bill_rate) as rep_code_list,
    case when sum(case when ap.profile_type = 'Split' then 1 else 0 end) > 0
         then 1 else 0 end as split_rep_code,
    case when min(ap.id) <> max(ap.id) then 1 else 0 end as multi_rep_code
from representatives r
inner join profiles ap
    on r.user_id = ap.user_id
group by
    r.user_id;

enter image description here

Демо

Обратите внимание, что демонстрационная версия находится в Postgres, и я использовал string_agg вместо list_agg Redshift, но принцип тот же. Также обратите внимание, что Redshift не поддерживает использование DISTINCT внутри list_agg. Если вам действительно нужно такое поведение, возможно, вам придется сначала выполнить подзапрос, чтобы удалить дубликаты.

0 голосов
/ 05 сентября 2018

Вы можете использовать OVER:

select distinct r.user_id,
  listagg(distinct ap.rep_code, ', ') within group (order by ap.bill_rate)
   over(partition by ap.user_id) as rep_code_list
  -- rest of cols
from representatives r
join profiles ap on r.user_id=ap.user_id;
...