Вот краткая и приятная версия с использованием оператора "DO":
DO $$
BEGIN
BEGIN
ALTER TABLE <table_name> ADD COLUMN <column_name> <column_type>;
EXCEPTION
WHEN duplicate_column THEN RAISE NOTICE 'column <column_name> already exists in <table_name>.';
END;
END;
$$
Вы не можете передать их в качестве параметров, вам нужно будет выполнить замену переменной в строке на стороне клиента, но это автономный запрос, который выдает сообщение только в том случае, если столбец уже существует, добавляет, если нет и продолжит сбой при других ошибках (например, недопустимый тип данных).
Я не рекомендую использовать ЛЮБОЙ из этих методов, если это случайные строки, поступающие из внешних источников. Независимо от того, какой метод вы используете (на стороне клиента или на стороне сервера динамические строки, выполняемые как запросы), это будет рецептом катастрофы, поскольку он откроет вам атаки SQL-инъекций.
DO $$ BEGIN BEGIN CREATE INDEX type_idx ON table1 USING btree (type); EXCEPTION WHEN duplicate_table THEN RAISE NOTICE 'Index exists.'; END; END;$$;
такой же подход вCREATE INDEX
;) Спасибо за Ваш ответ,DO $$
ошибкой. Я тоже пробовал,DO $$;
что тоже терпит неудачу, пока я просто не запустил блок,DO $$DECLARE r record;
который приведен в примере в документации разработчиков postgres .END; $$
синтаксической ошибкой (Postgres 9.3), мне пришлось использоватьEND $$;
вместо этогоEXCEPTION
) является немного более общим и может использоваться, например, для задач, не имеющихIF NOT EXISTS
синтаксисаALTER TABLE ... ADD CONSTRAINT
.В Postgres 9.6 это можно сделать с помощью опции
if not exists
ALTER TABLE table_name ADD COLUMN IF NOT EXISTS column_name INTEGER;
источник
ADD CONSTRAINT IF NOT EXISTS
.CREATE OR REPLACE function f_add_col(_tbl regclass, _col text, _type regtype) RETURNS bool AS $func$ BEGIN IF EXISTS (SELECT 1 FROM pg_attribute WHERE attrelid = _tbl AND attname = _col AND NOT attisdropped) THEN RETURN FALSE; ELSE EXECUTE format('ALTER TABLE %s ADD COLUMN %I %s', _tbl, _col, _type); RETURN TRUE; END IF; END $func$ LANGUAGE plpgsql;
Вызов:
SELECT f_add_col('public.kat', 'pfad1', 'int');
Возврат
TRUE
в случае успеха, иначеFALSE
(столбец уже существует).Вызывает исключение для недопустимой таблицы или имени типа.
Почему другая версия?
Это можно сделать с помощью
DO
оператора, ноDO
операторы ничего не могут вернуть. А если он для многократного использования, я бы создал функцию.Я использую типы идентификаторов объектов
regclass
иregtype
для_tbl
и_type
который а) препятствует SQL инъекции и б) проверяет правильность обоих сразу (дешевый возможный путь). Имя столбца_col
имеет еще продезинфицировать дляEXECUTE
сquote_ident()
. Дополнительные объяснения в этом связанном ответе:format()
требуется Postgres 9.1+. Для более старых версий объедините вручную:EXECUTE 'ALTER TABLE ' || _tbl || ' ADD COLUMN ' || quote_ident(_col) || ' ' || _type;
Вы можете указать имя своей таблицы с помощью схемы, но это не обязательно.
Вы можете заключить идентификаторы в двойные кавычки в вызове функции, чтобы сохранить верблюжий регистр и зарезервированные слова (но вы все равно не должны использовать это).
Я запрашиваю
pg_catalog
вместоinformation_schema
. Детальное объяснение:Блоки, содержащие
EXCEPTION
предложение, подобное принятому в настоящее время ответу, работают значительно медленнее. Как правило, это проще и быстрее. Документация:источник
DO
инструкции, небольшая модификация, которую нужно принять,DEFAULT
и это сработало отлично!Следующий запрос выбора вернется
true/false
с использованиемEXISTS()
функции.SELECT EXISTS(SELECT column_name FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'x' AND column_name = 'y');
и используйте следующий динамический оператор SQL, чтобы изменить свою таблицу
DO $$ BEGIN IF NOT EXISTS (SELECT column_name FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'x' AND column_name = 'y') THEN ALTER TABLE x ADD COLUMN y int DEFAULT NULL; ELSE RAISE NOTICE 'Already exists'; END IF; END $$
источник
приведенная ниже функция проверит столбец, если он существует, вернет соответствующее сообщение, иначе он добавит столбец в таблицу.
create or replace function addcol(schemaname varchar, tablename varchar, colname varchar, coltype varchar) returns varchar language 'plpgsql' as $$ declare col_name varchar ; begin execute 'select column_name from information_schema.columns where table_schema = ' || quote_literal(schemaname)||' and table_name='|| quote_literal(tablename) || ' and column_name= '|| quote_literal(colname) into col_name ; raise info ' the val : % ', col_name; if(col_name is null ) then col_name := colname; execute 'alter table ' ||schemaname|| '.'|| tablename || ' add column '|| colname || ' ' || coltype; else col_name := colname ||' Already exist'; end if; return col_name; end; $$
источник
Это в основном решение от sola, но немного поправленное. Это достаточно другое, что я не просто хотел «улучшить» его решение (плюс, я думаю, что это грубо).
Основное отличие состоит в том, что он использует формат EXECUTE. Я думаю, что это немного чище, но я считаю, что это означает, что вы должны быть на PostgresSQL 9.1 или новее.
Это было протестировано на 9.1 и работает. Примечание: это вызовет ошибку, если схема / имя_таблицы / или тип_данных недействительны. Это могло быть «исправлено», но во многих случаях могло быть правильным поведением.
CREATE OR REPLACE FUNCTION add_column(schema_name TEXT, table_name TEXT, column_name TEXT, data_type TEXT) RETURNS BOOLEAN AS $BODY$ DECLARE _tmp text; BEGIN EXECUTE format('SELECT COLUMN_NAME FROM information_schema.columns WHERE table_schema=%L AND table_name=%L AND column_name=%L', schema_name, table_name, column_name) INTO _tmp; IF _tmp IS NOT NULL THEN RAISE NOTICE 'Column % already exists in %.%', column_name, schema_name, table_name; RETURN FALSE; END IF; EXECUTE format('ALTER TABLE %I.%I ADD COLUMN %I %s;', schema_name, table_name, column_name, data_type); RAISE NOTICE 'Column % added to %.%', column_name, schema_name, table_name; RETURN TRUE; END; $BODY$ LANGUAGE 'plpgsql';
Применение:
select add_column('public', 'foo', 'bar', 'varchar(30)');
источник
Для тех, кто использует Postgre 9.5+ (я думаю, что большинство из вас это делает), есть довольно простое и понятное решение.
ALTER TABLE if exists <tablename> add if not exists <columnname> <columntype>
источник
Может быть добавлен в сценарии миграции, вызывающие функцию и отбрасываемую по завершении.
create or replace function patch_column() returns void as $$ begin if exists ( select * from information_schema.columns where table_name='my_table' and column_name='missing_col' ) then raise notice 'missing_col already exists'; else alter table my_table add column missing_col varchar; end if; end; $$ language plpgsql; select patch_column(); drop function if exists patch_column();
источник
В моем случае, из-за того, как это было создано, нашим сценариям миграции немного сложно пересекать разные схемы.
Чтобы обойти это, мы использовали исключение, которое просто перехватило и проигнорировало ошибку. Это также имело приятный побочный эффект - на него было намного проще смотреть.
Однако имейте в виду, что другие решения имеют свои преимущества, которые, вероятно, перевешивают это решение:
DO $$ BEGIN BEGIN ALTER TABLE IF EXISTS bobby_tables RENAME COLUMN "dckx" TO "xkcd"; EXCEPTION WHEN undefined_column THEN RAISE NOTICE 'Column was already renamed'; END; END $$;
источник
Сделать это можно следующим образом.
ALTER TABLE tableName drop column if exists columnName; ALTER TABLE tableName ADD COLUMN columnName character varying(8);
Таким образом, он удалит столбец, если он уже существует. А затем добавьте столбец в конкретную таблицу.
источник
Просто проверьте, вернул ли запрос имя_столбца.
Если нет, выполните что-то вроде этого:
ALTER TABLE x ADD COLUMN y int;
Где вы помещаете что-то полезное для 'x' и 'y' и, конечно же, подходящий тип данных, где я использовал int.
источник