Sie können dies erreichen, indem Sie einen verschobenen Self-Outer-Join in Verbindung mit einer Variablen verwenden. Siehe diese Lösung:
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
Dies gibt entweder eine 1
zurück oder eine 0
basierend darauf, ob sich ein Benutzer JEDERZEIT an 30 aufeinanderfolgenden Tagen oder länger angemeldet hat in der Vergangenheit.
Die Hauptlast dieser Abfrage liegt wirklich in der ersten Unterauswahl. Sehen wir uns das genauer an, damit wir besser verstehen, wie das funktioniert:
Mit folgendem Beispieldatensatz:
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');
Diese Abfrage:
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
Wird produzieren:
Wie Sie sehen können, verschieben wir uns gerade den verbundenen Tisch um +1 Tag. Für jeden Tag, der nicht auf den vorherigen Tag folgt, ein NULL
Wert wird durch den LEFT JOIN generiert.
Jetzt, wo wir wissen wo die nicht aufeinanderfolgenden Tage sind, können wir eine Variable verwenden, um jeden Satz zu unterscheiden von aufeinanderfolgenden Tagen, indem festgestellt wird, ob die Zeilen der verschobenen Tabelle NULL
sind oder nicht . Wenn sie NULL
sind , die Tage sind nicht aufeinander folgend, also erhöhen Sie einfach die Variable. Wenn sie NOT NULL
sind , dann erhöhen Sie die Variable nicht:
Nachdem wir jeden Satz aufeinanderfolgender Tage mit der inkrementierenden Variable differenziert haben, ist es nur noch eine Frage der Gruppierung nach jedem "Satz" (wie in consec_set
definiert). Spalte) und mit HAVING
So filtern Sie jeden Satz heraus, der weniger als die angegebenen aufeinanderfolgenden Tage hat (in Ihrem Beispiel 30):
Dann schließlich wickeln wir DAS ein abfragen und einfach die Anzahl der Sätze zählen, die 30 oder mehr aufeinanderfolgende Tage hatten. Wenn es einen oder mehrere dieser Sätze gab, geben Sie 1
zurück , andernfalls gib 0
zurück .