SQL-запрос: Как определить «видел в течение N часов», если заданы две метки времени DateTime - PullRequest
3 голосов
/ 18 марта 2010

Я пишу приложение на основе статистики из базы данных 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. 1014 *

Любая помощь будет принята с благодарностью!

Ответы [ 3 ]

2 голосов
/ 18 марта 2010

Немного поиграл на 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

Необходимые данные - это день для агрегирования в формате ГГГГ-ММ-ДД. Обратите внимание, что он не возвращает никаких результатов для часов, где счетчик равен нулю.

1 голос
/ 19 марта 2010

Возможно, у вас может быть другая таблица, которая при записи времени выхода из системы заполняет записи, чтобы определить часы, когда пользователь вошел в систему?

Например

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.

1 голос
/ 18 марта 2010

Я бы согласился с вашей идеей "взлома", но я не считаю это взломом, на самом деле - по истечении часа значение никогда не изменится, так почему бы не рассчитать его один раз и покончить с этим ? Сводные таблицы идеально подходят для этого и будут обеспечивать согласованное время запросов независимо от того, сколько пользователей вы отслеживали.

Вы можете рассчитывать их каждый час или, альтернативно, вы можете увеличивать счетчик каждого часа в событиях входа / выхода и избегать запланированных задач.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...