Oracle: pivot (coalesce) some counts onto a single row?

大城市里の小女人 提交于 2019-12-23 12:12:38

问题


update: what I was calling coalesce I should have been calling pivot.

I'm extracting some daily usage counts from a log table. I can easily get this data one row per date/item, but I would like to pivot coalesce the columns into a single row.

e.g., I have:

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

I want:

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

Here's my current 10g query.

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

update: 11g has a pivot operation. The accepted answer shows how to do this in 9i and 10g.


回答1:


What you're looking for is pivoting - transposing the row data into columnar.

Oracle 9i+, Using WITH/CTE:


Use:

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

Non-WITH/CTE Equivalent


Use:

  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

Pre Oracle9i would need the CASE statements changed to DECODE, Oracle specific IF/ELSE logic.

Oracle 11g+, Using PIVOT


Untested:

  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



回答2:


Well, I can at least provide an 11 solution; use Pivot:

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

The only 10g option I can think of offhand (I'm decent with SQL, but not an expert) is to fill a table variable and then select individual rows out of that table for your final result. Ugly and likely fairly slow, but could get the job done.



来源:https://stackoverflow.com/questions/2169720/oracle-pivot-coalesce-some-counts-onto-a-single-row

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!