我很难执行其中一个查询。我需要根据同一张桌子上的标志找到点火时间。表格如下,
UnitId eventtime ign
----------- ----------------------- -----
356 2011-05-04 10:41:00.000 1
356 2011-05-04 10:42:00.000 1
356 2011-05-04 10:43:00.000 1
356 2011-05-04 10:45:00.000 1
356 2011-05-04 10:47:00.000 1
356 2011-05-04 10:48:00.000 0
356 2011-05-04 11:14:00.000 1
356 2011-05-04 11:14:00.000 1
356 2011-05-04 11:15:00.000 1
356 2011-05-04 11:15:00.000 1
356 2011-05-04 11:15:00.000 1
356 2011-05-04 11:16:00.000 0
356 2011-05-04 11:16:00.000 0
356 2011-05-04 11:16:00.000 0
356 2011-05-04 14:49:00.000 1
356 2011-05-04 14:50:00.000 1
356 2011-05-04 14:50:00.000 1
356 2011-05-04 14:51:00.000 1
356 2011-05-04 14:52:00.000 0
356 2011-05-04 14:52:00.000 0
356 2011-05-04 20:52:00.000 0
此处,Ign标志将确定ignition_on和iginition_off时间。 所以在上面我们可以有点火对
2011-05-04 10:41:00.000 - 2011-05-04 10:48:00.000
2011-05-04 11:14:00.000 - 2011-05-04 11:16:00.000
2011-05-04 14:49:00.000 - 2011-05-04 14:52:00.000
所以从上面的一对我可以说我的单位运行7 + 2 + 3 = 12分钟。我不想在我的结果中完成上面的对,仅作为例子。我的目标是获得12分钟的结果。
我如何使用单个查询来实现它,现在我正在使用CURSOR循环,但是这个东西需要花费更多的时间用于多天和多个单元。无论如何,如果没有CURSOR,我能做到吗?
答案 0 :(得分:2)
现在已经很晚了,所以这次不是写出所有的代码,而是要总结一下如何做到这一点:
将表连接到其自身,其中右侧的一个连接条件是相关子查询,其从表>表中选择前1分钟(事件时间)。从左侧开始的当前行。然后使用where子句将其过滤到左侧的ign列为<>的行。到右边的ign列。这会让你得到你的改变。使用类似的技术第三次连接回表格,你将拥有既有开始时间又有结束时间的记录,可以使用日期函数来获取分钟值。
答案 1 :(得分:1)
如果我们有一个额外的标准来区分具有相同ign
值的相邻事件序列,我们可以从每个序列中获取ign=1
最早的事件并将其与最早的事件联系起来相应ign=0
序列的事件。
可以添加这样的标准,如下所示。我将首先发布解决方案,然后解释它是如何工作的。
首先,设置:
DECLARE @atable TABLE (
Id int IDENTITY,
UnitId int,
eventtime datetime,
ign bit
);
INSERT INTO @atable (UnitId, eventtime, ign)
SELECT 356, '2011-05-04 10:41:00.000', 1 UNION ALL
SELECT 356, '2011-05-04 10:42:00.000', 1 UNION ALL
SELECT 356, '2011-05-04 10:43:00.000', 1 UNION ALL
SELECT 356, '2011-05-04 10:45:00.000', 1 UNION ALL
SELECT 356, '2011-05-04 10:47:00.000', 1 UNION ALL
SELECT 356, '2011-05-04 10:48:00.000', 0 UNION ALL
SELECT 356, '2011-05-04 11:14:00.000', 1 UNION ALL
SELECT 356, '2011-05-04 11:14:00.000', 1 UNION ALL
SELECT 356, '2011-05-04 11:15:00.000', 1 UNION ALL
SELECT 356, '2011-05-04 11:15:00.000', 1 UNION ALL
SELECT 356, '2011-05-04 11:15:00.000', 1 UNION ALL
SELECT 356, '2011-05-04 11:16:00.000', 0 UNION ALL
SELECT 356, '2011-05-04 11:16:00.000', 0 UNION ALL
SELECT 356, '2011-05-04 11:16:00.000', 0 UNION ALL
SELECT 356, '2011-05-04 14:49:00.000', 1 UNION ALL
SELECT 356, '2011-05-04 14:50:00.000', 1 UNION ALL
SELECT 356, '2011-05-04 14:50:00.000', 1 UNION ALL
SELECT 356, '2011-05-04 14:51:00.000', 1 UNION ALL
SELECT 356, '2011-05-04 14:52:00.000', 0 UNION ALL
SELECT 356, '2011-05-04 14:52:00.000', 0 UNION ALL
SELECT 356, '2011-05-04 20:52:00.000', 0;
现在查询:
WITH
marked AS (
SELECT
*,
Grp = ROW_NUMBER() OVER (PARTITION BY UnitId ORDER BY eventtime) -
ROW_NUMBER() OVER (PARTITION BY UnitId, ign ORDER BY eventtime)
FROM @atable
),
ranked AS (
SELECT
*,
seqRank = DENSE_RANK() OVER (PARTITION BY UnitId, ign ORDER BY Grp),
eventRank = ROW_NUMBER() OVER (PARTITION BY UnitId, ign, Grp ORDER BY eventtime)
FROM marked
),
final AS (
SELECT
s.UnitId,
EventStart = s.eventtime,
EventEnd = e.eventtime
FROM ranked s
INNER JOIN ranked e ON s.UnitId = e.UnitId AND s.seqRank = e.seqRank
WHERE s.ign = 1
AND e.ign = 0
AND s.eventRank = 1
AND e.eventRank = 1
)
SELECT *
FROM final
ORDER BY
UnitId,
EventStart
这是它的工作原理。
marked
公用表表达式(CTE)为我们提供了我在开始时讨论的附加标准。它产生的结果集如下所示:
Id UnitId eventtime ign Grp
-- ------ ----------------------- --- ---
1 356 2011-05-04 10:41:00.000 1 0
2 356 2011-05-04 10:42:00.000 1 0
3 356 2011-05-04 10:43:00.000 1 0
4 356 2011-05-04 10:45:00.000 1 0
5 356 2011-05-04 10:47:00.000 1 0
6 356 2011-05-04 10:48:00.000 0 5
7 356 2011-05-04 11:14:00.000 1 1
8 356 2011-05-04 11:14:00.000 1 1
9 356 2011-05-04 11:15:00.000 1 1
10 356 2011-05-04 11:15:00.000 1 1
11 356 2011-05-04 11:15:00.000 1 1
12 356 2011-05-04 11:16:00.000 0 10
13 356 2011-05-04 11:16:00.000 0 10
14 356 2011-05-04 11:16:00.000 0 10
15 356 2011-05-04 14:49:00.000 1 4
16 356 2011-05-04 14:50:00.000 1 4
17 356 2011-05-04 14:50:00.000 1 4
18 356 2011-05-04 14:51:00.000 1 4
19 356 2011-05-04 14:52:00.000 0 14
20 356 2011-05-04 14:52:00.000 0 14
21 356 2011-05-04 20:52:00.000 0 14
您可以自己查看具有相同ign
的每个事件序列现在如何通过其自己的(UnitId, ign, Grp)
键轻松区分。所以现在我们可以对每个序列以及序列中的每个事件进行排序,这就是ranked
CTE的作用。它产生以下结果集:
Id UnitId eventtime ign Grp seqRank eventRank
-- ------ ----------------------- --- --- ------- ---------
1 356 2011-05-04 10:41:00.000 1 0 1 1
2 356 2011-05-04 10:42:00.000 1 0 1 2
3 356 2011-05-04 10:43:00.000 1 0 1 3
4 356 2011-05-04 10:45:00.000 1 0 1 4
5 356 2011-05-04 10:47:00.000 1 0 1 5
6 356 2011-05-04 10:48:00.000 0 5 1 1
7 356 2011-05-04 11:14:00.000 1 1 2 1
8 356 2011-05-04 11:14:00.000 1 1 2 2
9 356 2011-05-04 11:15:00.000 1 1 2 3
10 356 2011-05-04 11:15:00.000 1 1 2 4
11 356 2011-05-04 11:15:00.000 1 1 2 5
12 356 2011-05-04 11:16:00.000 0 10 2 1
13 356 2011-05-04 11:16:00.000 0 10 2 2
14 356 2011-05-04 11:16:00.000 0 10 2 3
15 356 2011-05-04 14:49:00.000 1 4 3 1
16 356 2011-05-04 14:50:00.000 1 4 3 2
17 356 2011-05-04 14:50:00.000 1 4 3 3
18 356 2011-05-04 14:51:00.000 1 4 3 4
19 356 2011-05-04 14:52:00.000 0 14 3 1
20 356 2011-05-04 14:52:00.000 0 14 3 2
21 356 2011-05-04 20:52:00.000 0 14 3 3
您可以看到ign=1
序列现在可以在ign=0
的帮助下与seqRank
序列匹配。并且只选择每个序列中最早的事件(按eventRank=1
过滤),我们将获得所有ign=1
序列的开始和结束时间。因此final
CTE的结果是:
UnitId EventStart EventEnd
------ ----------------------- -----------------------
356 2011-05-04 10:41:00.000 2011-05-04 10:48:00.000
356 2011-05-04 11:14:00.000 2011-05-04 11:16:00.000
356 2011-05-04 14:49:00.000 2011-05-04 14:52:00.000
显然,如果最后一个ign=1
序列后面没有ign=0
事件,则不会在最终结果中显示,因为最后ign=1
序列没有匹配ign=0
序列,使用上述方法。
有一种可能的情况,此查询无法正常工作。当事件列表以ign=0
事件而不是ign=1
开头时。如果这实际上是可行的,您只需将以下过滤器添加到ranked
CTE:
WHERE NOT (ign = 0 AND Grp = 0)
-- Alternatively: WHERE ign <> 0 OR Grp <> 0
利用Grp
的第一个值始终为0
的事实。因此,如果将0
分配给ign=0
的事件,则应排除这些事件。
有用的阅读:
答案 2 :(得分:0)
您可以根据row_number()
加入自己的表格select t1.RowNo as t1Row, t2.RowNo as t2Row, t1.StarTime, t2.EndTime as EndTime, cast(t2.EndTime - t1.StarTime as time) as Duration, t1.ign as IgnPeriod
from (select eventtime as StarTime, ign, ROW_NUMBER() over (order by eventtime) as RowNo from UnitTable) as t1
inner join (select * from (select eventtime as EndTime, ROW_NUMBER() over (order by eventtime) as RowNo from UnitTable) as t_inner) t2 on t1.RowNo + 1 = t2.RowNo
然后,您可以将ign = 1个句点的持续时间相加:
select cast(dateadd(millisecond,sum(datediff(millisecond,0,duration)),0) as time) from
(select cast(t2.EndTime - t1.StarTime as time) as Duration, t1.ign as IgnPeriod
from (select eventtime as StarTime, ign, ROW_NUMBER() over (order by eventtime) as RowNo from UnitTable) as t1
inner join (select * from (select eventtime as EndTime, ROW_NUMBER() over (order by eventtime) as RowNo from UnitTable) as t_inner) t2 on t1.RowNo + 1 = t2.RowNo
) t_outer
where t_outer.IgnPeriod = 1