Możesz to osiągnąć za pomocą przesuniętego sprzężenia zewnętrznego w połączeniu ze zmienną. Zobacz to rozwiązanie:
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
To zwróci albo 1
lub 0
na podstawie tego, czy użytkownik logował się przez 30 kolejnych dni lub dłużej o KAŻDEJ CZASO w przeszłości.
Cel tego zapytania leży w pierwszej podselekcji. Przyjrzyjmy się bliżej, abyśmy mogli lepiej zrozumieć, jak to działa:
Z następującym przykładowym zestawem danych:
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');
To zapytanie:
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
Wyprodukuje:
Jak widać, to, co robimy, to przesuwanie dołączył stół o +1 dzień. Dla każdego dnia, który nie jest następujący po dniu poprzednim, NULL
wartość jest generowana przez LEFT JOIN.
Teraz, gdy wiemy tam, gdzie są dni nie następujące po sobie, możemy użyć zmiennej do rozróżnienia każdego zestawu kolejnych dni, wykrywając, czy przesunięte wiersze tabeli są NULL
. Jeśli są NULL
, dni nie następują po sobie, więc po prostu zwiększ zmienną. Jeśli są NOT NULL
, nie zwiększaj wartości zmiennej:
Po rozróżnieniu każdego zestawu kolejnych dni za pomocą zmiennej inkrementacyjnej, wystarczy po prostu grupować według każdego „zestawu” (zgodnie z definicją w consec_set
kolumna) i przy użyciu HAVING
aby odfiltrować dowolny zestaw, który ma mniej niż określone kolejne dni (30 w twoim przykładzie):
W końcu zapakujemy TO zapytanie i po prostu policz liczbę zestawów, które miały 30 lub więcej kolejnych dni. Jeśli był jeden lub więcej z tych zestawów, zwróć 1
, w przeciwnym razie zwróć 0
.