【问题标题】:Is there an Oracle SQL query that aggregates multiple rows into one row? [duplicate]是否有将多行聚合为一行的 Oracle SQL 查询? [复制]
【发布时间】:2010-11-10 09:06:48
【问题描述】:

我有一张如下所示的表格:

A 1 
A 2 
B 1 
B 2

我想生成一个如下所示的结果集:

A 1 2 
B 1 2

是否有可以执行此操作的 SQL 语句?我正在使用 Oracle。

相关问题:

【问题讨论】:

标签: sql oracle aggregation string-concatenation


【解决方案1】:

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


这取决于您使用的 Oracle 版本。如果它支持 wm_concat() 函数,那么你可以简单地做这样的事情:

SELECT field1, wm_concat(field2) FROM YourTable GROUP BY field2;

wm_concat() 基本上就像 MySQL 中的 group_concat() 一样工作。它可能没有记录,所以启动 ye olde sqlplus 看看它是否存在。

如果它在那里,那么你会想要自己实现一些等效的东西。您可以在 oracle-base.com 的 string aggregation page 中找到有关如何执行此操作的一些说明。

【讨论】:

  • 请注意 wmsys.wm_concat 未记录且不受支持。
【解决方案2】:

相当老的话题,但它可以帮助其他人,因为同时 Oracle 也在改进。

LISTAGG 函数正是您所需要的(至少在 11g 中)

【讨论】:

【解决方案3】:

如果你有10g,那么你必须通过下面的函数:

CREATE OR REPLACE FUNCTION get_separated_value (input_val  in  number)
  RETURN VARCHAR2
IS
  return_text  VARCHAR2(10000) := NULL;
BEGIN
  FOR x IN (SELECT col2 FROM table_name WHERE col1 = input_val) LOOP
    return_text := return_text || ' ' || x.col2 ;
  END LOOP;
  RETURN return_text;
END;
/

所以,你可以这样做:

select col1, get_separated_value(col1) from table_name

Fiddle here

如果你有oracle 11g,可以使用listagg

SELECT 
    age,
    LISTAGG(name, ' ') WITHIN GROUP (ORDER BY name) "names"
FROM table_x
GROUP BY age

Fiddle here for Listagg

【讨论】:

    【解决方案4】:
    SELECT a , COLLECT(b) FROM foo GROUP BY a
    

    在 pl/sql 中使用时非常有用 - 可以转换为用户定义的集合。

    【讨论】:

    • 当我在 11g 数据库上尝试它时,需要 CAST。但我给你 +1 是因为我不知道 COLLECT 函数的存在 - Oracle 添加了太多功能,无法跟上。
    【解决方案5】:

    尝试类似:

    SELECT
        field1,
        RTRIM(REPLACE(REPLACE(XMLAgg(XMLElement("x", field2) ORDER BY field2), '<x>'), '</x>', ' ')) AS field2s
      FROM yourTable
      GROUP BY field1
    

    受到found in this Oracle forum 的回答的启发。

    编辑:该解决方案证明非常资源密集,请求涉及 105 行。我最终用 suggested by John 的自定义聚合函数替换了它。

    【讨论】:

      【解决方案6】:

      Oracle 10g+:

      SELECT  *
      FROM    (
              SELECT  *
              FROM    mytable
              MODEL
              PARTITION BY
                      (grouper)
              DIMENSION BY
                      (ROW_NUMBER() OVER (PARTITION BY grouper ORDER BY id) AS rn)
              MEASURES
                      (val, val AS group_concat, 0 AS mark)
              RULES SEQUENTIAL ORDER (
                      group_concat[rn > 1] ORDER BY rn = group_concat[CV() - 1] || ', ' || val[CV()],
                      mark[ANY] ORDER BY rn = PRESENTV(mark[CV() + 1], 0, 1)
                      )
              )
      WHERE   mark = 1
      ORDER BY
              grouper
      

      请参阅我博客中的这篇文章以获得解释:

      【讨论】:

      • 你完全依赖于被 rn 排序的 mytable。如果未排序,您将获得“ORA-32637:按顺序模型的自循环规则”。所以这个变种是错误的。您可能想在我的博客上阅读另一个示范条款变体:rwijk.blogspot.com/2008/05/…
      • @Rob: rn 这里只是ROW_NUMBER() 的别名。我从我的文章中复制了它(它使用CTE 作为行源),但没有将它放入表中。感谢您的关注。
      • 是的,我知道。但是,例如,如果您使用了另一个具有不同 order by 的分析函数,并且最后执行了附带的 WINDOW SORT 操作,则会出现上述错误。所以你仍然必须使用有序规则评估来使这个想法生效。
      • @Rob:再次正确,更新,检查6 - ROW_NUMBER() OVER (PARTITION BY grouper ORDER BY rno) AS rn。谢谢。
      【解决方案7】:

      用户定义的聚合函数:http://www.adp-gmbh.ch/ora/sql/user_def_agg.html

      只需复制/粘贴并使用它。适用于 9i。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-05-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-09
        • 1970-01-01
        • 1970-01-01
        • 2020-03-10
        相关资源
        最近更新 更多