【问题标题】:How can multiple rows be concatenated into one in Oracle without creating a stored procedure? [duplicate]在不创建存储过程的情况下,如何在 Oracle 中将多行连接成一行? [复制]
【发布时间】: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

【问题讨论】:

    标签: sql oracle concatenation string-aggregation


    【解决方案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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-01-02
      • 1970-01-01
      • 1970-01-01
      • 2016-09-28
      • 2017-02-07
      • 2011-04-25
      • 1970-01-01
      相关资源
      最近更新 更多