Mysql
 sql >> Baza danych >  >> RDS >> Mysql

PHP MySQL znajduje najmniejszą brakującą liczbę w kolumnie

Jeśli Order kolumna jest indeksowana, możesz uzyskać pierwszą brakującą liczbę za pomocą SQL, bez czytania całej tabeli za pomocą wykluczającego 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

lub (może bardziej intuicyjny)

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

Drugie zapytanie zostanie przekonwertowane przez MySQL na pierwsze. Więc są praktycznie równe.

Aktualizacja

Truskawka wspomniała o dobrym spostrzeżeniu:pierwszą brakującą liczbą może być 1 , którego nie obejmuje moje zapytanie. Ale nie udało mi się znaleźć rozwiązania, które jest zarówno eleganckie, jak i szybkie.

Moglibyśmy pójść w odwrotną stronę i wyszukać pierwszą liczbę po przerwie. Ale musiałbym ponownie dołączyć do stołu, aby znaleźć ostatnią istniejącą liczbę przed tą przerwą.

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 (w moim przypadku MariaDB 10.0.19) nie jest w stanie poprawnie zoptymalizować tego zapytania. Trwa to około jednej sekundy na indeksowanej (PK) tabeli wierszy 1M, mimo że pierwszy brakujący numer to 9. Spodziewałbym się, że serwer przestanie szukać po t1.Order=10 , ale wygląda na to, że tego nie robi.

Innym sposobem, który jest szybki, ale wygląda brzydko (IMHO), jest użycie oryginalnego zapytania w podselekcji tylko wtedy, gdy Order=1 istnieje. W przeciwnym razie zwróć 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

Lub używając 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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak zainstalować i skonfigurować mysql 5.6.16 w systemie Windows 7?

  2. Usuń zduplikowane wiersze w tabeli bez klucza podstawowego

  3. Jak obliczyć wartość mnożenia w pętli while w PHP?

  4. Filtruj według formatowania daty i godziny MYSQL

  5. Jak połączyć zapytanie SELECT + WHERE z zapytaniem INSERT?