SELECT возвращает несколько строк в виде строки - PullRequest
0 голосов
/ 20 февраля 2012

У меня есть таблица:

Контракты:

contractid | contract name
"1" | "MAG:001"
"2" | "MAG:002"

- и -

Устройства:

devid | serialnum | fk_contractid
10 | 1234 | 1
11 | 5678 | 1
12 | 4321 | 2
13 | 8765 | 2

devices.fk_contractid = contract.contractid

Мне нужно сделать выбор, который даст результат:

"MAG:001" | 1234, 5678
"MAG:002" | 4321, 8765

Как это сделать в PL-SQL?

Ответы [ 4 ]

4 голосов
/ 20 февраля 2012

Предполагая 11 г (когда было введено listagg):

  select    CONTRACT_NAME
         || '|'
         || LISTAGG(D.SERIALNUM, ',') within group (order by CONTRACTID)
    from CONTRACTS C join DEVICES D on D.FK_CONTRACTID = C.CONTRACTID
group by CONTRACT_NAME
3 голосов
/ 20 февраля 2012

Если у вас есть 10 г вместо 11 г, есть скрытая функция, похожая на LISTAGG.

WMSYS.WM_CONCAT

SELECT Contracts.contract_name
     , WMSYS.WM_CONCAT(Devices.serialnum)
  FROM Contracts, Devices
 WHERE Contracts.contractid = Devices.fk_contractid
 GROUP BY Contracts.contract_name;

WM_CONCAT не позволяет вам сортировать.

Вы также можете создать свою собственную функцию, например:

FUNCTION concat_serialnum(the_contract Contracts.contractid%TYPE)
 RETURN VARCHAR2
IS
  return_value VARCHAR2(4000);
  CURSOR serials_cur IS
    SELECT serialnum
      FROM Devices
      WHERE contractid = the_contract
      ORDER BY serialnum;
BEGIN
  FOR serials_rec IN serials_cur LOOP
    return_value := return_value || ', ' || serials_rec.serialnum;
  END LOOP;
  RETURN LTRIM(return_value, ', ');
END concat_serialnum;

Вы должны добавить код для обработки ограничения в 4000 символов.

Ваш запрос теперь будет

SELECT contract_name
     , concat_serialnum(contractid)
  from Contracts;
0 голосов
/ 20 февраля 2012

Если вы не используете 11g и не можете использовать решение @John Doyle, то вы можете создать собственную агрегатную функцию .

Если вы не боитесь проблем с производительностью, вы можете попробовать использовать xmlagg в качестве агрегатной функции, а затем отформатировать ее, например:

select contract_name,
       rtrim(xmlagg(xmlelement(e, serialnum || ',')).extract('//text()')) as serialnums
  from contracts, devices
 where contractId = fk_contractid
 group by contract_name

(не проверял)

0 голосов
/ 20 февраля 2012

Сделайте что-то вроде этого:

SELECT '"' || c.contract_name || '"'
...
FROM contracts c INNER JOIN devices d ON d.fk_contractid = c.contractid

Добавьте в нужные столбцы - используйте двойную черту (кажется, я помню) для объединения строк.

Вам нужно будет поэкспериментироватьчтобы увидеть, как получить знак кавычки - либо поставьте его в одинарных кавычках, либо в двойных кавычках с экранированным кавычкой каким-либо образом.

...