Я думаю, что это очень сложно (только для SQL hardcores), но предлагаемая проблема проста. У меня есть таблица журналов, которая регистрирует время соединения и отключения пользователей в отметках времени Unix:
USER_ID | CONN_TIME | DISC_TIME
1 | 1533742332 | 1533744332
2 | 1533744232 | 1533744337
1 | 1533744132 | 1533754332
3 | 1533714332 | 1533744532
3 | 1533744032 | 1533744532
Теперь мне нужен способ группировать строки на 10-минутные интервалы и подсчитывать количество онлайн-пользователей за каждый интервал. Я знаю, как GROUP BY
CONN_TIME
или DISC_TIME
но таким образом я получаю только то, сколько пользователей подключилось или отключилось за десять минут, а не сколько пользователей было в сети (CONN_TIME - DISC_TIME)
.
Мой текущий оператор SQL выглядит следующим образом:
SELECT DATE_FORMAT(FROM_UNIXTIME(CONN_TIME), '%Y-%m-%d %H:%i') as date, COUNT(*) as hits
FROM Stats
GROUP BY FLOOR(CONN_TIME / 600)
Как вы можете видеть, я могу получить только количество просмотров, которое совершенно неудовлетворительно для показа активности пользователя. Я хотел бы знать, был ли он еще в сети в этот период.
Хорошо, через несколько часов я думаю, что у меня, наконец, есть что-то похожее на ответ на вашу проблему. Тем не менее, я не проверил его полностью, поэтому я не могу гарантировать, что он полностью работоспособен и точно так же, как вам это нужно, используйте на свой страх и риск.
Здесь это как скрипка и теперь некоторые объяснения того, что я сделал:
Сначала я создал два представления, первый из которых генерирует числа от 0 до 16, второй генерирует числа от 0 до 256. (Возможно, вы могли бы встроить эти представления, но я этого не сделал).
CREATE OR REPLACE VIEW generator_16
AS SELECT 0 n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL
SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL
SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL
SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL
SELECT 12 UNION ALL SELECT 13 UNION ALL SELECT 14 UNION ALL
SELECT 15;
CREATE OR REPLACE VIEW generator_256
AS SELECT ( ( hi.n << 4 ) | lo.n ) AS n
FROM generator_16 lo, generator_16 hi;
Итак, теперь мы можем генерировать отметки времени, начиная с самого низкого CONN_TIME
до самого высокого DISC_TIME
:
SELECT UNIX_TIMESTAMP(DATE_ADD(@start_date, INTERVAL @i MINUTE)) AS result_date
FROM generator_256
CROSS JOIN
(
SELECT
@i:=-10,
@start_date:= FROM_UNIXTIME(FLOOR((SELECT MIN(CONN_TIME) FROM Stats) / 600) * 600)
) AS init
WHERE UNIX_TIMESTAMP(DATE_ADD(@start_date, INTERVAL@ i: = @i + 10 MINUTE))
BETWEEN(FLOOR((SELECT MIN(CONN_TIME) FROM Stats) / 600) * 600)
AND(CEIL((SELECT MAX(DISC_TIME) FROM Stats) / 600) * 600)
Затем вам нужно будет присоединиться к статистике на нем
JOIN Stats
ON Stats.CONN_TIME = Stats.CONN_TIME # Condition which is always true
AND time.result_date + 600 > Stats.CONN_TIME # Logon is before end of timespan
AND time.result_date < Stats.DISC_TIME # Logoff is after beginning of timespan
и сгруппируйте все это с помощью result_date.
Я пропустил некоторые части в этом текстовом сообщении, я бы предложил посмотреть на скрипку, связанную выше.
Надеюсь это поможет.