Как создать последовательность, если она не существует
Я попытался использовать код из Проверить, существует ли последовательность в Postgres (plpgsql).
Чтобы создать последовательность, если она не существует. Запуск этого кода два раза вызывает исключение:
последовательность... уже существует.
Как создать последовательность только в том случае, если она не существует?
Если последовательность не существует, ни одно сообщение не должно быть записано и не должно возникать ошибки, поэтому я не могу использовать хранимую процедуру в другом ответе на этот вопрос, так как он записывает сообщение в файл журнала каждый раз, если последовательность существует.
do $$
begin
SET search_path = '';
IF not EXISTS (SELECT * FROM pg_class
WHERE relkind = 'S'
AND oid::regclass::text = 'firma1.' || quote_ident('myseq'))
THEN
SET search_path = firma1,public;
create sequence myseq;
END IF;
SET search_path = firma1,public;
end$$;
select nextval('myseq')::int as nr;
Ответы
Ответ 1
Postgres 9.5 +
IF NOT EXISTS
был добавлен в CREATE SEQUENCE
в Postgres 9.5. Это простое решение:
CREATE SEQUENCE IF NOT EXISTS myschema.myseq;
Но рассмотрите детали устаревшего ответа в любом случае...
Знаете ли вы о столбцах serial
, правильно?
Postgres 9.4 и старше
Имя последовательности конфликтует с именами объектов нескольких типов, а не только последовательностями. Руководство:
Имя последовательности должно отличаться от имени любого другого , таблица, индекс, представление или внешняя таблица в той же схеме.
Смелый акцент мой.
Итак, у вас есть три случая:
- Имя не существует. → Создать последовательность.
- Последовательность с тем же именем существует. → Не делай ничего? Любой выход? Любой журнал?
- Существует другой конфликтный объект с тем же именем. → Сделайте что-нибудь? Любой выход? Любой журнал?
Вам нужно указать, что вы хотите сделать в любом из этих случаев. Оператор DO
может выглядеть следующим образом:
DO
$do$
DECLARE
_kind "char";
BEGIN
SELECT relkind
FROM pg_class
WHERE oid = 'myschema.myseq'::regclass -- sequence name, optionally schema-qualified
INTO _kind;
IF NOT FOUND THEN -- name is free
CREATE SEQUENCE myschema.myseq;
ELSIF _kind = 'S' THEN -- sequence exists
-- do nothing?
ELSE -- object name exists for different kind
-- do something!
END IF;
END
$do$;
Типы объектов (relkind
) в pg_class
в соответствии с руководством:
r = обычная таблица
i = индекс
S = последовательность v = просмотр
m = материализованное представление
c = композитный тип
t = таблица TOAST
f = внешняя таблица
по теме:
Ответ 2
Я пошел другим путем: просто поймайте исключение:
DO
$$
BEGIN
CREATE SEQUENCE myseq;
EXCEPTION WHEN duplicate_table THEN
-- do nothing, it already there
END
$$ LANGUAGE plpgsql;
Хорошим преимуществом этого является то, что вам не нужно беспокоиться о том, какова ваша текущая схема.
Ответ 3
Если вам не нужно сохранять потенциально существующую последовательность, вы можете просто отбросить ее, а затем воссоздать ее:
DROP SEQUENCE IF EXISTS id_seq;
CREATE SEQUENCE id_seq;
Ответ 4
Postgres не имеет CREATE SEQUENCE IF NOT EXISTS
, и если таблица имеет значение по умолчанию, используя последовательность, если вы просто отбрасываете последовательность, вы можете получить сообщение об ошибке:
ОШИБКА: невозможно удалить последовательность (имя_последовательности), потому что другие объекты зависят от нее Состояние SQL: 2BP01
Для меня это может помочь:
ALTER TABLE <tablename> ALTER COLUMN id DROP DEFAULT;
DROP SEQUENCE IF EXISTS <sequence_name>;
CREATE sequence <sequence_name>;
Ответ 5
Информация о последовательностях может быть получена из information_schema.sequences
(ссылка)
Попробуйте что-то вроде этого (untested):
...
IF not EXISTS (SELECT * FROM information_schema.sequences
WHERE sequence_schema = 'firma1' AND sequence_name = 'myseq') THEN
...
Ответ 6
У меня есть функция для очистки всех таблиц в приложении базы данных в любое время. Он строит динамически, но суть в том, что он удаляет все данные из каждой таблицы и сбрасывает последовательность.
Это код для reset последовательности одной из таблиц:
perform relname from pg_statio_all_sequences where relname = 'privileges_id_seq';
if found then
select setval ('privileges_id_seq',1, false) into i_result;
end if;
Надеюсь, что это поможет,
Loek
Я использую postgres 8.4, я вижу, что вы используете 9.2. Может быть разница в том, где хранится информация.