編集:最終回答は最下部です。
なぜ多くのSQL質問がテーブル名を忘れていますか?
-- Buggy: should reference (lo.max + 1)
SELECT lo.max + 1 AS min_range
FROM example lo, example hi
WHERE hi.min - (lo.max - 1) >= 40 -- Example won't work with 50
AND NOT EXISTS (SELECT * FROM example AS mid
WHERE mid.min > lo.max
AND mid.max < hi.min
)
れていない節が重要ですEXISTS - それはあなたが唯一の隣接範囲を検討していることを保証します。
「ギャップが十分にある」というケースがあります。内側のSELECTがインデント、最初の直接転写され
...
UNION
SELECT MAX(max)+1
FROM example
WHERE NOT EXISTS(
SELECT lo.max + 1 AS min_range
FROM example lo, example hi
WHERE hi.min - (lo.max - 1) >= 40 -- Example won't work with 50
AND NOT EXISTS (SELECT * FROM example AS mid
WHERE mid.min > lo.max
AND mid.max < hi.min
)
)
:UNION句と「十分に大きな隙間がない」で
名目上、あなたが扱うことができます。
上記のSQLはテストされていません。最初の部分は(特にテストデータ上で)機能しますが、複数の回答を生成することができます。だから、それは(固定、私が思うに、オフ・バイ・2つのエラー)に修正する必要があります
SELECT MIN(lo.max + 1) AS min_range
FROM example lo, example hi
WHERE hi.min - (lo.max + 1) >= 40 -- Example won't work with 50
AND NOT EXISTS (SELECT * FROM example AS mid
WHERE mid.min > lo.max
AND mid.max < hi.min
)
UNION句は、私が期待する答えを生成していない...私にいくつかの悲しみを与えています。
文法的には、私はそれを修正する必要がありました:
SELECT MIN(lo.max + 1) AS min_range
FROM example lo, example hi
WHERE hi.min - (lo.max + 1) >= 40 -- Example won't work with 50
AND NOT EXISTS (SELECT * FROM example AS mid
WHERE mid.min > lo.max
AND mid.max < hi.min
)
UNION
SELECT MAX(solo.max)+1
FROM example AS solo
WHERE NOT EXISTS(
SELECT MIN(lo.max + 1) AS min_range
FROM example lo, example hi
WHERE hi.min - (lo.max - 1) >= 40 -- Example won't work with 50
AND NOT EXISTS (SELECT * FROM example AS mid
WHERE mid.min > lo.max
AND mid.max < hi.min
)
)
これは、(私はおそらく代わりにsolo.max
のexample.max
を書かれている可能性がしかし、それが生産されていないMAXは、列名として使用されているキーワードを使用して問題を回避します。私、私は期待して答え
A UNIONは確かにこの場合には、ORと等価であり、このクエリは、私が欲しい答えを生成するようだ:。
を
OR節がlo.max
であり、hi.max
でないことが重要です。さもなければ、あなたは間違った答えを得る。
OK - MINのSQLのmisdefines行動ので、UNIONのバージョンは、運命にあります。具体的には、一致する行がない場合、MINは行を戻さずにNULL値を持つ単一の行を戻します。つまり、UNIONの最初の句は、行が見つからないときにNULLを返します。 2番目の句はNOT EXISTS内のSELECTからMINを省略することで '固定'できますが、実際には受け入れられない文から2行(NULLと正しい値)で終わります。したがって、ORバージョンが使用するバージョンです.SQLはNULL値で再び噛み付きます。
NULLを厳密に回避するには、FROM句のテーブル式でUNIONをフレーミングします。これは少しシンプルになります:
SELECT MIN(min_range)
FROM (SELECT (lo.max + 1) AS min_range
FROM example lo, example hi
WHERE hi.min - (lo.max + 1) >= 49
AND NOT EXISTS (SELECT * FROM example AS mid
WHERE mid.min > lo.max
AND mid.max < hi.min
)
UNION
SELECT MAX(solo.max + 1) AS min_range
FROM example AS solo
);
UNIONの最初の半分は0を含む任意の数のスロットを返すことができます。 2番目の値は常に(テーブルに行がある限り)値を返します。外側のクエリは、これらの値のうちの最小値を選択します。
このバージョンでは、当然のことながら、行を割り当てるために使用することができます
:
INSERT INTO Example(min, max)
SELECT MIN(min_range) AS min, MIN(min_range) + (50 - 1) AS max
FROM (SELECT (lo.max + 1) AS min_range
FROM example lo, example hi
WHERE hi.min - (lo.max + 1) >= 50
AND NOT EXISTS (SELECT * FROM example mid
WHERE mid.min > lo.max
AND mid.max < hi.min
)
UNION
SELECT MAX(solo.max + 1) AS min_range
FROM example AS solo
);
ここで、特定のアプリケーションとは何ですか?このデータは、あなたの問題を簡単にするために整理されている可能性があります。 –
アプリケーションは、別のテーブルのPK idsのブロックをユーザーに割り当てることです。 IDに割り当てられたブロック内にIDが含まれていない場合、IDを使用することはできません。 Idブロックは後で取り消すことができ、私は再利用したい穴ができます - thx –
実際には、行1と2の間に49の数字(201..249)しかありません。 –