Anda dapat melakukannya dengan menggunakan shift self-outer-join dalam hubungannya dengan variabel. Lihat solusi ini:
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
Ini akan mengembalikan 1
atau 0
berdasarkan apakah pengguna telah masuk selama 30 hari berturut-turut atau lebih pada KAPAN SAJA di masa lalu.
Beban dari kueri ini benar-benar ada di subpilihan pertama. Mari kita lihat lebih dekat agar kita dapat lebih memahami cara kerjanya:
Dengan kumpulan data contoh berikut:
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');
Kueri ini:
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
Akan menghasilkan:
Seperti yang Anda lihat, apa yang kami lakukan adalah bergeser tabel bergabung dengan +1 hari. Untuk setiap hari yang tidak berurutan dengan hari sebelumnya, NULL
nilai dihasilkan oleh LEFT JOIN.
Sekarang kita tahu di mana hari yang tidak berurutan, kita dapat menggunakan variabel untuk membedakan setiap set hari berturut-turut dengan mendeteksi apakah baris tabel yang digeser adalah NULL
. Jika mereka NULL
, hari-harinya tidak berurutan, jadi tambahkan saja variabelnya. Jika mereka NOT NULL
, maka jangan tambahkan variabel:
Setelah kita membedakan setiap rangkaian hari berturut-turut dengan variabel kenaikan, selanjutnya tinggal mengelompokkan berdasarkan setiap "set" (sebagaimana didefinisikan dalam consec_set
kolom) dan menggunakan HAVING
untuk memfilter set apa pun yang memiliki kurang dari hari berturut-turut yang ditentukan (30 dalam contoh Anda):
Lalu akhirnya, kita bungkus ITU kueri dan cukup hitung jumlah set yang memiliki 30 hari berturut-turut atau lebih. Jika ada satu atau lebih dari kumpulan ini, kembalikan 1
, jika tidak, kembalikan 0
.