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