3

Я хотел бы сделать Postgres выбрать первый следующий доступный идентификатор так, что не возникает ошибка в следующем случае:сделать Postgres выбрать следующий минимальный доступный идентификатор

CREATE TABLE test(
id serial PRIMARY KEY, 
name varchar 
); 

Тогда:

INSERT INTO test VALUES (2,'dd'); 
INSERT INTO test (name) VALUES ('aa'); 
INSERT INTO test (name) VALUES ('bb'); 

Это даст ошибку ограничения, так как id является основным.
Как я могу сообщить Postgres, чтобы вставить запись со следующим свободным идентификатором?

+0

вам не нужно, чтобы сказать ему, чтобы выбрать. Это будет сделано автоматически. Просто подавите идентификационную информацию. Конечно, если первичный файл является серийным. Postgresql создаст для него последовательность –

+0

@Jorge: Я думаю, что у OP уже есть идентификаторы не по порядку в их базе данных и хочет знать, как исправить ситуацию ... – Kevin

+1

Вам не следует указывать ручные значения для последовательного столбца. Почему вы думаете, что вам нужно это сделать? –

ответ

5

Обычно лучше всего никогда не отменяет значение по умолчанию в колонке serial. Если вам иногда нужно, чтобы предоставить значения идентификатора вручную, замените стандартный DEFAULT пункт nextval('sequence_name') столбца serial с пользовательской функцией, которая опускает существующие значения.

На основе этой фиктивной таблицы:

CREATE TABLE test (test_id serial PRIMARY KEY, test text); 

Функция:

CREATE OR REPLACE FUNCTION f_test_test_id_seq(OUT nextfree bigint) AS 
$func$ 
BEGIN 
LOOP 
    SELECT INTO nextfree val 
    FROM nextval('test_test_id_seq'::regclass) val -- use actual name of sequence 
    WHERE NOT EXISTS (SELECT 1 FROM test WHERE test_id = val); 

    EXIT WHEN FOUND; 
END LOOP; 
END 
$func$ LANGUAGE plpgsql; 

Alter по умолчанию:

ALTER TABLE test ALTER COLUMN test_id SET DEFAULT f_test_test_id_seq(); 

Это не строго serial больше, но serial только удобство в любом случае:

И если вы строите это на вершине serial колонки SEQUENCE является автоматически «принадлежащей» в колонке таблицы, которая, вероятно, хорошая вещь.

Это немного быстрее вариант:

Таблица и имя последовательности жестко заданы здесь. You может легко параметризовать имя последовательности (как в связанном ответе) и даже имя таблицы - и проверить существование с динамическим выражением, используя EXECUTE. Дала бы вам общая функция, но вызов был бы немного дороже.

CREATE OR REPLACE FUNCTION f_nextfree(_tbl regclass 
            , _col text 
            , _seq regclass 
            , OUT nextfree bigint) AS 
$func$ 
BEGIN 
LOOP 
    EXECUTE ' 
    SELECT val FROM nextval($1) val WHERE NOT EXISTS (
     SELECT 1 FROM ' || _tbl || ' WHERE ' || quote_ident(_col) || ' = val)' 
    INTO nextfree 
    USING _seq; 

    EXIT WHEN nextfree IS NOT NULL; 
END LOOP; 
END 
$func$ LANGUAGE plpgsql; 

ALTER TABLE test2 ALTER COLUMN test2_id 
SET DEFAULT f_nextfree('test2', 'test2_id', 'test2_test2_id_seq'); 

SQL Fiddle.

Смежные вопросы