9 ответов:
вот короткая и сладкая версия, использующая оператор "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; $$вы не можете передать их в качестве параметров, вам нужно будет сделать подстановку переменных в строке на стороне клиента, но это самодостаточный запрос, который выдает сообщение только в том случае, если столбец уже существует, добавляет, если он этого не делает, и будет продолжать терпеть неудачу при других ошибках (например, недопустимый тип данных).
Я не рекомендую делать любой из этих методов, если это случайные строки, поступающие из внешний источник. Независимо от того, какой метод вы используете (cleint-side или серверные динамические строки, выполняемые как запросы), это будет рецепт катастрофы, поскольку он открывает вам атаки SQL-инъекции.
С Postgres 9.6 Это можно сделать с помощью опции
if not existsALTER TABLE table_name ADD COLUMN IF NOT EXISTS column_name INTEGER;
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который a) предотвращает инъекцию SQL и b) проверяет правильность обоих сразу (самый дешевый возможный способ). Имя столбца_colвсе еще должен быть дезинфицирован дляEXECUTEСquote_ident(). Более подробное объяснение в этом соответствующем ответе:
format()требуется Postgres 9.1+. Для пожилых людей версии объединяются вручную:EXECUTE 'ALTER TABLE ' || _tbl || ' ADD COLUMN ' || quote_ident(_col) || ' ' || _type;вы можете определить схему вашего имени таблицы, но вам это не нужно.
Вы можете дважды процитировать идентификаторы в вызове функции, чтобы сохранить Camel-case и зарезервированные слова (но вы все равно не должны использовать это).запрос
pg_catalogвместоinformation_schema. Подробное объяснение:блоки, содержащие
EXCEPTIONпункт как в настоящее время принимаются ответ существенно медленнее. Это, как правило, проще и быстрее. документация:Совет: блок, содержащий
EXCEPTIONпредложение значительно больше дорогой, чтобы войти и выйти, чем без одной. Поэтому не используйтеEXCEPTIONбез надобности.
следующий запрос select вернет
true/false, используяEXISTS()():
аргумент EXISTS является произвольным оператором SELECT, или подзапрос. Подзапрос вычисляется, чтобы определить, возвращает ли он все строки. Если он возвращает хотя бы одну строку, результатом EXISTS является "true"; если подзапрос не возвращает строк, результатом 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, но просто немного очистилось. Это достаточно отличается от того, что я не просто хотел "улучшить" его решение (плюс, я думаю, что это грубо).
основное отличие заключается в том, что он использует формат выполнения. Что я думаю, немного чище, но я считаю, что это означает, что вы должны быть на PostgresSQL 9.1 или новее.
Это было проверено на 9.1 и работает. Примечание: это вызовет ошибку, если схема/table_name/или data_type являются недопустимыми. Это может быть "исправлено", но может быть правильным поведением во многих случаях.
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)');
вы можете сделать это следующим образом.
ALTER TABLE tableName drop column if exists columnName; ALTER TABLE tableName ADD COLUMN columnName character varying(8);поэтому он отбросит столбец, если он уже существует. А затем добавьте столбец в определенную таблицу.
может быть добавлен в сценарии миграции вызвать функцию и падение, когда это будет сделано.
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();
просто проверьте, если запрос вернул column_name.
если не выполните что-то вроде этого:
ALTER TABLE x ADD COLUMN y int;где вы положили что-то полезное для 'x' и 'y' и, конечно, подходящий тип данных, где я использовал int.
Comments