Mysql
 sql >> база данни >  >> RDS >> Mysql

Проверете за x последователни дни - дадени времеви печати в базата данни

Можете да постигнете това с помощта на изместено самостоятелно външно присъединяване във връзка с променлива. Вижте това решение:

SELECT IF(COUNT(1) > 0, 1, 0) AS has_consec
FROM
(
    SELECT *
    FROM
    (
        SELECT IF(b.login_date IS NULL, @val:[email protected]+1, @val) AS consec_set
        FROM tbl a
        CROSS JOIN (SELECT @val:=0) var_init
        LEFT JOIN tbl b ON 
            a.user_id = b.user_id AND
            a.login_date = b.login_date + INTERVAL 1 DAY
        WHERE a.user_id = 1
    ) a
    GROUP BY a.consec_set
    HAVING COUNT(1) >= 30
) a

Това ще върне или 1 или 0 въз основа на това дали потребителят е влизал за 30 последователни дни или повече във ВСЯКО ВРЕМЕ в миналото.

Тежестта на тази заявка наистина е в първия подселекция. Нека да разгледаме по-отблизо, за да разберем по-добре как работи това:

Със следния примерен набор от данни:

CREATE TABLE tbl (
  user_id INT,
  login_date DATE
);

INSERT INTO tbl VALUES
(1, '2012-04-01'),  (2, '2012-04-02'),
(1, '2012-04-25'),  (2, '2012-04-03'),
(1, '2012-05-03'),  (2, '2012-04-04'),
(1, '2012-05-04'),  (2, '2012-05-04'),
(1, '2012-05-05'),  (2, '2012-05-06'),
(1, '2012-05-06'),  (2, '2012-05-08'),
(1, '2012-05-07'),  (2, '2012-05-09'),
(1, '2012-05-09'),  (2, '2012-05-11'),
(1, '2012-05-10'),  (2, '2012-05-17'),
(1, '2012-05-11'),  (2, '2012-05-18'),
(1, '2012-05-12'),  (2, '2012-05-19'),
(1, '2012-05-16'),  (2, '2012-05-20'),
(1, '2012-05-19'),  (2, '2012-05-21'),
(1, '2012-05-20'),  (2, '2012-05-22'),
(1, '2012-05-21'),  (2, '2012-05-25'),
(1, '2012-05-22'),  (2, '2012-05-26'),
(1, '2012-05-25'),  (2, '2012-05-27'),
                    (2, '2012-05-28'),
                    (2, '2012-05-29'),
                    (2, '2012-05-30'),
                    (2, '2012-05-31'),
                    (2, '2012-06-01'),
                    (2, '2012-06-02');

Тази заявка:

SELECT a.*, b.*, IF(b.login_date IS NULL, @val:[email protected]+1, @val) AS consec_set
FROM tbl a
CROSS JOIN (SELECT @val:=0) var_init
LEFT JOIN tbl b ON 
    a.user_id = b.user_id AND
    a.login_date = b.login_date + INTERVAL 1 DAY
WHERE a.user_id = 1

Ще произведе:

Както можете да видите, това, което правим, е изместване обединената маса с +1 ден. За всеки ден, който не е последователен с предходния ден, NULL стойността се генерира от LEFT JOIN.

Сега, когато знаем където са непоследователните дни, можем да използваме променлива, за да разграничим всеки набор от последователни дни, като се установи дали изместените редове на таблицата са NULL . Ако са NULL , дните не са последователни, така че просто увеличете променливата. Ако те са NOT NULL , след това не увеличавайте променливата:

След като разграничим всеки набор от последователни дни с увеличаващата се променлива, това е просто въпрос на групиране по всеки "набор" (както е дефинирано в consec_set колона) и с помощта на HAVING за да филтрирате всеки набор, който има по-малко от посочените последователни дни (30 във вашия пример):

След това накрая, увиваме ТО заявка и просто пребройте броя на наборите, които са имали 30 или повече последователни дни. Ако е имало един или повече от тези набори, върнете 1 , в противен случай върнете 0 .

Вижте SQLPiddle демонстрация стъпка по стъпка



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как работи NOT RLIKE в MySQL

  2. Коя SQL заявка е по-добра, MATCH AGAINST или LIKE?

  3. Как да създадете база данни с множество наематели със споделени структури на таблици?

  4. Как да преименувате база данни в MySQL

  5. Как да изчислим общите продажби на месец в MySQL?