Как создать представление в Oracle со столбцом String, содержимое которого агрегируется из числовых значений c связанных объектов? - PullRequest
0 голосов
/ 15 апреля 2020

В приложении Java на основе базы данных Oracle SQL мне нужно решить следующую проблему:

Сущность DataDelivery может состоять из любого числа Packet. Packet имеет ReportDate, а внешний ключ datadeliveryid.

ReportDate имеет тип данных NUMBER (4,0) и содержит год (YYYY), например, 2020 или 2018. столбец ReportDate находится в таблице ПАКЕТ.

На мой взгляд, я хочу отобразить DataDelivery в виде строк таблицы, включая столбец, который отображает объединенную дату отчета (ГГГГ) всех соответствующих пакетов. Объединенная дата отчета пакетов должна представлять собой список, разделенный запятыми.

Важно: Когда год, такой как «2018», встречается несколько раз, он не должен повторяться.

Таким образом, DataDelivery с 3 пакетами выглядит следующим образом:

DataDelivery
    PACKET1, ReportDate:2020
    PACKET2, ReportDate:2020
    PACKET3, ReportDate:2018
    PACKET4, ReportDate: `null`

shall be displayed as:    2018, 2020

Это означает, что null необходимо игнорировать, 2020 не следует повторять. И значения должны быть отсортированы в порядке возрастания.

Если все пакеты имеют нулевое значение как ReportDate, значение в представлении должно быть пустым.


Для простоты я пропустил некоторые сложности моей проблемы, включая несколько объединений и т. Д. c. Кроме того, даты могут быть только 2018, 2020 или null, хотя было бы лучше снять это ограничение. Возможно, кто-то может предложить решение, основанное на том, что я попробовал здесь:

            CASE
                WHEN COUNT(CASE eqpaket.berichtszeitraum WHEN 2020 THEN 2020 END) = COUNT(*) THEN '2020'
                WHEN COUNT(CASE eqpaket.berichtszeitraum WHEN 2018 THEN 2018 END) = COUNT(*) THEN '2018'
                WHEN COUNT(distinct eqpaket.berichtszeitraum) > 1 THEN
                    listagg(eqpaket.berichtszeitraum, ',') within group(order by datenlieferungid)
                ELSE ''
            END AS berichtszeitraum,

Это прекрасно работает, когда все ReportDates одинаковы. Когда они отличаются, я получаю дубликаты. В приведенном выше примере я бы получил: 2018, 2020, 2020. Эти дубликаты должны быть удалены, и это должно произойти в рамках CASE - END, если я придерживаюсь этого подхода.

Ответы [ 2 ]

0 голосов
/ 16 апреля 2020

Сделайте это в два шага (поскольку ваша версия базы данных не поддерживает listagg с distinct):

SQL> with datedelivery (datedeliveryid, packet, reportdate) as
  2    -- sample data
  3    (select 1, 'packet1', 2020 from dual union all
  4     select 1, 'packet2', 2020 from dual union all
  5     select 1, 'packet3', 2018 from dual union all
  6     select 1, 'packet4', null from dual union all
  7     --
  8     select 2, 'packet5', 2017 from dual union all
  9     select 2, 'packet6', 2017 from dual union all
 10     select 2, 'packet7', null from dual
 11    )
 12  -- query you need
 13  select datedeliveryid,
 14         listagg(reportdate, ', ') within group (order by reportdate) years
 15  from (-- first find DISTINCT values, then aggregate them
 16        select distinct datedeliveryid, reportdate
 17        from datedelivery
 18       )
 19  group by datedeliveryid;

DATEDELIVERYID YEARS
-------------- --------------------
             1 2018, 2020
             2 2017

SQL>
0 голосов
/ 15 апреля 2020

для Oracle 11g и выше вы можете использовать listagg

select listagg(distinct ReportDate, ',') within group (order by ReportDate)
from DataDelivery
...