Получать сгруппированные данные из таблицы в виде столбцов, а не строк - PullRequest
3 голосов
/ 11 июля 2011

У меня есть таблица со следующей схемой: (Дата, Имя, Состояние), где State может принимать значения «Обрабатывается», «Активно» и «Закрыто».Примеры записей:

|------------+---------+------------|
|       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 ]

3 голосов
/ 11 июля 2011
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
2 голосов
/ 11 июля 2011

вы также можете использовать встроенную функцию поворота в oracle ...

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

эта функция предложена человеком, имеющим хороший опыт работы с базой данных oracle ... вот почему я вставил сюда: -)

1 голос
/ 11 июля 2011

Это стандартный способ (до 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.

С уважением,
Роб.

1 голос
/ 11 июля 2011

Точный синтаксис будет зависеть от вашего движка базы данных, но в 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...