Как изменить результат LISTAGG () в зависимости от количества агрегированных элементов в Oracle 11g +? - PullRequest
3 голосов
/ 07 января 2020

Как напечатать различный вывод в LISTAGG () в зависимости от количества агрегированных элементов?

Можно ли получить количество агрегированных элементов без дополнительного запроса COUNT (*)?

Есть пример DDL:

create table shepherds (
  SHEPHERD_ID NUMBER(19),
  SHEPHERD_NAME VARCHAR2(50 CHAR)
);

create table sheeps (
  SHEEP_ID VARCHAR2(10 CHAR),
  SHEEP_NAME VARCHAR2(50 CHAR),
  SHEEP_SHEPHERD_ID NUMBER(19)
);

-- insert shepherds
insert into shepherds VALUES (111, 'Asher');
insert into shepherds VALUES (222, 'Joseph');
insert into shepherds VALUES (333, 'Nicodemus');

-- first shepherd (one sheep)
insert into sheeps VALUES ('A', 'Mark', 111); 

-- second shepherd (two sheeps)
insert into sheeps VALUES ('A', 'Andres', 222);
insert into sheeps VALUES ('B', 'Jeffrey', 222);

-- third shepherd (three sheeps)
insert into sheeps VALUES ('B', 'Jeffrey', 333);
insert into sheeps VALUES ('A', 'Andres', 333);
insert into sheeps VALUES ('D', 'Andres', 333);

Теперь я хочу отобразить всех пастухов с разделенными новой строкой именами овец следующим образом:

SELECT
  SHEPHERD_NAME,
  (SELECT
     listagg(SHEEP_ID || ': ' || SHEEP_NAME, CHR(10)) WITHIN GROUP (ORDER BY SHEEP_ID)
   FROM SHEEPS
   WHERE SHEEP_SHEPHERD_ID = SHEPHERD_ID)
FROM SHEPHERDS;

Результат: http://sqlfiddle.com/#! 4 / 881a7 / 3

Однако я хочу скрыть овечье удостоверение личности для тех пастухов, у которых есть только одна овца.

Я попробовал следующее:

SELECT
  SHEPHERD_NAME,
  (SELECT
     listagg(
       CASE WHEN COUNT(*) > 1 THEN SHEEP_ID || ': ' ELSE '' END
       || SHEEP_NAME, CHR(10)) WITHIN GROUP (ORDER BY SHEEP_ID)
   FROM SHEEPS
   WHERE SHEEP_SHEPHERD_ID = SHEPHERD_ID)
FROM SHEPHERDS;

Однако я получаю сообщение об ошибке:

ORA-00978: функция вложенной группы без GROUP BY

http://sqlfiddle.com/#! 4 / 881a7 / 7

Можно ли вернуть другую строку из LISTAGG (), если агрегируется только один элемент?

Как определить количество агрегированных элементов без снижения производительности запросов в Oracle 11 г или выше?

Ответы [ 2 ]

2 голосов
/ 07 января 2020

Решение без подзапроса использует простой GROUP BY, COUNT(*) = 1 для различения количества овец и два разных LISTAGG оператора

SELECT
  s.SHEPHERD_NAME,
  case when count(*) = 1 then 
   listagg(SHEEP_NAME, CHR(10)) WITHIN GROUP (ORDER BY SHEEP_ID)  
  else 
   listagg(SHEEP_ID || ': ' || SHEEP_NAME, CHR(10)) WITHIN GROUP (ORDER BY SHEEP_ID) end as SHEEPS
FROM SHEPHERDS s
JOIN SHEEPS sh on s.SHEPHERD_ID = sh.SHEEP_SHEPHERD_ID
GROUP BY s.SHEPHERD_NAME /* add SHEPHERD_ID in GROUP BY if the name is not unique */

возвращает

SHEPHERD_NAME, SHEEPS
Asher          Mark
Joseph         A: Andres
               B: Jeffrey
Nicodemus      A: Andres
               B: Jeffrey
               D: Andres 
2 голосов
/ 07 января 2020

Условное выражение в подзапросе должно делать то, что вы хотите:

SELECT sh.SHEPHERD_NAME, 
        (SELECT (CASE WHEN COUNT(*) = 1 THEN MAX(s.SHEEP_NAME)
                      ELSE LISTAGG(s.SHEEP_ID || ': ' || s.SHEEP_NAME, CHR(10)) WITHIN GROUP (ORDER BY s.SHEEP_ID)
                 END) as SHEEPS
         FROM SHEEPS s
         WHERE s.SHEEP_SHEPHERD_ID = sh.SHEPHERD_ID
       ) as SHEEPS
FROM SHEPHERDS sh;

Здесь - это db <> скрипка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...