SQL 查询:如果给定两个 DateTime 时间戳,如何确定“在 N 小时内看到过”?

Posted

技术标签:

【中文标题】SQL 查询:如果给定两个 DateTime 时间戳,如何确定“在 N 小时内看到过”?【英文标题】:SQL Query: How to determine "Seen during N hour" if given two DateTime time stamps? 【发布时间】:2011-01-29 02:28:39 【问题描述】:

我正在编写一个基于 SQLite 数据库的统计应用程序。有一个表格记录用户登录和注销的时间(SessionStart,SessionEnd DateTimes)。

我正在寻找的是一个查询,它可以显示用户 登录的时间,以折线图的方式 - 所以在 12:00 到凌晨 1:00 之间有 60 个用户登录(在任何时候),在凌晨 1:00 到 2:00 之间有 54 个用户登录,等等......

我希望能够对此进行求和,这就是为什么我不能将记录带入 .NET 并以这种方式遍历它们。

我提出了一种相当原始的方法,即一天中每个小时的子查询,但是这种方法已被证明是缓慢而缓慢的。我需要能够在一瞬间计算出几十万条记录。

  SELECT
        case
        when (strftime('%s',datetime(date(sessionstart), '+0 hours')) > strftime('%s',sessionstart)
        AND strftime('%s',datetime(date(sessionstart), '+0 hours')) < strftime('%s',sessionend))
        OR (strftime('%s',datetime(date(sessionstart), '+1 hours')) > strftime('%s',sessionstart)
        AND strftime('%s',datetime(date(sessionstart), '+1 hours')) < strftime('%s',sessionend))
        OR (strftime('%s',datetime(date(sessionstart), '+0 hours')) < strftime('%s',sessionstart)
        AND strftime('%s',datetime(date(sessionstart), '+1 hours')) > strftime('%s',sessionend))
        then 1 else 0 end as hour_zero,
... hour_one, 
... hour_two, 
........ hour_twentythree
FROM UserSession

我想知道有什么更好的方法来确定在特定小时内是否看到了两个 DateTime(最好的情况是,如果它在多天登录,但不是必需的,它已经超过一个小时多少次)?

我唯一的另一个想法是有一个专门用于此的“小时”表,并且只计算用户在运行时看到的小时数,但我觉得这比以前的 SQL 更像是一种 hack。

任何帮助将不胜感激!

【问题讨论】:

你根本不关心 DATE 部分吗?您是否需要对整个历史记录、某个日期范围或每一天的每个小时进行汇总? 删除日期部分的唯一问题是有些用户可能登录超过一天,所以最好的情况是能够在25 小时会议。我会为特定用户或表格上的另一个标识符每小时汇总一次。不过,这可能包括几十万个会话。 【参考方案1】:

在 Sybase(T-SQL 方言)上玩了一会儿,然后想出了这个查询。

SELECT
    StartHour AS Hour, COUNT(*) AS SessionCount
FROM
    (SELECT
        CONVERT(DATETIME, '2001-01-01 ' + Hour + ':00:00') as StartHour,
        DATEADD(HH, 1, CONVERT(DATETIME, '2001-01-01 ' + Hour + ':00:00')) as EndHour
    FROM
        (SELECT '00' AS Hour UNION ALL SELECT '01' AS Hour UNION ALL
        SELECT '02' AS Hour UNION ALL SELECT '03' AS Hour UNION ALL
        SELECT '04' AS Hour UNION ALL SELECT '05' AS Hour UNION ALL
        SELECT '06' AS Hour UNION ALL SELECT '07' AS Hour UNION ALL
        SELECT '08' AS Hour UNION ALL SELECT '09' AS Hour UNION ALL
        SELECT '10' AS Hour UNION ALL SELECT '11' AS Hour UNION ALL
        SELECT '12' AS Hour UNION ALL SELECT '13' AS Hour UNION ALL
        SELECT '14' AS Hour UNION ALL SELECT '15' AS Hour UNION ALL
        SELECT '16' AS Hour UNION ALL SELECT '17' AS Hour UNION ALL
        SELECT '18' AS Hour UNION ALL SELECT '19' AS Hour UNION ALL
        SELECT '20' AS Hour UNION ALL SELECT '21' AS Hour UNION ALL
        SELECT '22' AS Hour UNION ALL SELECT '23' AS Hour) AS Hours
    ) AS T1,
    UserSession AS T2
WHERE
    -- Logged on during, logged off during
    (T2.SessionStart >= T1.StartHour AND T2.SessionEnd < T1.EndHour)
    -- Logged on before, logged off during
    OR (T2.SessionStart < T1.StartHour AND T2.SessionEnd >= StartHour AND T2.SessionEnd < T1.EndHour)
    -- Logged on during, logged off after
    OR (T2.SessionStart >= T1.StartHour AND T2.SessionStart < T1.EndHour AND T2.SessionEnd >= T1.EndHour)
    -- Logged on before, logged off after
    OR (T2.SessionStart < T1.StartHour AND T2.SessionEnd >= T1.EndHour)
GROUP BY
    T1.StartHour
ORDER BY
    T1.StartHour

所需的输入是以 YYYY-MM-DD 形式汇总的日期。请注意,对于计数为零的时间,它不会返回任何结果。

【讨论】:

【参考方案2】:

也许您可以有另一个表,当记录注销时间时,填充记录以确定用户登录的时间?

例如

create table hourlyUseLog (
    userID text not null,
    date float, // julian Day
    hour0 integer default 0,
    hour1 integer default 0,

etc...

    hour23 integer default 0,
);

如果您有这样的结构,您可以非常快速地查询在任何给定时间/日期谁登录(或有多少用户登录)。

SQLite 还支持位字段和位数学,因此您还可以用一个整数表示一天中的所有小时,并根据用户活跃的小时数翻转位。这将允许您使用位掩码进行更快的查询,并提供一种将小时转换为儒略日(仅限时间部分)表示的机制和/或使用位计数例程来计算在系统中花费的小时数。

此外,如果您需要实时活动报告,并且您的系统允许您集中展示谁已登录,您可以启动一个每小时更新 hourlyUseLog 记录的批处理过程。

【讨论】:

我认为这是最好的方法。 Martin 的答案比我的要干净得多,但是,它执行与我的相同的 And/Or 操作并且速度一样慢。我想我会走这条路,我认为每小时日志或汇总表是最好的解决方案。谢谢大家【参考方案3】:

我会接受你的“hack”想法,但我不认为它是 hack,真的 - 一个小时结束后,价值永远不会改变,所以为什么不计算一次并完成它?汇总表对此非常有效,无论您跟踪了多少用户,都会产生一致的查询时间。

您可以每小时计算一次,或者,您可以在登录/注销事件时增加每小时的计数器并避免计划任务。

【讨论】:

以上是关于SQL 查询:如果给定两个 DateTime 时间戳,如何确定“在 N 小时内看到过”?的主要内容,如果未能解决你的问题,请参考以下文章

SQL,查找两个给定名称在一列中是不是具有相同数字的查询

sqlserver数据怎么查询两个时间之间的数据

Sql查询以查找两个给定日期之间的视图百分比差异

如何在 SQL 中显示两个给定日期之间的所有日期

SQL 存储过程查询以清除日期字段(如果为 NULL)

给定两个区域的经度和纬度,如何找到它们之间的距离(以米为单位)。如何在 SQL 中查询..?