Найти период с последней паузы в MySQL

Мне нужно найти период без пауз в днях с момента последней паузы.
У меня есть следующая таблица:

id | user |    date
-----------------------
1 |  1   | 16.02.2017
1 |  1   | 15.02.2017
1 |  1   | 14.02.2017
1 |  1   | 13.02.2017
1 |  1   | 10.02.2017

Последняя пауза: 10-13 февраля

Последний период без паузы: 4 дня

Я пытался найти разницу между днем, как в этом вопросе, но в результате это было всегда NULL, И это только первая часть. Во второй части я думал использовать что-то вроде рейтинга, но не знаю, сработает ли это.

Я планирую использовать его с PHP 7 + MySQL 5.6.

3

Решение

Я использовал этот образец:

create table if not exists myt(id int, dd date);
insert into myt values
(1, '2017-01-01'),
(1, '2017-01-02'),
(1, '2017-01-03'),
(1, '2017-01-04'),
(1, '2017-01-08'),
(1, '2017-01-09'),
(1, '2017-01-10');

Сначала вы должны установить раздел по дням подряд:

select id, dd,
if(@last_date = '1900-01-01' or datediff(dd, @last_date) = -1, @cn := @cn, @cn := +1) consecutive,
@last_date := dd
from
(select @last_date := '1900-01-01', @cn := 0) x,
(select id, dd
from myt
order by dd desc) y
;

Это возвращает:

+----+---------------------+-------------+
| id | dd                  | consecutive |
+----+---------------------+-------------+
| 1  | 10.01.2017 00:00:00 |      0      |
| 1  | 09.01.2017 00:00:00 |      0      |
| 1  | 08.01.2017 00:00:00 |      0      |
+----+---------------------+-------------+
| 1  | 04.01.2017 00:00:00 |      1      |
| 1  | 03.01.2017 00:00:00 |      1      |
| 1  | 02.01.2017 00:00:00 |      1      |
| 1  | 01.01.2017 00:00:00 |      1      |
+----+---------------------+-------------+

После того, как вы установите раздел, получите MAX и MIN дату для каждого раздела:

select id, min(dd) as ini, max(dd) as fin, datediff(max(dd), min(dd)) as Days
from (
select id, dd,
if(@last_date = '1900-01-01' or datediff(dd, @last_date) = -1, @cn := @cn, @cn := +1) consecutive,
@last_date := dd
from
(select @last_date := '1900-01-01', @cn := 0) x,
(select id, dd
from myt
order by dd desc) y
) z
group by consecutive
;

Результат:

+----+---------------------+---------------------+------+
| id |         ini         |         fin         | Days |
+----+---------------------+---------------------+------+
| 1  | 08.01.2017 00:00:00 | 10.01.2017 00:00:00 |   2  |
+----+---------------------+---------------------+------+
| 1  | 01.01.2017 00:00:00 | 04.01.2017 00:00:00 |   3  |
+----+---------------------+---------------------+------+

Проверь это: http://rextester.com/XMIX80360

2

Другие решения

Попробуйте этот запрос. Он найдет все паузы —

SELECT curr_date, prev_date FROM (
SELECT t1.date curr_date, MAX(t2.date) prev_date FROM periods t1
LEFT JOIN periods t2
ON t1.date > t2.date
GROUP BY t1.date) t
WHERE DATEDIFF(curr_date, prev_date) > 1

Результат:

13-Feb-17   10-Feb-17

Затем добавьте условие / LIMIT, чтобы получить только одну строку.

1

Я пытаюсь написать общий запрос, как,

select count(distinct t1.`date`) from period t1 left join period t2 ON t2.user = t1.user and t1.`date` - INTERVAL 1 DAY = t2.date where t2.id is null

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

0

Этот запрос вернет последнюю дыру:

select
m.`date`,
min(m1.`date`) as next_date,
datediff(min(m1.`date`), m.`date`)+1 as diff
from
mytable m left join mytable m1
on m.`date`<m1.`date`
group by
m.`date`
having
datediff(min(m1.`date`), m.`date`)>1
order by
m.`date` desc
limit 1
0

Следующий запрос:

SELECT MIN(`date`) AS date_start,
MAX(`date`) AS date_end,
MAX(days_diff) AS pause_days,
COUNT(*) + 1 AS period_without_pays
FROM (
SELECT id, user, `date`,
DATE_SUB(`date`, INTERVAL rn DAY) AS group_date,
DATEDIFF(`date`, COALESCE(prevDate, `date`)) AS days_diff
FROM (
SELECT t1.id, t1.user, t1.`date`,
@rn := @rn + 1 AS rn,
(SELECT t2.`date`
FROM mytable AS t2
WHERE t1.id = t2.id AND t1.user = t2.user AND t1.`date` > t2.`date`
ORDER BY `date` DESC LIMIT 1) AS prevDate
FROM mytable AS t1
CROSS JOIN (SELECT @rn := 0) AS v
ORDER BY `date`) AS t) AS x
GROUP BY id, user, group_date, days_diff
HAVING SUM(days_diff) > 0

возвращает:

date_start date_end   pause_days  period_without_pays
-----------------------------------------------------
2017-02-14 2017-02-16 1           4
2017-02-13 2017-02-13 3           2
  • Ряд с pause_days > 1 возвращает дату начала паузы вместе с количеством дней.
  • Ряд с pause_days = 1 возвращает даты начала / окончания острова последовательных записей, имеющих последовательные даты, а также количество этих дат.

Заметка: Приведенный выше запрос работает с предоставленными образцами данных. Возможно, вам придется немного изменить запрос, чтобы приспособить его к сложности фактических данных.

0

Попробуй это:

SET @dateDiff=NULL;SET @dateDiff2='';
SELECT diff.secondDate AS fromDate,diff.initialDate AS toDate, diff.dateDiffR FROM (
SELECT d.date AS initialDate,@dateDiff AS secondDate,IF(@dateDiff IS NULL,@dateDiff:=d.date,0) AS try,
IF(DATE(@dateDiff)!=DATE(d.date),DATEDIFF(d.date,@dateDiff),NULL) AS dateDiffR,
IF(@dateDiff!=@dateDiff2,@dateDiff2:=@dateDiff,0) AS try1,
IF(DATE(@dateDiff)!=DATE(d.date),@dateDiff:=d.date,NULL) AS assign FROM
(SELECT b.date FROM mytable b)d ) diff WHERE diff.dateDiffR>0

это даст вам разницу в дате с диапазоном дат. Если вы получили отрицательный счет, то поменяйте местами даты по параметрам ‘для DATEDIFF;

0

(Опубликовано от имени ОП).

Я адаптировал небольшой запрос от @McNets:

select user, min(dd) as ini, max(dd) as fin, datediff(max(dd), min(dd))+1 as Days, consecutive
from (
select user,dd,
if(@last_date = curdate() or datediff(dd, @last_date) >= -1, @cn := @cn, @cn := @cn+1) consecutive,
@last_date := dd
from
(select @last_date := curdate(), @cn := 0) x,
(select user, date as dd
from myt
where user = %id
order by dd desc) y
) z
group by consecutive
order by CAST(consecutive AS UNSIGNED)

Я добавил фильтр по пользователю, изменил причину ‘> = -1’, чтобы принять использование времени, добавил номер серии и изменил начальную дату с ‘1900-01-01’ на функцию CURDATE () (я не вижу никакого влияния запросить результат этого действия).

Теперь по номеру серии можно найти самую длинную серию и ее даты.

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector