sql >> Databáze >  >> RDS >> Mysql

Zkontrolujte x po sobě jdoucích dnů - daná časová razítka v databázi

Můžete toho dosáhnout pomocí posunutého vnějšího spojení ve spojení s proměnnou. Viz toto řešení:

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 vrátí buď 1 nebo 0 podle toho, zda se uživatel přihlásil po dobu 30 po sobě jdoucích dnů nebo déle v KDYKOLI v minulosti.

Hlavní nápor tohoto dotazu je skutečně v prvním podvýběru. Podívejme se blíže, abychom lépe porozuměli tomu, jak to funguje:

S následujícím příkladem datové sady:

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');

Tento dotaz:

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

Vyrobí:

Jak můžete vidět, to, co děláme, je posouvání spojený stůl o +1 den. Pro každý den, který není po sobě jdoucí s předchozím dnem, NULL hodnotu generuje LEFT JOIN.

Nyní, když víme tam, kde jsou dny, které po sobě nejdou, můžeme použít proměnnou k rozlišení každé množiny po sobě jdoucích dnů tím, že zjistí, zda jsou řádky posunuté tabulky NULL . Pokud jsou NULL , dny nejsou po sobě jdoucí, takže stačí zvýšit proměnnou. Pokud jsou NOT NULL , pak nezvyšujte proměnnou:

Poté, co jsme odlišili každou sadu po sobě jdoucích dnů pomocí inkrementační proměnné, je to pak jen jednoduchá záležitost seskupení podle každé "množiny" (jak je definováno v consec_set sloupec) a pomocí HAVING pro odfiltrování jakékoli sady, která má méně než zadané po sobě jdoucí dny (30 ve vašem příkladu):

Pak nakonec zabalíme TO dotaz a jednoduše spočítat počet sad, které měly 30 nebo více po sobě jdoucích dnů. Pokud existuje jedna nebo více těchto sad, vraťte 1 , jinak vraťte 0 .

Podívejte se na podrobnou ukázku SQLFiddle



  1. Sestavení 'Microsoft.SqlServer.Types' verze 10 nebo vyšší nelze nalézt

  2. mysql -> vložit do tbl (vybrat z jiné tabulky) a nějaké výchozí hodnoty

  3. Jak vypsat seznam zastaralých funkcí v instanci SQL Server pomocí T-SQL

  4. Zvláštní ostrovy