2014-11-11 1 views
4

Учитывая набор записей базы данных, которые записывают дату, когда объект входит в определенное состояние, я хотел бы создать запрос, который показывает, сколько объектов находится в каждом состоянии в любую конкретную дату. Результаты будут использованы для создания отчетов о тенденциях, показывающих, как количество объектов в каждом состоянии изменяется со временем.SQL-запрос для подсчета количества объектов в каждом состоянии в каждый день

У меня есть таблица вроде следующей, который записывает дату, когда объект входит в определенное состояние:

ObjID EntryDate State 
----- ---------- ----- 
    1 2014-11-01 A 
    1 2014-11-04 B 
    1 2014-11-06 C 
    2 2014-11-01 A 
    2 2014-11-03 B 
    2 2014-11-10 C 
    3 2014-11-03 B 
    3 2014-11-08 C 

Есть произвольное число объектов и состояний.

Мне нужно создать запрос, который возвращает количество объектов в каждом состоянии каждой даты. Результат будет выглядеть следующим образом:

Date  State Count 
---------- ----- ----- 
2014-11-01 A  2 
2014-11-01 B  0 
2014-11-01 C  0 
2014-11-02 A  2 
2014-11-02 B  0 
2014-11-02 C  0 
2014-11-03 A  1 
2014-11-03 B  2 
2014-11-03 C  0 
2014-11-04 A  0 
2014-11-04 B  3 
2014-11-04 C  0 
2014-11-05 A  0 
2014-11-05 B  3 
2014-11-05 C  0 
2014-11-06 A  0 
2014-11-06 B  2 
2014-11-06 C  1 
2014-11-07 A  0 
2014-11-07 B  2 
2014-11-07 C  1 
2014-11-08 A  0 
2014-11-08 B  1 
2014-11-08 C  2 
2014-11-09 A  0 
2014-11-09 B  1 
2014-11-09 C  2 
2014-11-10 A  0 
2014-11-10 B  0 
2014-11-10 C  3 

Я работаю с базой данных Oracle.

Я не смог найти пример, соответствующий моему делу. Следующие вопросы выглядят как они просят решения подобных, но различных проблем:

Любая помощь или советы, которые могут быть предоставлены были бы оценены.

+0

Ваши ожидаемые результаты включают данные не в вашей таблице ... откуда это происходит? – Ben

+0

База данных записывает дату, когда объект входит в определенное состояние. Объект остается в этом состоянии, пока он не перейдет в другое состояние. В идеале результаты запроса будут содержать количество объектов в каждом состоянии даже для дат, на которых не произошло никаких переходов состояния. – jmm3

ответ

0

Выберите EntryDate в качестве даты, государство, граф (Distinct ObjId) в качестве графа С Table_1 группы по EntryDate, Государственный

+0

Я понимаю, что даю этот ответ. Я не понимаю понимания. Понятно, что это ничего не дает ничего похожего на то, что просит ОП. –

0
SELECT EntryDate AS "Date", State, COUNT(DISTINCT ObjectId) AS "Count" GROUP BY EntryDate, State ORDER BY EntryDate, State; 
0

Поскольку каждое состояние не записывается каждый дату, что вам нужно сделать CROSS JOIN, чтобы получить уникальные состояния, а затем GROUP BY.

SELECT EntryDate, 
     C.State, 
     SUM(case when C.state = Table1.state then 1 else 0 end) as Count 
FROM Table1 
CROSS JOIN (SELECT DISTINCT State FROM Table1) C 
GROUP BY EntryDate, C.State 
ORDER BY EntryDate 
0

Я собираюсь сделать быстрый и грязный способ получить номера. Вы можете выбрать предпочтительный метод. , , с использованием рекурсивных CTE, connect by или таблицы чисел. Итак, следующее генерирует все комбинации дат и состояний. Затем он использует связанный подзапрос для подсчета количества объектов в каждом штате на каждую дату:

with n as (
     select rownum - 1 as n 
     from table t 
    ), 
    dates as (
     select mind + n.n 
     from (select min(date) as mind, max(date) as maxd from table) t 
     where mind + n.n <= maxd 
    ) 
select d.date, s.state, 
     (select count(*) 
     from (select t2.*, lead(date) over (partition by ObjId order by date) as nextdate 
       from table t2 
      ) t2 
     where d.date >= t2.date and (d.date < t2.nextdate or t2.nextdate is null) and 
       d.state = t2.state 
     ) as counts 
