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

PHP MySQL najde nejmenší chybějící číslo ve sloupci

Pokud Order je indexován, můžete získat první chybějící číslo pomocí SQL, aniž byste museli číst celou tabulku pomocí vylučujícího LEFT JOIN:

SELECT t1.`Order` + 1 AS firstMissingOrder
FROM tabla t1
LEFT JOIN tabla t2 ON t2.`Order` = t1.`Order` + 1
WHERE t2.`Order` IS NULL
  AND t1.`Order` <> (SELECT MAX(`Order`) FROM tabla)
ORDER BY t1.`Order`
LIMIT 1

nebo (možná intuitivnější)

SELECT t1.`Order` + 1 AS firstMissingOrder
FROM tabla t1
WHERE NOT EXISTS (
    SELECT 1
    FROM tabla t2
    WHERE t2.`Order` = t1.`Order` + 1
) 
    AND t1.`Order` <> (SELECT MAX(`Order`) FROM tabla)
ORDER BY t1.`Order`
LIMIT 1

Druhý dotaz převede MySQL na první. Jsou si tedy prakticky rovni.

Aktualizovat

Strawberry zmínil dobrý bod:První chybějící číslo může být 1 , což není zahrnuto v mém dotazu. Ale nebyl jsem schopen najít řešení, které je jak - elegantní, tak rychlé.

Mohli bychom jít opačnou cestou a hledat první číslo po mezeře. Ale musel by se znovu připojit ke stolu, aby našel poslední existující číslo před touto mezerou.

SELECT IFNULL(MAX(t3.`Order`) + 1, 1) AS firstMissingOrder
FROM tabla t1
LEFT JOIN tabla t2 ON t2.`Order` = t1.`Order` - 1
LEFT JOIN tabla t3 ON t3.`Order` < t1.`Order`
WHERE t1.`Order` <> 1
  AND t2.`Order` IS NULL
GROUP BY t1.`Order`
ORDER BY t1.`Order`
LIMIT 1

MySQL (v mém případě MariaDB 10.0.19) nedokáže tento dotaz správně optimalizovat. U indexované (PK) 1M řádkové tabulky to trvá asi jednu sekundu, i když první chybějící číslo je 9. Očekával bych, že server přestane hledat po t1.Order=10 , ale zdá se, že to nedělá.

Dalším způsobem, který je rychlý, ale vypadá ošklivě (IMHO), je použít původní dotaz v podvýběru, pouze pokud Order=1 existuje. Jinak vraťte 1 .

SELECT CASE
    WHEN NOT EXISTS (SELECT 1 FROM tabla WHERE `Order` = 1) THEN 1
    ELSE (
        SELECT t1.`Order` + 1 AS firstMissingOrder
        FROM tabla t1   
        LEFT JOIN tabla t2 ON t2.`Order` = t1.`Order` + 1
        WHERE t2.`Order` IS NULL
          AND t1.`Order` <> (SELECT MAX(`Order`) FROM tabla)
        ORDER BY t1.`Order`
        LIMIT 1
    )
END AS firstMissingOrder

Nebo pomocí UNION

SELECT 1 AS firstMissingOrder FROM (SELECT 1) dummy WHERE NOT EXISTS (SELECT 1 FROM tabla WHERE `Order` = 1)
UNION ALL
SELECT firstMissingOrder FROM (
    SELECT t1.`Order` + 1 AS firstMissingOrder
    FROM tabla t1
    LEFT JOIN tabla t2 ON t2.`Order` = t1.`Order` + 1
    WHERE t2.`Order` IS NULL
      AND t1.`Order` <> (SELECT MAX(`Order`) FROM tabla)
    ORDER BY t1.`Order`
    LIMIT 1
) sub
LIMIT 1


  1. Přidání více parametrizovaných proměnných do databáze v c#

  2. PHP MySQL SQL parser (INSERT a UPDATE)

  3. postgresql - nahradí všechny výskyty řetězce v textovém poli

  4. A.* není ve skupině GROUP BY s levým spojením na laravel query builderu