Oracle:将一些计数旋转(合并)到单行?

Posted

技术标签:

【中文标题】Oracle:将一些计数旋转(合并)到单行?【英文标题】:Oracle: pivot (coalesce) some counts onto a single row? 【发布时间】:2010-01-30 22:33:02 【问题描述】:

更新:我之前调用的是 coalesce 我应该调用的是 pivot

我正在从日志表中提取一些日常使用计数。我可以轻松地为每个日期/项目获取一行数据,但我想将 coalesce 列转换为一行。

例如,我有:

date    item-to-be-counted count-of-item
10/1    foo                23
10/1    bar                45
10/2    foo                67
10/2    bar                89

我想要:

date    count-of-foo     count-of-bar
10/1    23               45
10/2    67               89

这是我当前的 10g 查询。

select    trunc(started,'HH'),depot,count(*)
  from    logstats
 group by trunc(started,'HH'),depot
 order by trunc(started,'HH'),depot;

TRUNC(STARTED,'HH')       DEPOT      COUNT(*)
------------------------- ---------- --------
10/01/11 01.00.00         foo        28092
10/01/11 01.00.00         bar        2194
10/01/11 02.00.00         foo        3402
10/01/11 02.00.00         bar        1058

更新:11g 有一个 pivot 操作。接受的答案显示了如何在 9i 和 10g 中执行此操作。

【问题讨论】:

【参考方案1】:

您正在寻找的是旋转 - 将行数据转换为柱状数据。

Oracle 9i+,使用 WITH/CTE:


用途:

WITH summary AS (
    SELECT TRUNC(ls.started,'HH') AS dt,
           ls.depot,
           COUNT(*) AS num_depot
      FROM logstats ls
  GROUP BY TRUNC(ls.started,'HH'), ls.depot)
  SELECT s.dt,
         MAX(CASE WHEN s.depot = 'foo' THEN s.num_depot ELSE 0 END) AS "count_of_foo",
         MAX(CASE WHEN s.depot = 'bar' THEN s.num_depot ELSE 0 END) AS "count_of_bar"
    FROM summary s
GROUP BY s.dt
ORDER BY s.dt

非 WITH/CTE 等效项


用途:

  SELECT s.dt,
         MAX(CASE WHEN s.depot = 'foo' THEN s.num_depot ELSE 0 END) AS "count_of_foo",
         MAX(CASE WHEN s.depot = 'bar' THEN s.num_depot ELSE 0 END) AS "count_of_bar"
    FROM (SELECT TRUNC(ls.started,'HH') AS dt,
                 ls.depot,
                 COUNT(*) AS num_depot
            FROM LOGSTATS ls
        GROUP BY TRUNC(ls.started, 'HH'), ls.depot) s
GROUP BY s.dt
ORDER BY s.dt

Oracle9i 之前需要将 CASE 语句更改为 DECODE,Oracle 特定的 IF/ELSE 逻辑。

Oracle 11g+,使用 PIVOT


未经测试:

  SELECT * 
    FROM (SELECT TRUNC(ls.started, 'HH') AS dt,
                 ls.depot
            FROM LOGSTATS ls
        GROUP BY TRUNC(ls.started, 'HH'), ls.depot)
   PIVOT (
     COUNT(*) FOR depot
   )
ORDER BY 1

【讨论】:

您介意仔细检查示例 1 吗?我修复了 "as" 引用,但在最后一行得到 ORA-00904: "SUMMARY"."DT": invalid identifier。谢谢! 使用单引号并且没有AS 关键字是接受的列别名语法。使用双引号的唯一原因是为了支持特殊字符。它在 PLSQL Developer 中按原样工作,但我有回应说 Toad 和 DBVisualizer 不喜欢单引号方法。 hmm,我也在使用 sqldeveloper... 加上它给出的单引号 >,改为双引号可以解决这些问题。这个10g。 在 9i 和 10g、PLSQL Developer 6 和 7 中使用单引号没有问题。 嗯,它不适用于 sqlplus。此外,在原版中,FROM 之前还有一个额外的逗号。我会将我的编辑恢复为您的示例,并留下我得到的结果。我会用谷歌搜索“10g pivot”,看看我能不能弄清楚。谢谢指点!【参考方案2】:

好吧,我至少可以提供 11 个解决方案;使用枢轴:

http://www.oracle.com/technology/pub/articles/oracle-database-11g-top-features/11g-pivot.html

我能临时想到的唯一 10g 选项(我很擅长 SQL,但不是专家)是填充表变量,然后从该表中选择单个行以获得最终结果。丑陋,可能相当慢,但可以完成工作。

【讨论】:

以上是关于Oracle:将一些计数旋转(合并)到单行?的主要内容,如果未能解决你的问题,请参考以下文章

Oracle APEX 交互式报告中的错误 - ORA-01427:单行子查询返回多于一行

查询返回:ORA-01427 单行子查询返回多于一行

ORA-01427 单行子查询返回多行 - 如何解决?

ORA-01427: 单行子查询返回多于一行 ,,WHEN USING SELECT COUNT

MySQL 语法混淆 - 合并简单数据以实现优雅的单行插入

如何将多行合并为表中的单行