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

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

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

注意:

  1. 如果您经常使用它,那么您的列表中通常不会有很多空白。
  2. 仅当您从表中删除行时才会出现间隙(或者您在插入数据时忽略此查询或其亲属返回的范围)。
  3. 重用标识符通常是一个坏主意,因此实际上这种努力可能是错误的。

但是,如果您想这样做,这是一种方法。

于 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 回答