2012-02-02 33 views
2

在SQL Server 2005數據庫中,我有一個表格,其中啓用或禁用信號時記錄了數據。簡化它看起來像這樣:在指定的時間範圍內提取信號狀態

Signal State  Time 
------ -------- ---------------- 
Alarm1 Disabled 2011-11-15 09:00 
Alarm1 Enabled  2011-12-20 13:30 
Alarm2 Enabled  2011-11-17 15:01 
Alarm2 Disabled 2011-12-15 06:57 
Alarm3 Disabled 2011-11-10 11:42 
Alarm3 Enabled  2011-12-02 13:12 
Alarm3 Disabled 2011-12-24 14:41 
Alarm4 Enabled  2011-10-09 13:25 
Alarm4 Disabled 2012-01-07 08:29 
Alarm5 Disabled 2011-11-19 07:12 
Alarm5 Enabled  2011-11-28 15:48 
Alarm6 Disabled 2011-12-14 17:29 
Alarm6 Enabled  2011-12-23 23:46 

(所有行也有一個ID列具有唯一標識符)。

使用T-SQL我想提取哪個報警是一個給定的時間範圍內禁止的信息,例如2011年12月。結果不僅應包括那些在當月被記錄爲禁用的警報,還應包括先前禁用並且在給定時間範圍內未啓用的警報。

鑑於以上數據,我想提取類似:

Signal Disabled   Enabled 
------ ---------------- ------- 
Alarm1 -     2011-12-20 12:30 
Alarm2 2011-12-15 06:57 - 
Alarm3 -     2011-12-02 13:12 
Alarm3 2011-12-24 14:41 - 
Alarm6 2011-12-14 17:29 2011-12-23 23:46 

任何幫助表示讚賞!

回答

1

簡化類型。

DECLARE @t TABLE (AlarmId INT NOT NULL, State BIT NOT NULL, TIME SMALLDATETIME NOT NULL) 

INSERT @t 
VALUES 
(1 ,0,'2011-11-15 09:00') 
,(1 ,1,'2011-12-20 13:30') 
,(2 ,1,'2011-11-17 15:01') 
,(2 ,0,'2011-12-15 06:57') 
,(3 ,0,'2011-11-10 11:42') 
,(3 ,1,'2011-12-02 13:12') 
,(3 ,0,'2011-12-24 14:41') 
,(4 ,1,'2011-10-09 13:25') 
,(4 ,0,'2012-01-07 08:29') 
,(5 ,0,'2011-11-19 07:12') 
,(5 ,1,'2011-11-28 15:48') 
,(6 ,0,'2011-12-14 17:29') 
,(6 ,1,'2011-12-23 23:46') 


DECLARE @Start DATETIME = '20111201' 

--Initial State DISABLED 
;WITH Disabled(AlarmId, Time) AS 
(
    SELECT 
     AlarmId, 
     Time 
    FROM 
    (
     SELECT 
      ROW_NUMBER() OVER (PARTITION BY AlarmId ORDER BY Time DESC) Ordinal, 
      AlarmId, 
      Time, 
      State 
     FROM @t 
     WHERE 
      Time < @Start 
    ) t 
    WHERE 
     t.Ordinal = 1 
    AND t.STate = 0 
    UNION 
    SELECT 
     AlarmId, 
     TIME 
    FROM @t 
    WHERE 
     Time >= @start AND Time < DATEADD(m,1,@STart) 
    AND STate = 0 

), 
Enabled(AlarmId, Time) AS 
(
    SELECT 
     AlarmId, 
     TIME 
    FROM @t 
    WHERE 
     Time >= @start AND Time < DATEADD(m,1,@STart) 
    AND STate = 1 
), 
Alarms(AlarmId) AS 
(
    SELECT DISTINCT AlarmId FROM @t 
) 

