Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

PHP MySQL menemukan nomor hilang terkecil di kolom

Jika Order kolom diindeks, Anda bisa mendapatkan nomor pertama yang hilang dengan SQL, tanpa membaca tabel lengkap menggunakan pengecualian 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

atau (mungkin lebih intuitif)

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

Permintaan kedua akan dikonversi oleh MySQL ke yang pertama. Jadi mereka praktis sama.

Perbarui

Strawberry menyebutkan poin bagus:Angka pertama yang hilang mungkin 1 , yang tidak tercakup dalam kueri saya. Tetapi saya tidak dapat menemukan solusi, yang keduanya - elegan dan cepat.

Kita bisa pergi ke arah yang berlawanan dan mencari nomor pertama setelah celah. Tetapi perlu bergabung dengan tabel lagi untuk menemukan nomor terakhir yang ada sebelum celah itu.

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 (dalam kasus saya MariaDB 10.0.19) tidak dapat mengoptimalkan kueri itu dengan benar. Dibutuhkan sekitar satu detik pada tabel baris 1M yang diindeks (PK), meskipun angka pertama yang hilang adalah 9. Saya berharap server berhenti mencari setelah t1.Order=10 , tapi sepertinya tidak.

Cara lain, yang cepat tetapi terlihat jelek (IMHO), adalah dengan menggunakan kueri asli dalam subpilihan hanya jika Order=1 ada. Jika tidak, kembalikan 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

Atau Menggunakan 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. MySQL-Cluster gagal memulai

  2. EF Core `update-database` di MySql gagal dengan `__EFMigrationsHistory' tidak ada`

  3. Kode Migrasi Spesifik Basis Data

  4. Bagaimana cara menentukan bidang kueri induk dari dalam subkueri di MySQL?

  5. Gabungkan INSERT dan SELECT dalam satu kueri SQL (Zapier)