Условие MySQL GROUP BY на ВСЕХ строках (не ГДЕ или НЕ ИМЕЕТ)

0

Я думаю, что это очень сложно (только для 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)

Как вы можете видеть, я могу получить только количество просмотров, которое совершенно неудовлетворительно для показа активности пользователя. Я хотел бы знать, был ли он еще в сети в этот период.

  • 1
    Подумайте об использовании функции MOD и посмотрите на MySQL «на переменные» (нестандартное расширение), которое позволяет сохранять состояние при выполнении запроса. Вам может даже понадобиться сводная таблица, но также помните, что есть вещи, которые вы не можете сделать с SQL. Вам может понадобиться процедурный язык в какой-то момент.
Теги:
group-by

1 ответ

1
Лучший ответ

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

Здесь это как скрипка и теперь некоторые объяснения того, что я сделал:

Сначала я создал два представления, первый из которых генерирует числа от 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.

Я пропустил некоторые части в этом текстовом сообщении, я бы предложил посмотреть на скрипку, связанную выше.

Надеюсь это поможет.

  • 0
    Ух ты, я потратил часы, пытаясь понять основную логику. Вы монстр SQL. Если я должен быть искренним, я был убежден, что никто не решит это. Спасибо вам большое!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню