Mysql
 sql >> Datenbank >  >> RDS >> Mysql

PHP MySQL findet die kleinste fehlende Zahl in der Spalte

Wenn die Order Spalte indiziert ist, könnten Sie die erste fehlende Zahl mit SQL erhalten, ohne die vollständige Tabelle mit einem ausschließlichen LEFT JOIN zu lesen:

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

oder (vielleicht intuitiver)

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

Die zweite Abfrage wird von MySQL in die erste umgewandelt. Sie sind also praktisch gleich.

Aktualisieren

Strawberry erwähnte einen guten Punkt:Die erste fehlende Zahl könnte 1 sein , die in meiner Abfrage nicht enthalten ist. Aber ich konnte keine Lösung finden, die sowohl elegant als auch schnell ist.

Wir könnten den umgekehrten Weg gehen und nach einer Lücke nach der ersten Zahl suchen. Sie müssten sich jedoch erneut in die Tabelle einreihen, um die letzte vorhandene Nummer vor dieser Lücke zu finden.

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 meinem Fall MariaDB 10.0.19) kann diese Abfrage nicht richtig optimieren. Es dauert ungefähr eine Sekunde auf einer indizierten (PK) 1M-Zeilentabelle, obwohl die erste fehlende Zahl 9 ist. Ich würde erwarten, dass der Server die Suche nach t1.Order=10 beendet , aber das scheint es nicht zu tun.

Ein anderer Weg, der schnell ist, aber hässlich aussieht (IMHO), besteht darin, die ursprüngliche Abfrage in einer Unterauswahl nur dann zu verwenden, wenn Order=1 existiert. Geben Sie andernfalls 1 zurück .

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

Oder mit 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