当前位置: 首页 > 面试题库 >

基于来自多行SQL Server的标志的时间总和

徐洛华
2023-03-14
问题内容

我很难执行查询之一。我需要根据同一张表中的标志找到点火时间。表格如下

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的情况下我可以实现它吗?


问题答案:

如果还有其他标准可以区分具有相同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)。因此,现在我们可以对每个序列以及序列中的每个事件进行排名,这就是rankedCTE所做的。它产生以下结果集:

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序列的开始时间和结束时间。因此,finalCTE的结果是:

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。如果确实可行,则只需将以下过滤器添加到rankedCTE:

WHERE NOT (ign = 0 AND Grp = 0)
-- Alternatively: WHERE ign <> 0 OR Grp <> 0

利用以下事实:的第一个值Grp将始终为0。因此,如果0将分配给具有ign=0的事件,则应排除这些事件。



 类似资料:
  • 问题内容: 从选择查询的开始时间和结束时间列表中,我需要找出不包括重叠时间和休息时间的总时间。 因此,在这种情况下,总计应为160分钟。 我不想使用太多循环来解决这个问题。寻找一些简单的解决方案。 问题答案: 结果是160

  • 我对以下查询有问题: 这个想法是把包括邮资在内的订单总价拿回来。 已订购的项目-包括所有已订购的项目(因此可以有多行) 订单-包括订单的邮资价格(这里每个订单只有一行) 我遇到的问题是,如果订单中包含多个“ordered_items”项目,则上述金额会多次计算“orders”中的邮资。 如何重写此查询,使邮资只计算一次? 提前感谢任何帮助。

  • 问题内容: 在Java中,如何以以下格式打印自纪元以来的时间,以秒和纳秒为单位: 我的输入是: 两者的总和是自该纪元以来经过的时间。 问题答案: 你可以这样做 例如 如果您真的不需要超过几毫秒的时间,您可以做

  • 我对时间序列分类比较陌生,正在寻求帮助: 我有一个包含5000个多元时间序列的数据集,每个数据集由21个变量组成,时间周期为3年,类别信息为1或0。我想做的是对一个新的输入进行分类,它在3年的时间内由21个变量组成。 就目前而言,经过几天的研究,我还没有找到(或显然没有理解)将多变量时间序列输入LSTM的方法。有没有可能的解决办法? 我目前的想法是将5000个时间序列“合并”成一个,并向每个序列添

  • null 例如,对于单个多行日志,如下所示: 这是一个详细的语句,它将非常详细地说明发生了什么,发生在哪里,以及应用程序在响应异常事件时正在做什么。 我能找到的最接近的是JBoss日志API和在ActiveMQ Artemis源代码中找到的一些代码示例。可以在单个文件中定义消息格式声明,如下所示: 有人对这个问题有什么建议吗--不管是另一个API、代码模式还是一个漂亮的技巧?