选择不存在的元素

时间:2009-03-25 16:10:02

标签: sql select

我正在开发一个必须为元素分配数字代码的应用程序。这个代码不是连续的,我的想法是不要将它们插入到数据库中,直到有相关元素,但我想在sql中找到未分配的代码,我不知道该怎么做。

有什么想法吗? 感谢!!!

修改1

表格可以这么简单:

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

我想要这样的东西:1,4,5,6。没有任何其他桌子。

修改2

感谢您的反馈,您的回答非常有用。

3 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

与使用纯SQL无法完成的断言相反,这里有一个反例说明如何完成它。 (请注意,我并不是说这很容易 - 但是,这是可能的。)假设表的名称为value_list,其中包含codevalue列,如编辑中所示(为什么每个人都忘记在问题中包含表名吗?):

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子句中的两个并行查询生成的值分别位于表中值范围内的间隙的顶部和底部。然后限制这两个列表的交叉产品,使得底部不大于顶部,并且在底部和顶部之间的原始列表中没有值。

在样本数据上,这会产生4-6的范围。当我添加一个额外的行(9,'九')时,它也生成了8-8的范围。显然,对于'无限'的合适定义,您还有另外两个可能的范围:

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

请注意:

  1. 如果您经常使用此列表,则列表中通常没有太多空白。
  2. 只有在从表中删除行时才会出现间隙(或者在插入数据时忽略此查询或其亲属返回的范围)。
  3. 重复使用标识符通常是一个坏主意,所以实际上这种努力可能是错误的。
  4. 但是,如果你想这样做,这是一种方法。

答案 2 :(得分: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

修改 当然,这不是理想的解决方案。如果您有很多元素或经常检查不存在的代码,则可能会导致性能问题。