Получение самой ранней даты путем сопоставления двух столбцов и возврата массива - PullRequest
0 голосов
/ 24 апреля 2019

У меня есть запрос, который я пытаюсь написать, но я не могу получить правильный синтаксис. Из таблицы ниже у меня есть набор дат с id, и если id не имеет parent_id, а если parent_id не существует для id, то это NULL.

Я пытаюсь получить выходные данные всех потомков родителя, которые имеют ту же дату, что и родитель. Как показано в ожидаемом результате ниже, [D#P, Z#Z] будет присвоено A, потому что они имеют одинаковый date, а их parent_id равно A, однако Q#L не будет назначено A, поскольку его дата не 1/1/2019. Ничто не назначено на B или D, потому что у них нет детей на даты их создания.

Я нашел несколько сообщений о том, как это сделать в Postgres, однако, поскольку я использую Redshift, некоторые операции не работают.

Буду признателен за любую помощь.

|date   |id  |parent_id |
-------------------------
1/1/2019|A   |NULL
1/1/2019|B   |NULL
1/1/2019|C   |NULL
1/1/2019|D#P |A
1/1/2019|Z#Z |A
1/1/2019|K#H |C
1/2/2019|Q#L |A
1/3/2019|D   |NULL
1/4/2019|H#Q |C

Ожидаемый результат:

date     |id |children
-----------------------
1/1/2019 |A  |[D#P, Z#Z]
1/1/2019 |C  |[K#H]

Текущая работа:

SELECT
    first_value(case
            when parent_id
            then date
            end)
        over (
            partition by parent_id
            order by date
            rows between unbounded preceding and unbounded following)
        as first_date)
        id,
        list_agg(parent_id)
    FROM foo

1 Ответ

2 голосов
/ 25 апреля 2019

Я не знаю, почему я получаю ошибку при использовании LISTAGG агрегатной функции , поэтому я решил использовать SELECT DISTINCT с LISTAGG оконной функцией :

WITH input as (
  SELECT '1/1/2019' as date, 'A' as id, NULL as parent_id UNION ALL
  SELECT '1/1/2019', 'B', NULL                            UNION ALL
  SELECT '1/1/2019', 'C', NULL                            UNION ALL
  SELECT '1/1/2019', 'D#P', 'A'                           UNION ALL
  SELECT '1/1/2019', 'Z#Z', 'A'                           UNION ALL
  SELECT '1/1/2019', 'K#H', 'C'                           UNION ALL
  SELECT '1/2/2019', 'Q#L', 'A'                           UNION ALL
  SELECT '1/3/2019', 'D', NULL                            UNION ALL
  SELECT '1/4/2019', 'H#Q', 'C'
), parents as (
  SELECT *
  FROM input
  WHERE parent_id IS NULL
), children as (
  SELECT *
  FROM input
  WHERE parent_id IS NOT NULL
)

SELECT DISTINCT
  parents.date,
  parents.id,
  listagg(children.id, ',') WITHIN GROUP ( ORDER BY children.id )OVER (PARTITION BY parents.id, parents.date) as children
FROM parents JOIN children
                  ON parents.id = children.parent_id
                       AND parents.date = children.date

Выходы:

date        id  children
1/1/2019    A   D#P,Z#Z
1/1/2019    C   K#H

Решение с GROUP BY и LISTAGG агрегатной функцией , было бы для меня более естественным решения вашей проблемы:

WITH input as (
[...] 
SELECT 
  parents.date,
  parents.id,
  listagg(children.id, ',') WITHIN GROUP ( ORDER BY children.id )
FROM parents JOIN children
                  ON parents.id = children.parent_id
                       AND parents.date = children.date
group by parents.id, parents.date

К сожалению, это возвращает ошибку, которую я на самом деле не понимаю:

[XX000] [500310] Amazon Недопустимая операция: одинили более используемых функций должны быть применены как минимум к одной созданной пользователем таблице.Примерами функций только для пользовательских таблиц являются LISTAGG, MEDIAN, PERCENTILE_CONT и т. Д .;java.lang.RuntimeException: com.amazon.support.exceptions.ErrorException: Amazon Недопустимая операция: одна или несколько используемых функций должны быть применены как минимум к одной созданной пользователем таблице.Примерами функций только для пользовательских таблиц являются LISTAGG, MEDIAN, PERCENTILE_CONT и т. Д .;

...