SELECT returning multiple rows as string

点点圈 提交于 2019-12-12 00:39:11

问题


I have a table:

Contracts:

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

-- and --

Devices:

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

devices.fk_contractid = contracts.contractid

I need to make select which will give result:

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

How can that be done in PL-SQL?


回答1:


Assuming 11g (when listagg was introduced):

  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



回答2:


If you have 10g instead of 11g, there's a hidden function that's similar to 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 does not let you sort.

You can also create your own function like this:

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;

You should add code to handle the 4,000 character limit.

Your query would now be

SELECT contract_name
     , concat_serialnum(contractid)
  from Contracts;



回答3:


Do something like this:

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

Add in the columns you need - using the double bar (I seem to recall) to concatenate strings.

You'll need to experiment to see how to get a quote mark - either supply it in single quotes, or in double quotes with the quote mark escaped in some way.




回答4:


If you're not using 11g and can't use @John Doyle's solution, then you can create your own aggregate function.

If you're not afraid of performance issues then you can try to use xmlagg as an aggregate function and then format it, ie:

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

(didn't check it)



来源:https://stackoverflow.com/questions/9359033/select-returning-multiple-rows-as-string

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!