ПРИМЕЧАНИЕ: если вы используете PostgreSQL 9.1 или более поздней версии и можете вносить изменения вне транзакции, см. Этот ответ для более простого подхода.
У меня была такая же проблема несколько дней назад и я нашел этот пост. Так что мой ответ может быть полезен для тех, кто ищет решение :)
Если у вас есть только один или два столбца, которые используют тип перечисления, который вы хотите изменить, вы можете попробовать это. Также вы можете изменить порядок значений в новом типе.
-- 1. rename the enum type you want to change
alter type some_enum_type rename to _some_enum_type;
-- 2. create new type
create type some_enum_type as enum ('old', 'values', 'and', 'new', 'ones');
-- 3. rename column(s) which uses our enum type
alter table some_table rename column some_column to _some_column;
-- 4. add new column of new type
alter table some_table add some_column some_enum_type not null default 'new';
-- 5. copy values to the new column
update some_table set some_column = _some_column::text::some_enum_type;
-- 6. remove old column and type
alter table some_table drop column _some_column;
drop type _some_enum_type;
3-6 следует повторить, если имеется более 1 столбца.
ALTER TYPE
. Но даже до этогоALTER TABLE foo ALTER COLUMN bar TYPE new_type USING bar::text::new_type;
был намного выше.ALTER TABLE some_table ALTER COLUMN some_column TYPE some_enum_type USING some_column::text::some_enum_type;
PostgreSQL 9.1 представляет возможность для типов ALTER Enum:
источник
Возможное решение заключается в следующем; предварительным условием является отсутствие конфликтов в используемых значениях перечисления. (например, при удалении значения enum убедитесь, что это значение больше не используется.)
Также в этом случае порядок столбцов не будет изменен.
источник
pg_enum
которые могут на самом деле сломать вещи и в отличие от транзакцийALTER TYPE ... ADD
.default for column "my_column" cannot be cast automatically to type "my_enum"
. Вам нужно будет сделать следующее:ALTER TABLE "my_table" ALTER COLUMN "my_column" DROP DEFAULT, ALTER COLUMN "my_column" TYPE "my_type" USING ("my_column"::text::"my_type"), ALTER COLUMN "my_column" SET DEFAULT 'my_default_value';
Если вы попадаете в ситуацию, когда вам нужно добавить
enum
значения в транзакцию, например, выполнив ее при переходе с пролета наALTER TYPE
утверждение, вы получите ошибкуERROR: ALTER TYPE ... ADD cannot run inside a transaction block
(см. Выпуск № 350 ), вы можете добавить такие значенияpg_enum
непосредственно в качестве обходного пути (type_egais_units
это имя целиenum
):источник
Дополнение @Dariusz 1
Для Rails 4.2.1 есть этот раздел документации:
== Транзакционные миграции
Если адаптер базы данных поддерживает транзакции DDL, все миграции будут автоматически включены в транзакцию. Однако есть запросы, которые вы не можете выполнить внутри транзакции, и для этих ситуаций вы можете отключить автоматические транзакции.
источник
Из Postgres 9.1 Документация :
Пример:
источник
Отказ от ответственности: я не пробовал это решение, поэтому оно может не работать ;-)
Вы должны смотреть на
pg_enum
. Если вы хотите изменить только метку существующего ENUM, простое ОБНОВЛЕНИЕ сделает это.Чтобы добавить новые значения ENUM:
pg_enum
. Если новое значение должно быть последним, все готово.pg_enum
обратном порядке.Иллюстрация
У вас есть следующий набор меток:
и вы хотите получить:
затем:
затем:
И так далее...
источник
Кажется, я не могу оставить комментарий, поэтому просто скажу, что обновление pg_enum работает в Postgres 8.4. Для настройки наших перечислений я добавил новые значения в существующие типы перечислений с помощью:
Это немного страшно, но имеет смысл, учитывая то, как Postgres на самом деле хранит свои данные.
источник
Работает обновление pg_enum, как и трюк с промежуточным столбцом, выделенный выше. Можно также использовать ИСПОЛЬЗОВАНИЕ магии, чтобы напрямую изменить тип столбца:
Пока у вас нет функций, которые явно требуют или возвращают это перечисление, у вас все хорошо. (pgsql будет жаловаться, когда вы отбрасываете тип, если таковые имеются.)
Также обратите внимание, что PG9.1 вводит оператор ALTER TYPE, который будет работать с перечислениями:
http://developer.postgresql.org/pgdocs/postgres/release-9-1-alpha.html
источник
ALTER TABLE foo ALTER COLUMN bar TYPE test USING bar::text::new_type;
Но в значительной степени не имеет значения сейчас ...... USING bar::type
работал на меня. Мне даже не нужно было указывать::text
.Самое простое: избавиться от перечислений. Их нелегко изменить, и поэтому их следует использовать очень редко.
источник
Не удается добавить комментарий в соответствующее место, но
ALTER TABLE foo ALTER COLUMN bar TYPE new_enum_type USING bar::text::new_enum_type
по умолчанию для столбца не удалось. Мне пришлось:ALTER table ALTER COLUMN bar DROP DEFAULT
;и тогда это сработало.
источник
на всякий случай, если вы используете Rails и у вас есть несколько операторов, вам нужно будет выполнить одно за другим, например:
источник
Вот более общее, но довольно быстрое решение, которое, помимо изменения самого типа, обновляет все столбцы в базе данных, используя его. Этот метод можно применять, даже если новая версия ENUM отличается более чем на одну метку или пропускает некоторые из оригинальных. Код ниже заменяется
my_schema.my_type AS ENUM ('a', 'b', 'c')
наENUM ('a', 'b', 'd', 'e')
:Весь процесс будет выполняться довольно быстро, потому что, если порядок меток сохраняется, фактическое изменение данных не произойдет. Я применил метод к 5 таблицам, используя по
my_type
50 000–70 000 строк в каждой, и весь процесс занял всего 10 секунд.Конечно, функция будет возвращать исключение в случае, если где-то в данных используются метки, отсутствующие в новой версии ENUM, но в такой ситуации что-то должно быть сделано в любом случае заранее.
источник
Для тех, кто ищет решение для транзакций, следующее работает.
Вместо
ENUM
aDOMAIN
следует использовать типTEXT
с ограничением, проверяющим, что значение находится в указанном списке допустимых значений (как предлагается в некоторых комментариях). Единственная проблема заключается в том, что никакое ограничение не может быть добавлено (и, следовательно, ни изменено) к домену, если он используется каким-либо составным типом (документы просто говорят, что это «должно в конечном итоге быть улучшено»). Однако такое ограничение можно обойти, используя ограничение, вызывающее функцию, следующим образом.Ранее я использовал решение, аналогичное принятому ответу, но оно далеко не годится, если рассматривать представления или функции или составные типы (и особенно представления, использующие другие представления с использованием модифицированных ENUM ...). Решение, предложенное в этом ответе, похоже, работает в любых условиях.
Единственным недостатком является то, что никакие проверки не выполняются на существующих данных, когда некоторые разрешенные значения удалены (что может быть приемлемо, особенно для этого вопроса). (Вызов
ALTER DOMAIN test_domain VALIDATE CONSTRAINT val_check
завершается той же ошибкой, что и добавление нового ограничения в домен, используемый составным типом, к сожалению.)Обратите внимание, что небольшая модификация, такая как(работает, на самом деле - это была моя ошибка)CHECK (value = ANY(get_allowed_values()))
, гдеget_allowed_values()
функция вернула список разрешенных значений, не сработает - что довольно странно, поэтому я надеюсь, что предложенное выше решение работает надежно (пока у меня работает ...).источник
Как обсуждалось выше,
ALTER
команда не может быть записана внутри транзакции. Предлагаемый способ - вставить в таблицу pg_enum напрямую, с помощьюretrieving the typelem from pg_type table
иcalculating the next enumsortorder number
;Ниже приведен код, который я использую. (Проверяет, существует ли дублирующее значение перед вставкой (ограничение между enumtypid и enumlabel name)
Обратите внимание, что вашему имени типа предшествует знак подчеркивания в таблице pg_type. Кроме того, имя типа должно быть строчными в предложении where.
Теперь это можно безопасно записать в сценарий переноса БД.
источник
Я не знаю, есть ли другой вариант, но мы можем сбросить значение, используя:
источник
При использовании Navicat вы можете перейти к типам (в представлении -> другие -> типы) - получить представление дизайна типа - и нажать кнопку «добавить метку».
источник
ERROR: cannot drop type foo because other objects depend on it HINT: Use DROP ... CASCADE to drop the dependent objects too.