SELECT 
    Alarms.AlarmId, 
    CASE WHEN Disabled.Time >= @start AND Disabled.Time < DATEADD(m,1,@STart) THEN Disabled.Time ELSE NULL END Disabled, 
    CASE WHEN Enabled.Time < Disabled.Time THEN NULL ELSE Enabled.Time END Enabled 
FROM Alarms 
LEFT JOIN Enabled 
    ON Alarms.AlarmId = Enabled.AlarmId 
LEFT JOIN Disabled 
    ON Alarms.AlarmId = Disabled.AlarmId 
WHERE COALESCE(Enabled.Time, Disabled.Time) IS NOT NULL 
+0

美麗!你讓我今天一整天都感覺很好! :-) – Henrik 2012-02-02 13:04:38

0

我有兩個建議(取決於你想要什麼樣的數據)

首先是一些測試數據:

DECLARE @tbl TABLE(Signal VARCHAR(100),State VARCHAR(100),Time DATETIME) 
INSERT INTO @tbl 
SELECT 'Alarm1','Disabled','2011-11-15 09:00' 
UNION ALL 
SELECT 'Alarm1','Enabled','2011-12-20 13:30' 
UNION ALL 
SELECT 'Alarm2','Enabled','2011-11-17 15:01' 
UNION ALL 
SELECT 'Alarm2','Disabled','2011-12-15 06:57' 
UNION ALL 
SELECT 'Alarm3','Disabled','2011-11-10 11:42' 
UNION ALL 
SELECT 'Alarm3','Enabled','2011-12-02 13:12' 
UNION ALL 
SELECT 'Alarm3','Disabled','2011-12-24 14:41' 
UNION ALL 
SELECT 'Alarm4','Enabled','2011-10-09 13:25' 
UNION ALL 
SELECT 'Alarm4','Disabled','2012-01-07 08:29' 
UNION ALL 
SELECT 'Alarm5','Disabled','2011-11-19 07:12' 
UNION ALL 
SELECT 'Alarm5','Enabled','2011-11-28 15:48' 
UNION ALL 
SELECT 'Alarm6','Disabled','2011-12-14 17:29' 
UNION ALL 
SELECT 'Alarm6','Enabled','2011-12-23 23:46' 

DECLARE @startDate DATETIME='2011-12-01' 

然後,如果你有什麼報警不是唯一的。我會做這樣的事情:

SELECT 
    tbl.Signal, 
    CASE 
     WHEN tbl.State='Disabled' 
     THEN convert(varchar, tbl.Time, 120) 
     ELSE '-' 
    END AS DisabledTime, 
    CASE 
     WHEN tbl.State='Enabled' 
     THEN convert(varchar, tbl.Time, 120) 
     ELSE '-' 
    END AS EnabledTime 
FROM 
    @tbl AS tbl 
WHERE 
    tbl.Time BETWEEN @startDate AND (DATEADD(MM,1,@startDate)-1) 

如果你什麼警報獨特的,我會做這樣的事情:

SELECT 
    pvt.Signal, 
    ISNULL(pvt.Disabled,'-') AS Disabled, 
    ISNULL(pvt.Enabled,'-') AS Enabled 
FROM 
(
    SELECT 
     tbl.Signal, 
     convert(varchar, tbl.Time, 120) AS Time, 
     tbl.State 
    FROM 
     @tbl AS tbl 
    WHERE 
     tbl.Time BETWEEN @startDate AND (DATEADD(MM,1,@startDate)-1) 
) AS p 
PIVOT 
(
    MAX(p.Time) 
    FOR p.State IN([Disabled],[Enabled]) 
) AS pvt 
+0

謝謝你的時間和答案!它很接近,但不完全是我想要的;第一個查詢返回Alarm6的兩行,我想將其顯示在同一行上,警報被禁用,稍後再啓用。第二個查詢返回Alarm3的一行,我想要兩個,警報被禁用,啓用,然後再次禁用。 – Henrik 2012-02-06 12:48:12