2009-03-08 6 views
3

SQL gurusに関する簡単な質問。テーブル内のmin_numbersとmax_numberの間の穴を見つけるSQLクエリ

私は、とりわけ、2列含むテーブルを持っている - 私は、最小値と最大値の数字

Nサイズの最初の穴を見つけたクエリを記述するために失敗したしようとしているmin_numberとMAX_NUMBER を例えば

 min max 
1. 100 200 
2. 250 300 
3. 330 400 

Iは、サイズ50の穴200の1の最大値は、返される行を検索する場合は、行2Sを返す20の穴(すなわち、行2の分の間に50の穴があります)最大300など 適切なサイズがない場合最後のmax(400)が返されます。

おかげで個人的に

+0

ここで、特定のアプリケーションとは何ですか?このデータは、あなたの問題を簡単にするために整理されている可能性があります。 –

+0

アプリケーションは、別のテーブルのPK idsのブロックをユーザーに割り当てることです。 IDに割り当てられたブロック内にIDが含まれていない場合、IDを使用することはできません。 Idブロックは後で取り消すことができ、私は再利用したい穴ができます - thx –

+0

実際には、行1と2の間に49の数字(201..249)しかありません。 –

答えて

0

、私はSQLにすることをやろうではないだろう - AIUIそれが効果的に最悪の場合はO(n^2)でテーブルをスキャンすることなく、異なる行全体で分析を実行することは困難です。しかし、それはストアドプロシージャを使うほうが簡単かもしれません。

私の解決策は、できるだけ新しい行を挿入するたびに、その行の最大値と最小値の差その新しい値をその列に格納した新しい行。

ギャップが十分に大きい最初の行を検索すると、比較的簡単になります。

+0

はい、私はその考え方しかし、それは穴の原因となっている行の削除です。 –

+0

削除するたびに差分値を更新できなかった理由はありますか?しかし、それを行うには前と次の行の両方を考慮する必要があります。 – Alnitak

0

ありがとうございますmodel clause?はいの場合は、それを使ってクエリを実行できます。

1

編集:最終回答は最下部です。

なぜ多くの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.maxexample.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 
      ); 
+0

これは私がSQLでやっていないことを勧めた理由です;-) – Alnitak

+0

OK - SQLは誰もが好きではありません。 SQLでそれを行うための多くの健全な理由があります - そしてそうすることは完全に実現可能です。 –

0

私はそこにあなたのロジック以下のいないよ 「20の穴は、300などの、最大2Sの行を返します」 - ギャップ行2(300)の最大値と行3(330)の最小値の差は30です(最小値または最大値を含む場合は29、そうでない場合は29)。これは、指定した値以上の最初のギャップを探していることを意味しますか、またはギャップは完全一致である必要がありますか?もしそれが "より大きいか等しい"なら、最初に返されるマッチは行1であり、その行と行2の間にはギャップ> 20があるでしょうか?

いずれにしても、テーブルに何らかの並べ替えの行IDがある場合は、このようなことを試してみることができます(RowID、MinVal、MaxVal列のMyTableテーブルを想定しています例):

SELECT TOP 1 
     a.RowID, 
     a.MinVal, 
     a.MaxVal, -- this is the value you want to return 
     ISNULL(b.MinVal, 9999) AS MinVal_NextRow, 
     ISNULL(b.MinVal, 9999) - a.MaxVal AS Diff 
FROM MyTable a 
     LEFT JOIN MyTable b ON a.RowID = (b.RowID - 1) 
WHERE (ISNULL(b.MinVal, 9999) - a.MaxVal) = 20 

この例では、少なくとも20の第1の隙間を探していた場合にギャップが正確に20である最初の行を選択し、その後は変更することができWHERE句に:

WHERE (ISNULL(b.MinVal, 9999) - a.MaxVal) >= 20 

このクエリは、任意の数(999 9)は、行が最後に利用可能なときに使用されます。これは、適切なサイズのギャップがない場合、最後(最大)のMaxValを返します。この数値は、データに合った値(データの値より大きい値)に調整する必要があります。

+0

ROWIDの値は、しばらくして順不同であることがほぼ保証されています。 ROWIDに依存して - 1は偽の結果をもたらすでしょう。 –

+0

あなたはそれを何と考えているのですか?疑問にもRowId列が存在することを示すことさえありません。したがって、このソリューションは、テーブルにRowId列がある場合にのみ "if"を適用します。これは、提供される情報に基づいて実行可能な解決策ですが、明らかにいくつかの明確性があります。 – Nathan

1
SELECT 
    MIN(T1.max_value) 
FROM 
    My_Table T1 
LEFT OUTER JOIN My_Table T2 ON 
    T2.min_value BETWEEN (T1.max_value + 1) AND (T1.max_value + @range) 
WHERE 
    T2.id IS NULL 

私はあなたがMAX_VALUE及びMIN_VALUEの値の範囲は完全に排他したいこと、あなたが割り当てるためのIDを探しているので、推測しています。

NOT EXISTS句を使用して上記のクエリを実行することもできます。両方で試してみて、どちらがあなたに適しているかを見てください。

もうひとつ考慮すべきことは、実際にIDを再利用する必要があるかどうかです。あなたのIDの価値は非常に高くなるでしょうし、あなたの範囲はあなたがそれを行う必要があるほど低いですか?あなたのシステムの詳細はわかりませんが、実際には存在しない問題を解決するために多くの労力を費やし、多くの余分な処理を使用しているようです。

1
select min(n+1) from myTable where n+1 NOT IN (select n from myTable) 
  • Rドハティ
関連する問題