2016-03-15 161 views
0

我有一個SQL Server表,每行表示一個機器日誌,表示機器開機或關機的時間。列是ACTION,MACHINE_NAME,TIME_STAMP提取組中的開始日期和結束日期

ACTION是一個字符串,可以是「ON」或「OFF」 MACHINE_NAME是表示機器ID TIME_STAMP是日期的字符串。

一個例子:

ACTION  MACHINE_NAME   TIME_STAMP 
ON   PC1     2016/03/04 17:13:10 
OFF   PC1     2016/03/04 17:13:15 
ON   PC1     2016/03/04 17:14:15 
OFF   PC1     2016/03/04 17:15:45 

我需要從這些日誌中提取的新表,可以告訴我:「這臺機器X是ON從START_TIME N分鐘到END_TIME」

我怎麼能編寫一個SQL查詢爲了做到這一點?

期望的結果

MACHINE_NAME   START_TIME     END_TIME 
PC1     2016/03/04 17:13:10   2016/03/04 17:13:15 
PC1     2016/03/04 17:14:15   2016/03/04 17:15:45    
+7

MySQL!= MS SQL Server – lad2025

+0

我對這類查詢沒有太多經驗。我被卡住了,因爲我不知道如何正確地將兩個不同行的「ON」和「OFF」狀態合併爲一個單獨的行 –

+0

我正在使用SQL Server –

回答

2

我能解決這個使用CTE和LAG功能。這使我們能夠獲得每個'OFF'第一'ON'行動,並隨後申請ROW_NUMBER與它們匹配:

;WITH first_ON AS 
(
    SELECT *, LAG(m.ACTION, 1, 'OFF') OVER (PARTITION BY m.MACHINE_NAME ORDER BY m.TIME_STAMP) AS previous_action 
    FROM your_table m 
), 
ON_actions AS 
(
    SELECT 
      m.ACTION, 
      m.MACHINE_NAME, 
      m.TIME_STAMP, 
      ROW_NUMBER() OVER (ORDER BY TIME_STAMP) AS RN 
    FROM first_ON m 
    WHERE m.previous_action = 'OFF' AND m.ACTION = 'ON' 
), 
OFF_actions AS (
    SELECT 
      m.ACTION, 
      m.MACHINE_NAME, 
      m.TIME_STAMP, 
      ROW_NUMBER() OVER (ORDER BY TIME_STAMP) AS RN 
    FROM your_table m 
    WHERE m.ACTION = 'OFF' 
) 

SELECT a.MACHINE_NAME, a.TIME_STAMP AS START_TIME, b.TIME_STAMP AS END_TIME 
FROM ON_actions a 
INNER JOIN OFF_actions b ON a.MACHINE_NAME = b.MACHINE_NAME AND a.RN = b.RN 

編輯:該解決方案還需要無與倫比的插件和權衡考慮,例如ON,ON,OFF,ON ,ON,ON,OFF,OFF。

+0

即使可能,ON ON OFF如何?你怎麼打開一臺機器,然後在關機之前再打開它? – sagi

+0

同樣,請參閱Damien_The_Unbeliever問題下的註釋。他問是否會發生這種情況,而Luca S.明確表示,以及應如何處理。 – tobypls

1

你可以用這樣的相關查詢做到這一點:

SELECT t.Machine_name, 
     t.time_stamp as start_date, 
     (SELECT min(s.time_stamp) from YourTable s 
     WHERE t.Machine_name = s.Machine_Name 
      and s.ACTION = 'OFF' 
      and s.time_stamp > t.time_stamp) as end_date 
FROM YourTable t 
WHERE t.action = 'ON' 

編輯:

SELECT * FROM (
    SELECT t.Machine_name, 
      t.time_stamp as start_date, 
      (SELECT min(s.time_stamp) from YourTable s 
      WHERE t.Machine_name = s.Machine_Name 
       and s.ACTION = 'OFF' 
       and s.time_stamp > t.time_stamp) as end_date 
    FROM YourTable t 
    WHERE t.action = 'ON') 
WHERE end_date is not null 
+1

返回4行而不是2。 – DNac

+0

@DNac正確,修正。 – sagi

+0

仍然沒有返回正確的,想要的結果。 – DNac

0

提供基於time_stampmachine_name然後ROW_NUMBER一個group_id

查詢

;with cte as(
    select rn = row_number() over(  
     order by time_stamp, machine_name 
    ), * 
    from your_table_name 
) 
select z.machine_name, z.start_time, 
case when z.start_time = z.end_time then null 
    else z.end_time end as end_time from(
     select t.machine_name, min(t.time_stamp) as start_time, 
     max(t.time_stamp) as end_time from(
      select ((rn - 1)/2) + 1 AS Group_Id, * 
      from cte 
    )t 
    group by t.machine_name, t.Group_Id 
)z; 
0

將表連接到自身將產生所需的輸出,並且在SQL Server中編寫起來相當簡單。我在工作地點經常使用這種格式。

SELECT m1.MACHINE_NAME, m1.TIME_STAMP AS START_TIME, MIN(m2.TIME_STAMP) AS END_TIME 
FROM MACHINE_LOG m1 
INNER JOIN MACHINE_LOG m2 ON m1.MACHINE_NAME = m2.MACHINE_NAME 
    AND m2.ACTION = 'OFF' 
    AND m2.TIME_STAMP > m1.TIME_STAMP 
WHERE m1.ACTION = 'ON' 
GROUP BY m1.MACHINE_NAME, m1.START_TIME 
相關問題