2011-02-03 3 views
0

У нас есть Происшествия в нашей системе с указанием времени начала и окончания и названия проекта (и другая информация). Мы хотели бы иметь отчет: Сколько инцидентов имеет статус «открыто» в месяц за проект. Открытое состояние статуса: Не завершено.Расчет Открытых инцидентов в месяц

Если инцидент создан в декабре 2009 года и закрыта в марте 2010 года, то она должна быть включена в декабре 2009 года, январе и феврале 2010 года

Needed структура должна быть такой:

Project Year Month  Count 
------- ------ ------- ------- 
Test  2009 December 2 
Test  2010 January  10 
Test  2010 February 12 
.... 
+1

Какое время финиша установлено, пока инцидент еще открыт? И какие СУБД вы используете? –

ответ

0

В SQL Server:

SELECT 
    Project, 
    Year = YEAR(TimeWhenStillOpen), 
    Month = DATENAME(month, MONTH(TimeWhenStillOpen)), 
    Count = COUNT(*) 
FROM (
    SELECT 
    i.Project, 
    i.Incident, 
    TimeWhenStillOpen = DATEADD(month, v.number, i.StartTime) 
    FROM (
    SELECT 
     Project, 
     Incident, 
     StartTime, 
     FinishTime = ISNULL(FinishTime, GETDATE()), 
     MonthDiff = DATEDIFF(month, StartTime, ISNULL(FinishTime, GETDATE())) 
    FROM Incidents 
) i 
    INNER JOIN master..spt_values v ON v.type = 'P' 
     AND v.number BETWEEN 0 AND MonthDiff - 1 
) s 
GROUP BY Project, YEAR(TimeWhenStillOpen), MONTH(TimeWhenStillOpen) 
ORDER BY Project, YEAR(TimeWhenStillOpen), MONTH(TimeWhenStillOpen) 

Вкратце, как это работает:

  • Самый внутренний подзаголовок, который работает непосредственно в таблице «Происшествия», просто «нормализует» таблицу (заменяет NULL время окончания с текущим временем) и добавляет столбец разницы в месяц, MonthDiff. Если в вашем случае не может быть NULL, просто удалите соответствующее выражение ISNULL.

  • Внешний подзапрос использует MonthDiff, чтобы разбить временной диапазон на ряд временных меток, соответствующих месяцам, когда инцидент еще был открыт, т. Е. Месяц FinishTime не включен. Системная таблица, называемая master..spt_values, также используется там как готовая numbers table.

  • И наконец, основной выбор остается только с задачей группировки данных.

0

Полезным методом здесь является создание таблицы «всех» дат (очевидно, что это было бы бесконечно, поэтому я имею в виду достаточно большой диапазон для ваших целей) ИЛИ создайте две таблицы: один из всех месяцев (12 строк) и другой из " все "годы.

Давайте предположим, что вы идете на 1 из них:

create table all_dates (d date) 

и заполнить в случае необходимости. Я собираюсь определить таблицу падающей следующего

create table incident 
(
    incident_id int not null, 
    project_id int not null, 
    start_date date not null, 
    end_date  date null 
) 

Я не уверен, что RDBMS вы используете даты и функции рознятся между ними, так что следующим битом может потребоваться корректировки для ваших нужд.

select 
    project_id, 
    datepart(yy, all_dates.d) as "year", 
    datepart(mm, all_dates.d) as "month", 
    count(*) as "count" 
from 
    incident, 
    all_dates 
where 
    incident.start_date <= all_dates.d and 
    (incident.end_date >= all_dates.d or incident.end_date is null) 
group by 
    project_id, 
    datepart(yy, all_dates.d) year, 
    datepart(mm, all_dates.d) month 

Это не будет достаточно работать, как мы хотим, как отсчеты будут на каждый день, что инцидент был открыт в каждом месяце. Чтобы исправить это, нам нужно либо использовать подзапрос, либо временную таблицу, и это действительно зависит от СУРБД ...

Другая проблема заключается в том, что для открытых инцидентов он будет показывать их в течение всех последующих месяцев в таблице all_dates , добавление all_dates.d <= today решает это. Опять же, различные РСУБД имеют разные способы отдать сейчас/сегодня/SystemTime ...

Другой подход заключается иметь all_months, а не all_dates таблицы, просто имеет дату первого месяца в нем:

create table all_months (first_of_month date) 

select 
    project_id, 
    datepart(yy, all_months.first_of_month) as "year", 
    datepart(mm, all_months.first_of_month) as "month", 
    count(*) as "count" 
from 
    incident, 
    all_months 
where 
    incident.start_date <= dateadd(day, -1, dateadd(month, 1, first_of_month) 
    (incident.end_date >= first_of_month or incident.end_date is null) 
group by 
    project_id, 
    datepart(yy, all_months.first_of_month), 
    datepart(mm, all_months.first_of_month) 
Смежные вопросы