在指定的时间范围内提取信号状态

时间:2012-02-02 07:05:39

标签: sql-server-2005 tsql

在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

(所有行都有一个带有uniqueidentifier的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

任何帮助表示赞赏!

2 个答案:

答案 0 :(得分: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

答案 1 :(得分: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