2011-01-07 3 views
1

У меня есть простой SQL Express сервер, и я регистрирую данные на нем, у меня есть несколько машин (промышленное оборудование), которые я контролирую. Всякий раз, когда изменяется состояние компьютеров, я создаю новую запись, которая вводит данные в следующие столбцы. Time (Time Stamp), Machine Name (Текст), Status (1,2 или 3) для запуска, простоя и вниз и ReasonCode (1-10). Мне нужно рассчитать, сколько времени машина находилась в каждом статусе, а также причина для каждого состояния. Я хотел бы сделать это доступным через SQL-отчеты. Это функция, которую LOT промышленных производителей хотят сделать в наши дни, и я пытаюсь создать простой пример. К сожалению, я не так разбираюсь в SQL. Я предполагаю, что это можно поместить в хранимую процедуру и запустить каждые n секунд, чтобы пересчитать. Любая помощь будет оценена по достоинству.Расчет состояния машины в SQL

+0

удалить мой ответ, так как он не решает корневой вопрос - я неправильно поняли часть вашего объяснения о ваших типах данных. – JNK

ответ

1

Вам не нужно пересчитывать. Вы можете запросить информацию по запросу. Вот самодостаточный пример

DECLARE @Test 
Table (
    LogTime datetime, 
    MachineName varchar(100), 
    Status int , 
    ReasonCode int) 

INSERT INTO @Test VALUES ('01/01/2011 4:19:11.459' , 'ServerX', 1, 3) 
INSERT INTO @Test VALUES ('01/02/2011 3:43:03.652' , 'ServerZ', 0, 4) 
INSERT INTO @Test VALUES ('02/04/2011 11:17:51.827' , 'ServerX', 2, 2) 
INSERT INTO @Test VALUES ('02/05/2011 4:22:22.205' , 'ServerX', 3, 1) 
INSERT INTO @Test VALUES ('01/03/2011 11:42:44.211' , 'ServerZ', 1, 4) 



;with TIMEdelta AS (
SELECT 
    machineName, 
    t.LogTime, 
    MIN(nextTime) as nextTime 
FROM (
    Select 
     t.MachineName, 
     t.LogTime, 

     t1.LogTime nextTime 
    from @Test t 
     INNER JOIN @Test t1 
     ON t.machineName = t1.machineName 
     AND t.LogTime < t1.LogTime 

    ) t 

GROUP BY 
    machineName, 

    t.LogTime 

) 

SELECT 
    t.MachineName, 
    t.LogTime, 
    t.ReasonCode, 
    t.Status, 
DateDiff(DAY, 0, (TIMEdelta.nextTime - TIMEdelta.LogTime)) Days, 
DatePart(HOUR , TIMEdelta.nextTime - TIMEdelta.LogTime) Hour, 
DatePart(MINUTE, TIMEdelta.nextTime - TIMEdelta.LogTime) MInute 

FROM 

    @Test t 
    LEFT JOIN TIMEdelta 
    ON t.LogTime = timedelta.logtime 
     and t.MachineName = TIMEdelta.MachineName 

Это выводит

MachineName LogTime     ReasonCode Status  Days  Hours  Minutes 
----------- ----------------------- ----------- ----------- ----------- ----------- ----------- 
ServerX  2011-01-01 04:19:11.460 3   1   34   6   58 
ServerZ  2011-01-02 03:43:03.653 4   0   1   7   59 
ServerX  2011-02-04 11:17:51.827 2   2   0   17   4 
ServerX  2011-02-05 04:22:22.207 1   3   NULL  NULL  NULL 
ServerZ  2011-01-03 11:42:44.210 4   1   NULL  NULL  NULL 

Вы можете изменить выход для отображения текущего времени - logtime вместо Null для тех текущего состояния строк

Update Для агрегаты для стержня вы можете использовать PIVOT

SELECT 
MachineName, 
[0] as Started, 
[1] as Stopped, 
[2] as Paused, 
[3] as Foo 

FROM 
(
SELECT 
    t.MachineName, 
    t.status, 
    cast(TimeDelta.nextTime - t.LogTime as DECIMAL(18,10)) duration 

FROM 

    @Test t 
    LEFT JOIN TIMEdelta 
    ON t.LogTime = timedelta.logtime 
    and t.MachineName = TIMEdelta.MachineName 
) source 
PIVOT 
(
SUM(duration) 
FOR status IN ([0], [1], [2], [3]) 
) AS PivotTable; 

Который имеет этот выход

MachineName Started  Stopped  Paused  Foo 
----------- ------------ -------------- ------------ ------------ 
ServerX  NULL   34.2907449846 0.7114627315 1.0000000000 
ServerZ  1.3331082948 NULL   NULL   ULL 

Update Используемые даты, перекрещенные месяцы и обновленные дни известково

+0

ОК. Я хотел спросить об этом ниже, но прищурился. Может ли быть добавлен вывод, поэтому я получаю итоговое значение для каждого состояния, чтобы оно выводило общее время, в течение которого каждая машина находилась в каждом состоянии? – Bob

+0

Еще раз спасибо за вашу помощь, это прекрасно – Bob

2

Предполагая, что таблица называется status содержащий

MachineName NVarChar(whatever) 
Status Int 
Reason Int 
Time DateTime 

Тогда этот запрос должен работать хорошо

Select 
    st.MachineName, 
    st.status, 
    st.reason 
    st.Time as TimeChanged, 
    DateDiff(ss, min(dur.Time), st.Time) 
From 
    Status st inner join 
    Status dur on st.MachineName = dur.MachineName and st.Time <dur.Time 
group by 
    st.MachineName, 
    St.Status, 
    st.Time, 
    st.reason 

Edit - в ответ на ваш комментарий

select 
    st.MachineName, 
    sum(case when status=1 then Duration else 0 end) as RunningTime, 
    sum(case when status=2 then Duration else 0 end) as IdleTime, 
    sum(case when status=3 then Duration else 0 end) as DownTime, 
From 
    (Select 
     st.MachineName, 
     st.status, 
     st.reason 
     st.Time as TimeChanged, 
     DateDiff(ss, min(dur.Time), st.Time) as Duration 
    From 
     Status st inner join 
     Status dur on st.MachineName = dur.MachineName and st.Time <dur.Time 
    group by 
     st.MachineName, 
     St.Status, 
     st.Time, 
     st.reason) as foo 
Group by MachineName 

Это должно получить имя машины и колонки для времени, проведенного в каждом из состояний

+1

+1 Очень хорошее решение. Вы теряете текущее состояние, но его можно получить, по крайней мере, с профсоюзом. –

+0

@Conrad - Хорошая точка. Присоединение может быть изменено на 'left outer', которое должно решить это, датированный даным нулевой аргумент возвращает null. – Robb

+0

Спасибо за вашу помощь, я вижу, как эти работы и я играю с кодом теперь работать, и это так, есть ли способ скомпенсировать все время, когда machien был вверх, без дела и вниз, поэтому я создаю только 3 строки в выходе? как это – Bob

Смежные вопросы