在不创建存储过程的情况下,如何在 Oracle 中将多行连接成一行? [复制]

Posted

技术标签:

【中文标题】在不创建存储过程的情况下,如何在 Oracle 中将多行连接成一行? [复制]【英文标题】:How can multiple rows be concatenated into one in Oracle without creating a stored procedure? [duplicate] 【发布时间】:2010-11-07 17:47:44 【问题描述】:

如何在不创建存储过程的情况下在 oracle 中实现以下功能?

数据集:

question_id    element_id
1              7
1              8
2              9
3              10
3              11
3              12

期望的结果:

question_id    element_id
1              7,8
2              9
3              10,11,12

【问题讨论】:

【参考方案1】:

从 Oracle 11gR2 开始,LISTAGG 子句应该可以解决问题:

SELECT question_id,
       LISTAGG(element_id, ',') WITHIN GROUP (ORDER BY element_id)
FROM YOUR_TABLE
GROUP BY question_id;

如果结果字符串太大(例如 VARCHAR2 超过 4000 个字符)请注意:从版本 12cR2 开始,我们可以使用 ON OVERFLOW TRUNCATE/ERROR 来处理此问题。

【讨论】:

附带说明,我们可以通过查询表v$versionproduct_component_version 来了解数据库版本。 11.2 表示 11gR2。 无论如何它帮助了我 用了很久,就这么简单。 这是缺少GROUP BY question_id 吗?【参考方案2】:

警告 - WM_CONCAT 是一个不受支持的函数,已在版本 12c 中删除。除非您使用的是非常旧的数据库,否则应避免使用此函数。)


简单:

SELECT question_id, wm_concat(element_id) as elements
FROM   questions
GROUP BY question_id;

个人在 10g 上测试 ;-)

来自http://www.oracle-base.com/articles/10g/StringAggregationTechniques.php

【讨论】:

请注意 wm_concat 是一个未记录的函数。因此,在生产代码中使用它之前,您可能需要三思。 非常酷。也适用于我,但我需要确保此功能在我们的生产环境中可用。 我得到错误 --> ORA-00904 WM_CONCAT : Invalid Identifier ORA-06502: PL/SQL: numeric or value error: character string buffer too small 如果连接的值恰好超过 4000 字节的最大长度。 我曾经在 oracle 11g(Oracle Database 11g Enterprise Edition Release 11.1.0.7.0 - 64bit Production)中的大多数快速而肮脏的工作中使用 wmsys.wm_concat(...)【参考方案3】:

有很多方法可以进行字符串聚合,但最简单的是用户定义的函数。 Try this for a way that does not require a function. 注意,没有这个功能就没有简单的方法。

这是没有自定义函数的最短路径:(它使用 ROW_NUMBER() 和 SYS_CONNECT_BY_PATH 函数)

SELECT questionid,
       LTRIM(MAX(SYS_CONNECT_BY_PATH(elementid,','))
       KEEP (DENSE_RANK LAST ORDER BY curr),',') AS elements
FROM   (SELECT questionid,
               elementid,
               ROW_NUMBER() OVER (PARTITION BY questionid ORDER BY elementid) AS curr,
               ROW_NUMBER() OVER (PARTITION BY questionid ORDER BY elementid) -1 AS prev
        FROM   emp)
GROUP BY questionid
CONNECT BY prev = PRIOR curr AND questionid = PRIOR questionid
START WITH curr = 1;

【讨论】:

效果很好! ROW_NUMBER() 是我让 sys_connect_by_path 为我工作所缺少的。 请注意,当应用此技术连接其值可能包含分隔符的字段时,将引发以下错误:ORA-30004: when using SYS_CONNECT_BY_PATH function, cannot have separator as part of column value.... 如果连接的值恰好超过最大长度4000 字节,你会得到错误:ORA-01489: result of string concatenation is too long.【参考方案4】:

此 OTN 线程包含几种进行字符串聚合的方法,包括性能比较:http://forums.oracle.com/forums/message.jspa?messageID=1819487#1819487

【讨论】:

以上是关于在不创建存储过程的情况下,如何在 Oracle 中将多行连接成一行? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何在不知道查询结果类型的情况下在 EF/VB.net 中运行存储过程?

oracle如何列出特定存储过程中使用的所有表

如何在不复制数据的情况下创建 Oracle 表的副本?

如何在不使用存储过程的情况下在表函数中返回值 exec?

如何在不等待完成的情况下调用存储过程?

在不使用存储过程的情况下循环 n 次