0

我有一张桌子:

合同:

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 =contracts.contractid

我需要做出选择,这将给出结果:

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

如何在 PL-SQL 中做到这一点?

4

4 回答 4

4

假设 11g(何时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
于 2012-02-20T10:15:45.360 回答
3

如果你有 10g 而不是 11g,则有一个类似于 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;

您应该添加代码来处理 4,000 个字符的限制。

您的查询现在是

SELECT contract_name
     , concat_serialnum(contractid)
  from Contracts;
于 2012-02-20T15:39:32.443 回答
0

如果您没有使用 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

(没检查)

于 2012-02-20T12:19:34.050 回答
0

做这样的事情:

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

添加您需要的列 - 使用双栏(我似乎记得)连接字符串。

您需要进行实验以了解如何获取引号 - 以单引号或双引号提供引号,引号以某种方式转义。

于 2012-02-20T09:52:53.073 回答