从表中获取分组数据作为列而不是行

时间:2011-07-11 04:51:28

标签: sql oracle

我有一个包含以下模式的表:(日期,名称,状态)其中State可以是'Processing','Active'和'Closed'之一。样本条目是:

|------------+---------+------------|
|       Date | Name    | Status     |
|------------+---------+------------|
| 2011-07-01 | Alice   | Processing |
| 2011-07-01 | Alice   | Active     |
| 2011-07-02 | Alice   | Closed     |
| 2011-07-01 | Bob     | Active     |
| 2011-07-02 | Charlie | Processing |
|------------+---------+------------|

我使用以下查询来获取不同状态的帐户数量:

select date, status, count(distinct name)
from accounts
group by date, status

它给出了以下内容:

2011-07-01 Processing 1
2011-07-01 Active 2
2011-07-02 Active 1
2011-07-02 Closed 1

如何在列中获取数据?即,

2011-07-01 2 1 0
2011-07-02 1 0 1

如果第一列是日期,第二列是处于活动状态的帐户数,第三列是处理状态中的帐户数,最后一列是处于已关闭状态的帐户数?我唯一能想到的是为每个状态编写三个子查询,并进行父查询以选择每个状态。但它似乎不是非常可扩展的(例如,如果我必须添加新状态,我已经修改了父查询并添加了一个子查询)。

4 个答案:

答案 0 :(得分:3)

SELECT date
   , SUM(CASE status WHEN 'Active'     THEN cnt ELSE 0 END) AS a
   , SUM(CASE status WHEN 'Processing' THEN cnt ELSE 0 END) AS p
   , SUM(CASE status WHEN 'Closed'     THEN cnt ELSE 0 END) AS c
FROM 
  ( SELECT date, status, COUNT(DISTINCT name) AS cnt
    FROM accounts
    GROUP BY date, status
  ) grp
GROUP BY date
ORDER BY date

答案 1 :(得分:2)

你也可以在oracle中使用build in pivot函数......

SELECT * FROM accounts 
pivot ( count(distinct name) for status in ('Active','Processing','Closed')); 

这个功能是由在oracle数据库中有很好经验的人建议的..这就是我粘贴在这里的原因: - )

答案 2 :(得分:1)

确切的语法将取决于您的数据库引擎,但在PostgreSQL中,可能还有其他的,这将起作用。这可能在Oracle中逐字逐句,因为Postgres倾向于复制Oracle语法。

SELECT
    date,
    SUM((Status='Processing')::INT) AS Processing,
    SUM((Status='Active')::INT) AS Active,
    SUM((Status='Closed')::INT) AS Closed
FROM accounts
GROUP BY date;

答案 3 :(得分:1)

这是执行数据透视的标准方式(在Oracle 11g之前):

SQL> create table mytable (mydate,name,status)
  2  as
  3  select date '2011-07-01', 'Alice', 'Processing' from dual union all
  4  select date '2011-07-01', 'Alice', 'Active' from dual union all
  5  select date '2011-07-02', 'Alice', 'Closed' from dual union all
  6  select date '2011-07-01', 'Bob', 'Active' from dual union all
  7  select date '2011-07-02', 'Charlie', 'Processing' from dual
  8  /

Table created.

SQL> select mydate
  2       , count(case status when 'Active' then 1 end)     a
  3       , count(case status when 'Processing' then 1 end) p
  4       , count(case status when 'Closed' then 1 end)     c
  5    from mytable
  6   group by mydate
  7   order by mydate
  8  /

MYDATE                       A          P          C
------------------- ---------- ---------- ----------
01-07-2011 00:00:00          2          1          0
02-07-2011 00:00:00          0          1          1

2 rows selected.

的问候,
罗布。