2016-10-30 2 views
0

У меня есть таблица MySQL с тремя столбцами: takenOn (datetime - primary key), sleepDay (date) и type (int). Эта таблица содержит данные моего сна, когда я ложась спать, когда я встаю (с небольшим интервалом).Количество последовательных строк вхождения

В качестве примера, если я пойду спать 29 октября в 11:00 и встаю 30 октября в 6:00, у меня будет 420 записей (7 часов * 60 минут). takenOn будет варьироваться от 2016-10-29 23:00:00 до 2016-10-30 06:00:00. sleepDay будет 2016-10-30 для всех 420 записей. type - это «качество» моего сна (1 = спящий, 2 = беспокойный, 3 = бодрствующий). Я пытаюсь получить, сколько раз Я был беспокойным/бодрствующим, что можно вычислить, посчитав, сколько раз я вижу тип = 2 (или тип = 3) последовательно.

До сих пор я должен выполнить следующий запрос, который работает только на один день. Это правильный/«эффективный» способ сделать это (поскольку этот метод требует, чтобы у меня были данные без каких-либо «зазоров» в takenOn)? Кроме того, как я могу его расширить, чтобы рассчитать все возможные sleepDays?

SELECT 
    sleepDay, 
    SUM(CASE WHEN type = 2 THEN 1 ELSE 0 END) AS TimesRestless, 
    SUM(CASE WHEN type = 3 THEN 1 ELSE 0 END) AS TimesAwake 
FROM 
    (SELECT s1.sleepDay, s1.type 
    FROM sleep s1 
    LEFT JOIN sleep s2 
     ON s2.takenOn = ADDTIME(s1.takenOn, '00:01:00') 
    WHERE 
     (s2.type <> s1.type OR s2.takenOn IS NULL) 
     AND s1.sleepDay = '2016-10-30' 
    ORDER BY s1.takenOn) a 

Я создал SQL скрипку - http://sqlfiddle.com/#!9/b33b4/3

Спасибо!

ответ

1

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

Я представляю здесь альтернативное решение, которое хорошо справится с пробелами в серии и может использоваться более одного дня за раз.

Недостатком является то, что она опирается в большей степени на нестандартных функций MySql (рядный использование переменных):

select sleepDay, 
     sum(type = 2) TimesRestless, 
     sum(type = 3) TimesAwake 
from (
    select @lagDay as lagDay, 
      @lagType as lagType, 
      @lagDay := sleepDay as sleepDay, 
      @lagType := type as type 
    from (select * from sleep order by takenOn) s1, 
      (select @lagDay := '', 
        @lagType := '') init 
    ) s2 
where lagDay <> sleepDay 
    or lagType <> type 
group by sleepDay 

Чтобы увидеть, как это работает, это может помочь выбрать второй select заявление самостоятельно. Внутренний самый select должен иметь предложение order by, чтобы убедиться, что средний запрос обработает записи в этом порядке, что важно для назначений переменных, которые там происходят.

См. Обновленный SQL fiddle.

+0

Awesome! Спасибо, это работает отлично! –

Смежные вопросы