繁体   English   中英

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

[英]SQL Query: How to determine “Seen during N hour” if given two DateTime time stamps?

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

我正在寻找的是一个查询,可以显示哪些用户时间已经登录,在排序线图的12:00和1:00 AM之间的时间way-所以有60个用户登录的(在任何点),在凌晨1点到凌晨2点之间有54位用户登录等...

我希望能够运行这个的SUM,这就是为什么我不能将记录带入.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

我想知道有什么更好的方法可以确定在特定时间内是否已经看到两个DateTimes(最好的情况是,如果它是在多天内记录的话,它已经过了一个小时多少次,但没有必要)?

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

任何帮助将不胜感激!

在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形式聚合的日子。 请注意,它不会返回计数为零的小时数的任何结果。

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

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

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

例如

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记录。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM