기존 ENUM 유형에 새 값 추가
는 다을사용테열있다습니이이블는음하를 있습니다.enum
유형을 . 업데이트를 원합니다.enum
type을 입력하여 추가 가능한 값을 지정합니다.기존 값을 삭제하지 않고 새 값만 추가합니다.이것을 하는 가장 간단한 방법은 무엇입니까?
PostgreSQL 9.1에는 ALTER Enum 유형에 대한 기능이 도입되었습니다.
ALTER TYPE enum_type ADD VALUE 'new_value'; -- appends to list
ALTER TYPE enum_type ADD VALUE 'new_value' BEFORE 'old_value';
ALTER TYPE enum_type ADD VALUE 'new_value' AFTER 'old_value';
참고: Postgre를 사용하는 경우SQL 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;
1개 이상의 열이 있을 경우 3-6회 반복해야 합니다.
가능한 해결책은 다음과 같습니다. 전제 조건은 사용된 열거형 값에 충돌이 없다는 것입니다.(예: 열거형 값을 제거할 때는 이 값이 더 이상 사용되지 않는지 확인하십시오.)
-- rename the old enum
alter type my_enum rename to my_enum__;
-- create the new enum
create type my_enum as enum ('value1', 'value2', 'value3');
-- alter all you enum columns
alter table my_table
alter column my_column type my_enum using my_column::text::my_enum;
-- drop the old enum
drop type my_enum__;
이 방법으로도 열 순서는 변경되지 않습니다.
12 그 이후하는 경우에는 Postgres 12(으)로 .ALTER TYPE ... ADD VALUE
거래 내부(해석)
ALTER TYPE ... ADD VALUE( 열거형에 새 값을 추가하는 양식)가 트랜잭션 블록 내에서 실행되면 트랜잭션이 커밋될 때까지 새 값을 사용할 수 없습니다.
따라서 마이그레이션에 해킹이 필요하지 않습니다.
UPD: 여기 예가 있습니다(Nick 덕분에).
ALTER TYPE enum_type ADD VALUE 'new_value';
만약 당신이 상황에 빠진다면 당신은 언제 추가해야 합니다.enum
, ALTER TYPE
할 문 ㅠㅠㅠㅠㅠㅜㅜㅜㅜㅜERROR: ALTER TYPE ... ADD cannot run inside a transaction block
(플라이웨이 이슈 #350 참조) 다음에 이러한 값을 추가할 수 있습니다.pg_enum
해결 방법으로 직접(type_egais_units
는 대상의 입니다.enum
):
INSERT INTO pg_enum (enumtypid, enumlabel, enumsortorder)
SELECT 'type_egais_units'::regtype::oid, 'NEW_ENUM_VALUE', ( SELECT MAX(enumsortorder) + 1 FROM pg_enum WHERE enumtypid = 'type_egais_units'::regtype )
@Dariusz 1 보완
Rails 4.2.1의 경우 다음 문서 섹션이 있습니다.
트랜잭션 마이그레이션
데이터베이스 어댑터가 DDL 트랜잭션을 지원하는 경우 모든 마이그레이션이 자동으로 트랜잭션으로 래핑됩니다.그러나 트랜잭션 내에서 실행할 수 없는 쿼리가 있으며 이러한 상황에서는 자동 트랜잭션을 해제할 수 있습니다.
class ChangeEnum < ActiveRecord::Migration
disable_ddl_transaction!
def up
execute "ALTER TYPE model_size ADD VALUE 'new_value'"
end
end
만일 당신이 Rails를 사용하고 있고 몇 개의 문이 있다면, 당신은 다음과 같이 하나씩 실행해야 할 것입니다.
execute "ALTER TYPE XXX ADD VALUE IF NOT EXISTS 'YYY';"
execute "ALTER TYPE XXX ADD VALUE IF NOT EXISTS 'ZZZ';"
Postgres 9.1 설명서에서:
ALTER TYPE name ADD VALUE new_enum_value [ { BEFORE | AFTER } existing_enum_value ]
예:
ALTER TYPE user_status ADD VALUE 'PROVISIONAL' AFTER 'NORMAL'
고지 사항:이 해결책을 시도해본 적이 없어서 안 될 수도 있어요 ;-)
당신은 이것을 봐야 합니다.pg_enum
기존 ENUM의 레이블만 변경하려는 경우 단순 UPDATE로 변경할 수 있습니다.
새 ENUM 값 추가하기
- 새 을 저새 값을에삽다에 넣습니다.
pg_enum
새 값이 마지막 값이어야 하는 경우에는 끝입니다. - 그렇지 않은 경우(기존 ENUM 값 사이에 새 ENUM 값이 필요함) 테이블의 각 고유 값을 맨 위에서 맨 아래로 업데이트해야 합니다.
- 그런다이변합니다야경에서 .
pg_enum
반대의 순서로
다음과 같은 레이블 세트가 있습니다.
ENUM ('enum1', 'enum2', 'enum3')
다음과 같은 정보를 얻을 수 있습니다.
ENUM ('enum1', 'enum1b', 'enum2', 'enum3')
그러면:
INSERT INTO pg_enum (OID, 'newenum3');
UPDATE TABLE SET enumvalue TO 'newenum3' WHERE enumvalue='enum3';
UPDATE TABLE SET enumvalue TO 'enum3' WHERE enumvalue='enum2';
그러면:
UPDATE TABLE pg_enum SET name='enum1b' WHERE name='enum2' AND enumtypid=OID;
등등...
댓글을 달 수가 없어서 pg_enum 업데이트는 Postgres 8.4에서 작동한다고만 하겠습니다. 우리의 열거형이 설정되는 방식을 위해, 나는 다음을 통해 기존 열거형에 새로운 값을 추가했습니다.
INSERT INTO pg_enum (enumtypid, enumlabel)
SELECT typelem, 'NEWENUM' FROM pg_type WHERE
typname = '_ENUMNAME_WITH_LEADING_UNDERSCORE';
조금 무섭긴 하지만 Postgres가 실제로 데이터를 저장하는 방식을 고려하면 말이 됩니다.
pg_enum 업데이트는 위에서 강조한 중간 열 트릭과 마찬가지로 작동합니다.마법을 사용하여 열의 유형을 직접 변경할 수도 있습니다.
CREATE TYPE test AS enum('a', 'b');
CREATE TABLE foo (bar test);
INSERT INTO foo VALUES ('a'), ('b');
ALTER TABLE foo ALTER COLUMN bar TYPE varchar;
DROP TYPE test;
CREATE TYPE test as enum('a', 'b', 'c');
ALTER TABLE foo ALTER COLUMN bar TYPE test
USING CASE
WHEN bar = ANY (enum_range(null::test)::varchar[])
THEN bar::test
WHEN bar = ANY ('{convert, these, values}'::varchar[])
THEN 'c'::test
ELSE NULL
END;
해당 열거형을 명시적으로 요구하거나 반환하는 함수가 없는 한 좋습니다.(있는 경우 유형을 삭제하면 pgsql이 불만을 제기합니다.)
또한 PG9.1은 열거형에 적용되는 ALTER TYPE 문을 도입하고 있습니다.
http://developer.postgresql.org/pgdocs/postgres/release-9-1-alpha.html
장소에 할 수 해당위치추수가할없다습니주석을에.ALTER TABLE foo ALTER COLUMN bar TYPE new_enum_type USING bar::text::new_enum_type
열에 기본값을 지정하지 못했습니다.해야만 했습니다.
ALTER table ALTER COLUMN bar DROP DEFAULT
;
그리고 효과가 있었습니다.
다음은 좀 더 일반적이지만 작업 속도가 빠른 솔루션으로, 유형 자체를 변경하는 것 외에 데이터베이스의 모든 열을 업데이트합니다.이 메서드는 ENUM의 새 버전이 둘 이상의 레이블이 다르거나 원래 레이블 중 일부가 누락된 경우에도 적용할 수 있습니다.는 아래코대습다니었체되가드를 대체합니다.my_schema.my_type AS ENUM ('a', 'b', 'c')
와 함께ENUM ('a', 'b', 'd', 'e')
:
CREATE OR REPLACE FUNCTION tmp() RETURNS BOOLEAN AS
$BODY$
DECLARE
item RECORD;
BEGIN
-- 1. create new type in replacement to my_type
CREATE TYPE my_schema.my_type_NEW
AS ENUM ('a', 'b', 'd', 'e');
-- 2. select all columns in the db that have type my_type
FOR item IN
SELECT table_schema, table_name, column_name, udt_schema, udt_name
FROM information_schema.columns
WHERE
udt_schema = 'my_schema'
AND udt_name = 'my_type'
LOOP
-- 3. Change the type of every column using my_type to my_type_NEW
EXECUTE
' ALTER TABLE ' || item.table_schema || '.' || item.table_name
|| ' ALTER COLUMN ' || item.column_name
|| ' TYPE my_schema.my_type_NEW'
|| ' USING ' || item.column_name || '::text::my_schema.my_type_NEW;';
END LOOP;
-- 4. Delete an old version of the type
DROP TYPE my_schema.my_type;
-- 5. Remove _NEW suffix from the new type
ALTER TYPE my_schema.my_type_NEW
RENAME TO my_type;
RETURN true;
END
$BODY$
LANGUAGE 'plpgsql';
SELECT * FROM tmp();
DROP FUNCTION tmp();
레이블 순서가 계속되면 실제 데이터 변경이 발생하지 않기 때문에 전체 프로세스가 상당히 빠르게 실행됩니다.나는 5개의 테이블에 방법을 적용했습니다.my_type
각각 50,000-70,000개의 줄이 있고, 전체 과정은 단 10초 만에 끝났습니다.
물론 ENUM의 새 버전에서 누락된 레이블이 데이터의 어딘가에서 사용되는 경우 함수는 예외를 반환하지만, 이러한 상황에서는 사전에 무언가를 수행해야 합니다.
거래 중인 솔루션을 찾는 사람들에게는 다음과 같은 방법이 효과적인 것 같습니다.
대신에ENUM
,aDOMAIN
형식에 사용되어야 합니다.TEXT
일부 주석에서 제안한 대로 값이 지정된 허용 값 목록 내에 있는지 확인하는 제약 조건을 사용합니다.유일한 문제는 도메인이 복합 유형에 의해 사용되는 경우 도메인에 어떠한 제약 조건도 추가할 수 없다는 것입니다(문서에 따르면 이것은 "결국 개선되어야 한다"고만 합니다).그러나 이러한 제한은 다음과 같이 함수를 호출하는 제약 조건을 사용하여 해결할 수 있습니다.
START TRANSACTION;
CREATE FUNCTION test_is_allowed_label(lbl TEXT) RETURNS BOOL AS $function$
SELECT lbl IN ('one', 'two', 'three');
$function$ LANGUAGE SQL IMMUTABLE;
CREATE DOMAIN test_domain AS TEXT CONSTRAINT val_check CHECK (test_is_allowed_label(value));
CREATE TYPE test_composite AS (num INT, word test_domain);
CREATE TABLE test_table (val test_composite);
INSERT INTO test_table (val) VALUES ((1, 'one')::test_composite), ((3, 'three')::test_composite);
-- INSERT INTO test_table (val) VALUES ((4, 'four')::test_composite); -- restricted by the CHECK constraint
CREATE VIEW test_view AS SELECT * FROM test_table; -- just to show that the views using the type work as expected
CREATE OR REPLACE FUNCTION test_is_allowed_label(lbl TEXT) RETURNS BOOL AS $function$
SELECT lbl IN ('one', 'two', 'three', 'four');
$function$ LANGUAGE SQL IMMUTABLE;
INSERT INTO test_table (val) VALUES ((4, 'four')::test_composite); -- allowed by the new effective definition of the constraint
SELECT * FROM test_view;
CREATE OR REPLACE FUNCTION test_is_allowed_label(lbl TEXT) RETURNS BOOL AS $function$
SELECT lbl IN ('one', 'two', 'three');
$function$ LANGUAGE SQL IMMUTABLE;
-- INSERT INTO test_table (val) VALUES ((4, 'four')::test_composite); -- restricted by the CHECK constraint, again
SELECT * FROM test_view; -- note the view lists the restricted value 'four' as no checks are made on existing data
DROP VIEW test_view;
DROP TABLE test_table;
DROP TYPE test_composite;
DROP DOMAIN test_domain;
DROP FUNCTION test_is_allowed_label(TEXT);
COMMIT;
이전에는 승인된 답변과 유사한 솔루션을 사용했지만 뷰 또는 함수 또는 복합 유형(특히 수정된 ENUM을 사용하는 다른 뷰를 사용하는 경우)을 고려하면 좋지 않습니다.이 답변에서 제안된 솔루션은 어떤 조건에서도 작동하는 것으로 보입니다.
유일한 단점은 일부 허용된 값이 제거될 때(특히 이 질문의 경우 허용 가능할 수 있음) 기존 데이터에 대해 검사가 수행되지 않는다는 것입니다.(전화:ALTER DOMAIN test_domain VALIDATE CONSTRAINT val_check
안타깝게도 복합 유형에서 사용하는 도메인에 새 제약 조건을 추가하는 것과 동일한 오류가 발생합니다.)
다음과 같은 약간의 수정 사항에 유의하십시오. CHECK (value = ANY(get_allowed_values()))
어디서 get_allowed_values()
function이 허용된 값 목록을 반환했습니다. 작동하지 않습니다. 매우 이상한 일입니다. 따라서 위에서 제안한 솔루션이 안정적으로 작동하기를 바랍니다(지금까지는 그렇습니다...).
(실제로 효과가 있어요 - 제 실수였어요)
와 같이, 위서논의바같이와한에,,ALTER
트랜잭션 내부에 명령을 쓸 수 없습니다.입니다.retrieving the typelem from pg_type table
그리고.calculating the next enumsortorder number
;
다음은 제가 사용하는 코드입니다. (삽입 전에 중복값이 있는지 확인합니다(enumtypeid와 enumlabel name 사이의 제약 조건)
INSERT INTO pg_enum (enumtypid, enumlabel, enumsortorder)
SELECT typelem,
'NEW_ENUM_VALUE',
(SELECT MAX(enumsortorder) + 1
FROM pg_enum e
JOIN pg_type p
ON p.typelem = e.enumtypid
WHERE p.typname = '_mytypename'
)
FROM pg_type p
WHERE p.typname = '_mytypename'
AND NOT EXISTS (
SELECT * FROM
pg_enum e
JOIN pg_type p
ON p.typelem = e.enumtypid
WHERE e.enumlabel = 'NEW_ENUM_VALUE'
AND p.typname = '_mytypename'
)
pg_type 테이블에는 형식 이름 앞에 밑줄이 추가됩니다.또한 typname은 where 절에서 모두 소문자여야 합니다.
이제 이것을 db마이그레이션 스크립트에 안전하게 쓸 수 있습니다.
DB::statement("ALTER TABLE users DROP CONSTRAINT users_user_type_check");
$types = ['old_type1', 'old_type1', 'new_type3'];
$result = join( ', ', array_map(function ($value){
return sprintf("'%s'::character varying", $value);
}, $types));
DB::statement("ALTER TABLE users ADD CONSTRAINT users_user_type_check CHECK (user_type::text = ANY (ARRAY[$result]::text[]))");
Navicat을 사용할 때 유형(보기 -> 기타 -> 유형)으로 이동하여 유형의 설계 보기를 확인한 후 "라벨 추가" 단추를 클릭할 수 있습니다.
다른 옵션이 있는지 모르겠지만 다음을 사용하여 값을 낮출 수 있습니다.
select oid from pg_type where typname = 'fase';'
select * from pg_enum where enumtypid = 24773;'
select * from pg_enum where enumtypid = 24773 and enumsortorder = 6;
delete from pg_enum where enumtypid = 24773 and enumsortorder = 6;
가장 간단한 것은 열거형을 없애는 것입니다.쉽게 수정할 수 없기 때문에 거의 사용하지 않아야 합니다.
언급URL : https://stackoverflow.com/questions/1771543/adding-a-new-value-to-an-existing-enum-type
'itsource' 카테고리의 다른 글
잘못된 병합을 수정하고 수정된 병합에 좋은 커밋을 재생하려면 어떻게 해야 합니까? (0) | 2023.05.27 |
---|---|
Excel VBA에서 문자열을 URL로 인코딩하려면 어떻게 해야 합니까? (0) | 2023.05.27 |
MongoDB: 배열 일치 매개변수에서 하위 문서 찾기 (0) | 2023.05.22 |
Angular 2에서 경로 간 이동 시 로딩 화면 표시 (0) | 2023.05.22 |
ES6 모듈을 사용하는 경우 Node.js의 __dirname에 대한 대안 (0) | 2023.05.22 |