0

要素に数値コードを割り当てる必要があるアプリケーションに取り組んでいます。このコードは連続したものではなく、関連する要素が得られるまでデータベースに挿入しないというのが私の考えですが、SQLの問題で、割り当てられていないコードを見つけたいのですが、その方法がわかりません。

何か案は?ありがとう!!!

編集 1

テーブルは非常に単純です。

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

そして、私はこのようなものが欲しいです: 1, 4, 5, 6. 他のテーブルなし.

編集 2

フィードバックをお寄せいただきありがとうございます。あなたの回答は非常に役に立ちました。

4

3 に答える 3

6

NULLこれは、コードが割り当てられていない場合に返されます。

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

これにより、割り当てられていないすべてのコードが返されます。

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

SQLあなたが望むことを正確に行うための純粋な方法はありません。

では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
于 2009-03-25T16:11:08.480 に答える
1

純粋な SQL を使用してこれを行うことはできないという主張に反して、これがどのように行われるかを示す反例を次に示します。(簡単だとは言いませんでしたが、可能です。)テーブルの名前value_listに列がcodeありvalue、編集に示されていると仮定します(なぜ誰もが質問にテーブル名を含めるのを忘れているのですか?):

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);

from 句の 2 つの並列クエリは、テーブル内の値の範囲のギャップの上部と下部にそれぞれある値を生成します。次に、これら 2 つのリストのクロス積は、下部が上部よりも大きくならないように制限され、元のリストの下部と上部の間に値がないように制限されます。

サンプル データでは、これにより 4 ~ 6 の範囲が生成されます。余分な行 (9, 'nine') を追加すると、8 ~ 8 の範囲も生成されました。明らかに、「無限」の適切な定義には、他にも 2 つの可能な範囲があります。

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

ご了承ください:

  1. これを日常的に使用している場合、通常、リストに多くのギャップはありません。
  2. ギャップは、テーブルから行を削除した場合 (またはデータを挿入するときに、このクエリまたはその関連クエリによって返された範囲を無視した場合) にのみ表示されます。
  3. 通常、識別子を再利用することは悪い考えであるため、実際、この取り組みはおそらく見当違いです。

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

于 2009-03-28T20:09:18.383 に答える
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

編集: もちろん、これは理想的な解決策ではありません。多くの要素がある場合、または存在しないコードを頻繁にチェックする場合、パフォーマンスの問題が発生する可能性があります。

于 2009-03-25T16:51:35.167 に答える