Order
の場合 列にインデックスが付けられている場合、除外するLEFT JOINを使用してテーブル全体を読み取ることなく、SQLで最初に欠落している数値を取得できます。
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
または(おそらくもっと直感的)
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
2番目のクエリはMySQLによって最初のクエリに変換されます。したがって、それらは実質的に同等です。
更新
ストロベリーは良い点を述べました:最初に欠落している番号は1
かもしれません 、これは私のクエリではカバーされていません。しかし、私は解決策を見つけることができませんでした。それは、エレガントで高速です。
逆の方法で、ギャップの後の最初の番号を検索することもできます。ただし、そのギャップの前にある最後の既存の番号を見つけるには、テーブルに再度参加する必要があります。
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(私の場合はMariaDB 10.0.19)は、そのクエリを適切に最適化できません。最初に欠落している番号が9であっても、インデックス付き(PK)1M行テーブルでは約1秒かかります。t1.Order=10
の後でサーバーが検索を停止すると予想されます。 、しかしそれをしないのは継ぎ目です。
高速ですが見苦しい(IMHO)別の方法は、Order=1
の場合にのみ、副選択で元のクエリを使用することです。 存在します。それ以外の場合は、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
または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