2009-03-25 7 views
0

要素に数値コードを割り当てる必要があるアプリケーションで作業しています。このコードは連続ではなく、私の考えは、関連する要素があるまでデータベースに挿入することではありませんが、SQLの問題では、割り当てられていないコードを見つけたいと思います。存在しない要素を選択する

アイデア? ありがとうございます!テーブルはとても単純なことができ1

編集:

code | element 
----------------- 
3 | three 
7 | seven 
2 | two 

そして、私はこのような何か希望:1、4、5、6、他のテーブルなしを。フィードバックのための

編集2

おかげで、あなたの答えは非常に参考にされています。これは、すべての非割り当てられたコードを返します

SELECT assigned_codes.code 
FROM codes 
LEFT JOIN 
     assigned_codes 
ON  assigned_codes.code = codes.code 
WHERE codes.code = @code 

:コードが割り当てられていない場合、これはNULLを返します

+0

テーブルの構造を投稿してください。 – Quassnoi

+0

あなたはどのRDBMSを使用していますか? – Quassnoi

+0

私はMS SqlServerを使用しています。 – Alfre2

答えて

6

正確なことを行うには、純粋なSQL方法はありません

SELECT codes.code 
FROM codes 
LEFT JOIN 
     assigned_codes 
ON  assigned_codes.code = codes.code 
WHERE assigned_codes.code IS NULL 

ます欲しいです。

Oracleでは、次の操作を実行できます。

SELECT lvl 
FROM (
     SELECT level AS lvl 
     FROM dual 
     CONNECT BY 
       level <= 
       (
       SELECT MAX(code) 
       FROM elements 
       ) 
     ) 
LEFT OUTER JOIN 
     elements 
ON  code = lvl 
WHERE code IS NULL 

PostgreSQLでは、次の操作を行うことができます。

SELECT lvl 
FROM generate_series(
     1, 
     (
     SELECT MAX(code) 
     FROM elements 
     )) lvl 
LEFT OUTER JOIN 
     elements 
ON  code = lvl 
WHERE code IS NULL 
+0

+1あなたのESPスキルは+1です。 ;) – NotMe

+0

私はすでに私が望むようにすることができないかもしれないと思った。 – Alfre2

0

このQuassnoiが公開された同じ考えを。 私はすべてのアイデアをT-SQLのコードのように一緒にリンクしました。

DECLARE 
    series @table(n int) 

DECLARE 
    max_n int, 
    i int 

SET i = 1 
-- max value in elements table 
SELECT 
    max_n = (SELECT MAX(code) FROM elements) 

-- fill @series table with numbers from 1 to n 
WHILE i < max_n BEGIN 
    INSERT INTO @series (n) VALUES (i) 

    SET i = i + 1 
END 

-- unassigned codes -- these without pair in elements table 
SELECT 
    n 
FROM 
    @series AS series 
    LEFT JOIN 
     elements 
    ON 
     elements.code = series.n 
WHERE 
    elements.code IS NULL 

EDIT: これは、もちろん、理想的なソリューションではありません。多くの要素がある場合や存在しないコードを頻繁に確認すると、パフォーマンスの問題が発生する可能性があります。

1

これは純粋なSQLを使用して行うことができないという主張とは対照的に、ここでは、それがどのように実行できるかを示す反例があります。テーブルの名前は、codevalueのように、value_listであると仮定します(なぜ誰もが質問にテーブル名を含めるのを忘れていますか? ):FROM句で

SELECT b.bottom, t.top 
    FROM (SELECT l1.code - 1 AS top 
      FROM value_list l1 
      WHERE NOT EXISTS (SELECT * FROM value_list l2 
           WHERE l2.code = l1.code - 1)) AS t,  
     (SELECT l1.code + 1 AS bottom 
      FROM value_list l1 
      WHERE NOT EXISTS (SELECT * FROM value_list l2 
           WHERE l2.code = l1.code + 1)) AS b 
    WHERE b.bottom <= t.top 
     AND NOT EXISTS (SELECT * FROM value_list l2 
         WHERE l2.code >= b.bottom AND l2.code <= t.top); 

二つの平行なクエリは、テーブル内の値の範囲内の間隙の上部と下部にそれぞれ値を生成します。これらの2つのリストの外積は、底辺が頂点より大きくないように制限され、底辺と頂点の間の元のリストには値が存在しないように制限されます。

サンプルデータでは、範囲は4-6です。余分な行(9、 'nine')を追加すると、8〜8の範囲も生成されました。明らかに、あなたはまた、 '無限' の、適切な定義については、他の二つの可能な範囲を持っている..

  • -infinityMIN(code)-1
  • MAX(code)+1 ... +infinity

注意をその:

  1. これを日常的に使用しているのであれば、一般にあなたのリストにはギャップがありません。
  2. ギャップは、テーブルから行を削除するとき(またはデータを挿入するときにこのクエリまたはその親戚によって返される範囲を無視するとき)にのみ表示されます。
  3. 識別子を再利用することは通常はお勧めできません。実際、この作業は誤っている可能性があります。

ただし、実行したい場合は、これを行う方法があります。

+0

この表にコード1,000,000の行が1つしかないとします。ギャップを埋めるには、結果の行セットに999,999行が必要です。すべての可能な結合は1行の表を使用しても、使用する結合の数に関係なく、最大で1行しか生成されません。 – Quassnoi

+0

または結果セットに1行が必要です。これは、値1..999,999が再利用可能であることを示します。私が指摘したように、私が与えるクエリは、テーブル内の(複数の)行の間に穴を見つける。それが何かを返す機会を持つためには、複数行がなければなりません。 –

+0

そして、他の可能性については、下位の範囲についてMIN(コード)> 1を持ち、上限の範囲に対応するステートメントをMIN(コード)-1にすることができます。 –

関連する問題