Выбор элементов, которые не существуют - PullRequest
0 голосов
/ 25 марта 2009

Я работаю над приложением, которое должно присваивать числовые коды элементам. Эти коды не являются последовательными, и моя идея не состоит в том, чтобы вставлять их в базу данных до тех пор, пока у них не появится соответствующий элемент, но я хотел бы найти, в вопросе sql, не назначенные коды, и я не знаю, как это сделать. *

Есть идеи? Спасибо !!!

Редактировать 1

Таблица может быть такой простой:

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

И мне хотелось бы что-то вроде этого: 1, 4, 5, 6. Без какой-либо другой таблицы.

Редактировать 2

Спасибо за отзыв, ваши ответы были очень полезны.

Ответы [ 3 ]

6 голосов
/ 25 марта 2009

Возвращается 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 голос
/ 28 марта 2009

Вопреки утверждению, что это не может быть сделано с использованием чистого 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, «девять»), он также генерировал диапазон 8-8. Очевидно, у вас также есть два других возможных диапазона подходящего определения «бесконечности»:

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

Обратите внимание:

  1. Если вы используете это регулярно, в ваших списках обычно не будет много пробелов.
  2. Пробелы могут появляться только при удалении строк из таблицы (или при игнорировании диапазонов, возвращаемых этим запросом или его родственниками при вставке данных).
  3. Обычно плохая идея повторно использовать идентификаторы, так что на самом деле эти усилия, вероятно, ошибочны.

Однако, если вы хотите это сделать, вот один из способов сделать это.

0 голосов
/ 25 марта 2009

Это та же идея, которую опубликовал Кассной. Я просто связал все идеи вместе в 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: Это, конечно, не идеальное решение. Если у вас много элементов или вы часто проверяете несуществующий код, это может вызвать проблемы с производительностью.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...