Как агрегировать столбцы, а также строки?

#sql #oracle #oracle11g #aggregate-functions

#sql #Oracle #оракул11g #агрегатные функции

Вопрос:

listagg работает, как и ожидалось poll_id=2 .

Как я могу выполнить то же самое для одной строки и нескольких столбцов?

 with list_of_fruits as
(select  1 as poll_id ,'Apple' as first_choice, 'Pear' as second_choice, 'Peach' as third_choice, 'Plum' as fourth_choice from dual union all
select  2 as poll_id ,'Cherry' as first_choice, null as second_choice, null as third_choice, null as fourth_choice from dual union all
select  2 as poll_id ,'Grape' as first_choice, null as second_choice, null as third_choice, null as fourth_choice from dual union all
select  2 as poll_id ,'Kiwi' as first_choice, null as second_choice, null as third_choice, null as fourth_choice from dual union all
select  3 as poll_id ,'Squash' as first_choice, 'Peas' as second_choice, '' as third_choice, null as fourth_choice from dual union all
select  3 as poll_id ,null as first_choice, null as second_choice, null as third_choice, 'Barley' as fourth_choice from dual union all
select  3 as poll_id ,null as first_choice, null as second_choice, 'Oats' as third_choice, null as fourth_choice from dual

)    select poll_id, listagg(first_choice,';') within group (order by poll_id) as sam
    from list_of_fruits
    group by poll_id
 

Желаемый результат

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

 1 Apple;Pear;Peach;Plum
2 Cherry;Grape;Kiwi
3 Squash;Peas;Barley;Oats
 

Комментарии:

1. В вашем примере, например poll_id = 2 , все три фрукта — » first_choice «. В каком порядке они должны отображаться в выходных данных? (Имеет ли это значение? Например, они могут отображаться в алфавитном порядке.) В противном случае, я предполагаю, что для любого данного poll_id фрукта first_choice сначала должны появиться фрукты, указанные в, затем те, что указаны в second_choice и т. Д.?

2. Да, порядок действительно имеет значение. Для каждого идентификатора выберите 1-й, 2-й, 3-й, 4-й вариант. Затем 2-й ряд, затем третий ряд и т.д..

3. @zundarz Я обновил свой ответ ниже.

4. Ваши данные не нормализованы, и хотя решение @mathguy может дать вам желаемый результат, лучшим подходом было бы изменить дизайн вашей базы данных, чтобы избежать хранения данных в формате CSV.

5. Что вы подразумеваете под «первым рядом», «вторым рядом» и т.д.? Строки в таблице не упорядочены. У вас есть еще один столбец, чтобы упорядочить строки по этому столбцу? Или вы имеете в виду «произвольный» порядок строк, но фрукты следует считывать из каждой строки, а затем переходить к другой строке?

Ответ №1:

 with
     list_of_fruits 
            ( poll_id, first_choice, second_choice, third_choice, fourth_choice ) as (
       select  1,'Apple' , 'Pear', 'Peach', 'Plum'   from dual union all
       select  2,'Cherry', ''    , ''     , ''       from dual union all
       select  2,'Grape' , ''    , 'Berry', ''       from dual union all
       select  2,'Kiwi'  , ''    , ''     , ''       from dual union all
       select  3,'Squash', 'Peas', ''     , ''       from dual union all
       select  3,''      , ''    , ''     , 'Barley' from dual union all
       select  3,''      , ''    , 'Oats' , ''       from dual
     ),
     prep ( poll_id, first_choice, second_choice, third_choice, fourth_choice, rn ) as (
       select poll_id, first_choice, second_choice, third_choice, fourth_choice,
              row_number() over (partition by poll_id order by null)
       from list_of_fruits
     )
select poll_id, listagg(fruit, ',') within group (order by rn, choice) as sam
from prep
unpivot ( fruit for choice in (first_choice as 1, second_choice as 2, 
                                             third_choice as 3, fourth_choice as 4))
group by poll_id
order by poll_id  -- ORDER BY is optional
;


   POLL_ID SAM
---------- ------------------------------
         1 Apple,Pear,Peach,Plum
         2 Grape,Berry,Cherry,Kiwi
         3 Squash,Peas,Barley,Oats
 

Комментарии:

1. Обратите order by null внимание на in row_number() в определении rn in prep . Это означает, что строки для данного poll_id будут в произвольном порядке, но они будут в некотором порядке. Если они должны быть в более определенном порядке, это можно настроить в order by предложении in row_number . Кроме того, я изменил CTE, чтобы имена столбцов указывались сразу после имени CTE. Это работает только в Oracle 11.2 и выше; для версии 11.1 вы можете переместить имена столбцов обратно в определение CTE (как они были у вас изначально) и сделать то же самое для prep .

2. Я также добавил 'Berry' в качестве third_choice в одну из строк для poll_id = 2 , чтобы проверить, правильно ли работает решение.