sql >> Database >  >> RDS >> Mysql

PHP MySQL vind kleinste ontbrekende nummer in kolom

Als de Order kolom is geïndexeerd, kunt u het eerste ontbrekende nummer met SQL krijgen, zonder de volledige tabel te lezen met een exclusief 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

of (misschien meer intuïtief)

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

De tweede query wordt door MySQL geconverteerd naar de eerste. Ze zijn dus praktisch gelijk.

Bijwerken

Aardbei noemde een goed punt:het eerste ontbrekende getal kan 1 zijn , die niet wordt behandeld in mijn vraag. Maar ik kon geen oplossing vinden, die zowel elegant als snel is.

We kunnen de andere kant op gaan en zoeken naar het eerste nummer na een gat. Maar zou opnieuw aan de tafel moeten deelnemen om het laatste bestaande nummer voor dat gat te vinden.

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 (in mijn geval MariaDB 10.0.19) kan die query niet goed optimaliseren. Het duurt ongeveer een seconde op een geïndexeerde (PK) 1M rijtabel, ook al is het eerste ontbrekende getal 9. Ik zou verwachten dat de server stopt met zoeken na t1.Order=10 , maar het schijnt dat niet te doen.

Een andere manier, die snel is maar er lelijk uitziet (IMHO), is om de originele query alleen in een subselectie te gebruiken als Order=1 bestaat. Retourneer anders 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

Of met behulp van 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. Voorkom SQL-injectie in JavaScript / Node.js

  2. Hoe vind ik e-mail met meer dan 2 punten met de REGEXP MySQL-functie?

  3. Wat betekent dubbele balken (||) in SQL?

  4. Hoe LocalTime op te slaan in de slaapstand