from dates d cross join 
    (select distinct state from table t) 
0

Этот запрос перечислит, сколько объектов занесут определенное состояние на каждый день, предполагая, что каждый объект только изменяет состояние один раз в день , Если объекты меняют состояния больше, чем один раз в день, вам нужно будет использовать счетчик (отчетливый ObjId):

select entrydate, state, count(objid) 
from my_table 
group by entrydate, state 
order by entrydate, state 

Однако, вы спрашиваете, сколько объектов в определенном состоянии на каждый день, таким образом, вам потребуется чтобы показать это. Так как вы только предоставить эту конкретную таблицу в вашем примере, я буду работать с этой таблицей только:

select alldatestates.entrydate, alldatestates.state, count(statesbyday.objid) 
from 
    (
    select alldates.entrydate, allstates.state 
    from (select distinct entrydate from mytable) alldates, 
     (select distinct state from mytable) allstates 
    ) alldatestates 
    left join 
    (
    select alldates.entrydate, allobjs.objid, (select min(state) as state from mytable t1 
              where t1.objid = allobjs.objid and 
               t1.entrydate = (select max(entrydate) from mytable t2 
                   where t2.objid = t1.objid and 
                     t2.entrydate <= alldates.entrydate)) as state 
    from (select distinct entrydate from mytable) alldates, 
     (select distinct objid from mytable) allobjs 
    ) statesbyday 
    on alldatestates.entrydate = statesbyday.entrydate and alldatestates.state = statesbyday.state 
group by alldatestates.entrydate, alldatestates.state 
order by alldatestates.entrydate, alldatestates.state 

Конечно, этот запрос будет гораздо проще, если у вас есть таблица для всех возможных состояний и еще один для все возможные идентификаторы объектов.

Кроме того, возможно, вы можете найти запрос более простой, чем этот, но этот работает. Недостатком является то, что он может очень быстро стать кошмаром оптимизатора!:)

0

Разработка SQL SERVER, потому что я больше знаком, но вот то, что у меня до сих пор:

скрипку примера (SQL SERVER, но только разница должна быть функциями даты я думаю .. .): http://sqlfiddle.com/#!3/8b9748/2

WITH zeroThruNine AS (SELECT 0 AS n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9), 
nums AS (SELECT 10*b.n+a.n AS n FROM zeroThruNine a, zeroThruNine b), 
Dates AS (
    SELECT DATEADD(d,n.n,(SELECT MIN(t.EntryDate) FROM @tbl t)) AS Date 
    FROM nums n 
    WHERE DATEADD(d,n.n,(SELECT MIN(t.EntryDate) FROM @tbl t))<=(SELECT MAX(t.EntryDate) FROM @tbl t) 
), Data AS (
    SELECT d.Date, t.ObjID, t.State, ROW_NUMBER() OVER (PARTITION BY t.ObjID, d.Date ORDER BY t.EntryDate DESC) as r 
    FROM Dates d, @tbl t 
    WHERE d.Date>=t.EntryDate 
) 
SELECT t.Date, t.State, COUNT(*) 
FROM Data t 
WHERE t.r=1 
GROUP BY t.Date, t.State 
ORDER BY t.Date, t.State 

Во-первых, начать делать таблицу чисел (см http://sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an-auxiliary-numbers-table.html) для примеров. Существуют разные способы создания числовых таблиц в разных базах данных, поэтому первые два выражения WITH, которые я создал, - это просто создать представление чисел от 0 до 99. Я уверен, что есть другие способы, и вам может потребоваться больше, чем всего 100 номеров (что составляет 100 дат между первой и последней даты вы обеспечили)

Итак, как только вы получите даты КТР, основная часть является КТР данных

Он находит каждую дату из КТР даты, и сопоставляет его со значениями таблицы @tbl (вашей таблицы) с любыми государствами, которые были записаны после указанной даты. Он также отмечает порядок, в котором состояния/на единицу в порядке убывания. Таким образом, в конечном запросе мы можем просто использовать WHERE tr = 1, чтобы получить максимальное состояние для каждого объекта в день

Одна из проблем - это получение данных для всех дат, даже тех, где ничего не было записано, но для нуля -counts, он ничего не возвращает. Если бы вы захотели, вы могли бы присоединиться к этому результату с учетом различных состояний и принять 0, если не было присоединено.