在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
任何帮助表示赞赏!
答案 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