การเพิ่มค่าใหม่ให้กับประเภท ENUM ที่มีอยู่


208

ฉันมีคอลัมน์ตารางที่ใช้enumประเภท ฉันต้องการอัปเดตenumประเภทนั้นเพื่อให้มีค่าที่เป็นไปได้เพิ่มเติม ฉันไม่ต้องการลบค่าใด ๆ ที่มีอยู่เพียงเพิ่มค่าใหม่ วิธีที่ง่ายที่สุดในการทำเช่นนี้คืออะไร?

คำตอบ:


153

หมายเหตุหากคุณใช้ PostgreSQL 9.1 หรือใหม่กว่าและคุณสามารถทำการเปลี่ยนแปลงนอกธุรกรรมดูคำตอบสำหรับวิธีการที่ง่ายกว่านี้


ฉันมีปัญหาเดียวกันไม่กี่วันที่ผ่านมาและพบโพสต์นี้ ดังนั้นคำตอบของฉันจะมีประโยชน์สำหรับคนที่กำลังมองหาวิธีแก้ปัญหา :)

หากคุณมีคอลัมน์เพียงหนึ่งหรือสองคอลัมน์ที่ใช้ประเภท enum ที่คุณต้องการเปลี่ยนคุณสามารถลองทำสิ่งนี้ได้ นอกจากนี้คุณสามารถเปลี่ยนลำดับของค่าในรูปแบบใหม่

-- 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 คอลัมน์


9
เป็นมูลค่าการกล่าวขวัญว่าสิ่งนี้สามารถทำได้ในการทำธุรกรรมเดียวดังนั้นส่วนใหญ่จะปลอดภัยที่จะทำในฐานข้อมูลการผลิต
David Leppik

52
นี่ไม่ใช่ความคิดที่ดี ตั้งแต่ 9.1 ALTER TYPEคุณสามารถทำมันทั้งหมดที่มี แต่ก่อนหน้านั้นALTER TABLE foo ALTER COLUMN bar TYPE new_type USING bar::text::new_type;มันยอดเยี่ยมมาก
Erwin Brandstetter

1
โปรดทราบว่า Postgres เวอร์ชันเก่าไม่รองรับการเปลี่ยนชื่อประเภท โดยเฉพาะรุ่น Postgres บน Heroku (db ที่แชร์ฉันเชื่อว่าพวกเขาใช้ PG 8.3) ไม่รองรับ
Ortwin Gentz

13
คุณสามารถยุบขั้นตอนที่ 3, 4, 5 และ 6 เข้าด้วยกันเป็นประโยคเดียว:ALTER TABLE some_table ALTER COLUMN some_column TYPE some_enum_type USING some_column::text::some_enum_type;
glyphobet

3
หากทำสิ่งนี้บนตารางที่ใช้งานจริงให้ล็อคตารางระหว่างขั้นตอน ระดับการแยกธุรกรรมเริ่มต้นใน postgresql จะไม่ป้องกันการแทรกแถวใหม่โดยการทำธุรกรรมอื่น ๆ ในระหว่างการทำธุรกรรมนี้ดังนั้นคุณอาจถูกทิ้งให้อยู่ในแถวที่มีประชากรที่ไม่ถูกต้อง
Sérgio Carvalho

422

PostgreSQL 9.1แนะนำความสามารถในการเปลี่ยนแปลงประเภท 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';

1
"enum_type" คืออะไร ชื่อฟิลด์ชื่อ table_field? หรืออย่างอื่น? ฉันจะตีมันได้อย่างไร ฉันมีตาราง "คะแนน" และฉันมีคอลัมน์ "ประเภท" และในการถ่ายโอนข้อมูล db ฉันได้รับนี้: CONSTRAINT levels_type_check ตรวจสอบ ((((ประเภท)) :: ข้อความ = ใด ๆ (ARRAY ['สอบ' :: ตัวละครแตกต่างกัน 'ทดสอบ': : การเปลี่ยนแปลงตัวอักษร, 'พิเศษ' :: การเปลี่ยนแปลงตัวละคร, 'มิดเทอร์ม' :: การเปลี่ยนแปลงตัวอักษร, 'สุดท้าย' :: การเปลี่ยนแปลงตัวอักษร]) :: ข้อความ [])))

1
enum_type เป็นเพียงชื่อ enum ประเภท @mariotanenbaum ของคุณเอง หากคุณ enum ของคุณเป็น "ประเภท" นี่คือสิ่งที่คุณควรใช้
Dariusz

26
เป็นไปได้ไหมที่จะลบออก
Ced

8
การเพิ่มความคิดเห็น @DrewNoakes 'หากคุณใช้ db-migrate (ซึ่งทำงานในการทำธุรกรรม) จากนั้นคุณอาจได้รับข้อผิดพลาด: ข้อผิดพลาด: ALTER TYPE ... ADD ไม่สามารถทำงานภายในบล็อกธุรกรรมการแก้ปัญหาที่นี่ (โดย Hubbitus ): stackoverflow.com/a/41696273/1161370
Mahesh

1
คุณไม่สามารถลบออกได้ดังนั้นจึงเป็นไปไม่ได้ที่การย้ายถิ่นของดาวโจนส์จึงต้องหันไปใช้วิธีการอื่น
Muhammad Umer

65

ทางออกที่เป็นไปได้คือ เงื่อนไขเบื้องต้นคือว่าไม่มีความขัดแย้งในค่า enum ที่ใช้ (เช่นเมื่อลบค่า enum ต้องแน่ใจว่าไม่ได้ใช้ค่านี้อีกต่อไป)

-- 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__;

นอกจากนี้วิธีนี้ลำดับคอลัมน์จะไม่ถูกเปลี่ยนแปลง


1
+1 นี่คือวิธีที่จะไปก่อน 9.1 และยังคงเป็นวิธีที่จะไปสำหรับการลบหรือแก้ไของค์ประกอบ

นี่คือคำตอบที่ดีที่สุดสำหรับโซลูชันของฉันซึ่งเพิ่ม enums ใหม่ให้กับ enum ประเภทที่เรามีอยู่ซึ่งเราจะเก็บรักษา enums เก่าทั้งหมดและเพิ่มใหม่ นอกจากนี้สคริปต์อัปเดตของเรายังเป็นธุรกรรม โพสต์ที่ยอดเยี่ยม!
ดารินปีเตอร์สัน

1
คำตอบที่ยอดเยี่ยม! แฮ็หลีกเลี่ยงรอบที่จริงสามารถทำลายสิ่งและมีการทำธุรกรรมซึ่งแตกต่างจากpg_enum ALTER TYPE ... ADD
NathanAldenSr

4
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';
n1ru4l

30

หากคุณตกอยู่ในสถานการณ์ที่คุณควรเพิ่มenumมูลค่าในการทำธุรกรรม fe ดำเนินการในการโยกย้าย flyway ในALTER TYPEคำสั่งคุณจะได้รับข้อผิดพลาดERROR: ALTER TYPE ... ADD cannot run inside a transaction block(ดูปัญหา flyway # 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 )

9
อย่างไรก็ตามสิ่งนี้จะต้องได้รับอนุญาตจากผู้ดูแลระบบเพราะมันจะเปลี่ยนตารางระบบ
asnelzin

22

การพึ่งพา @Dariusz 1

สำหรับ Rails 4.2.1 มีส่วนของ doc นี้:

== การโยกย้ายธุรกรรม

หากอะแดปเตอร์ฐานข้อมูลรองรับธุรกรรม DDL การโยกย้ายทั้งหมดจะถูกห่อในธุรกรรมโดยอัตโนมัติ มีคิวรี่ที่คุณไม่สามารถดำเนินการภายในธุรกรรมได้และสำหรับสถานการณ์เหล่านี้คุณสามารถปิดธุรกรรมอัตโนมัติได้

class ChangeEnum < ActiveRecord::Migration
  disable_ddl_transaction!

  def up
    execute "ALTER TYPE model_size ADD VALUE 'new_value'"
  end
end

3
นี้! หากคุณกำลังเล่นกับ enums ในรางที่ทันสมัยนี่คือสิ่งที่คุณกำลังมองหา
Eli Albert

1
เยี่ยมมากช่วยฉันมาก!
Dmytro Uhnichenko

10

จาก 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'

3
นอกจากนี้จากเอกสารประกอบ: การเปรียบเทียบที่เกี่ยวข้องกับค่า enum ที่เพิ่มเข้ามานั้นบางครั้งจะช้ากว่าการเปรียบเทียบที่เกี่ยวข้องกับสมาชิกดั้งเดิมของประเภท enum เท่านั้น [.... รายละเอียด snipped ตราบเท่าที่ความคิดเห็น stackoverflow ... ] การชะลอตัวมักจะไม่สำคัญ; แต่ถ้ามันเป็นเรื่องสำคัญประสิทธิภาพที่ดีที่สุดสามารถคืนได้โดยการวางและสร้างชนิด enum ใหม่หรือโดยการดัมพ์และโหลดฐานข้อมูลอีกครั้ง
Aaron Zinman

8

คำเตือน:ฉันยังไม่ได้ลองวิธีนี้จึงอาจใช้ไม่ได้ ;-)

pg_enumคุณควรจะดูที่ หากคุณต้องการเปลี่ยนป้ายกำกับของ ENUM ที่มีอยู่ UPDATE ง่าย ๆ จะดำเนินการ

ในการเพิ่มค่า ENUM ใหม่:

  • pg_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;

และอื่น ๆ ...



5

ฉันไม่สามารถโพสต์ความคิดเห็นได้ดังนั้นฉันจะบอกว่าการอัปเดต pg_enum นั้นใช้งานได้ใน Postgres 8.4 สำหรับวิธีการตั้งค่า enums ของฉันฉันได้เพิ่มค่าใหม่ให้กับประเภท enum ที่มีอยู่ผ่าน:

INSERT INTO pg_enum (enumtypid, enumlabel)
  SELECT typelem, 'NEWENUM' FROM pg_type WHERE
    typname = '_ENUMNAME_WITH_LEADING_UNDERSCORE';

มันน่ากลัวนิดหน่อย แต่มันก็สมเหตุสมผลสำหรับวิธีที่ Postgres เก็บข้อมูลไว้


1
คำตอบที่ดี! ช่วยเพียงเติมท้าย enum ใหม่ แต่เห็นได้ชัดว่าไม่ได้แก้ไขกรณีที่คุณต้องสั่งซื้อใหม่
Mahmoud Abdelkader


นอกจากการขีดเส้นใต้สำหรับชื่อพิมพ์แล้วยังมีการพิจารณาตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ ฉันเกือบจะลืมความพยายามที่จะเลือกโดยพิมพ์ชื่อจากตาราง pg_type
Mahesh

5

การอัปเดต pg_enum ใช้งานได้เช่นเดียวกับเคล็ดลับคอลัมน์กลางที่ไฮไลต์ไว้ด้านบน ท่านสามารถใช้ USING magic เพื่อเปลี่ยนประเภทคอลัมน์ได้โดยตรง:

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;

ตราบใดที่คุณไม่มีฟังก์ชั่นที่ต้องการหรือคืนค่า enum อย่างชัดเจนคุณก็ทำได้ดี (pgsql จะบ่นเมื่อคุณวางประเภทหากมี)

นอกจากนี้โปรดทราบว่า PG9.1 กำลังแนะนำคำสั่ง ALTER TYPE ซึ่งจะทำงานบน enums:

http://developer.postgresql.org/pgdocs/postgres/release-9-1-alpha.html


สามารถดูเอกสารที่เกี่ยวข้องสำหรับ PostgreSQL 9.1 ได้ที่postgresql.org/docs/9.1/static/sql-altertype.html
Wichert Akkerman

1
ALTER TABLE foo ALTER COLUMN bar TYPE test USING bar::text::new_type;แต่ตอนนี้ไม่เกี่ยวข้องส่วนใหญ่ ...
เออร์วิน Brandstetter

ในทำนองเดียวกันกับสิ่งที่เออร์วินพูด... USING bar::typeทำงานให้ฉัน ::textผมไม่ได้มีการระบุ
Daniel Werner

3

ง่ายที่สุด: กำจัด enums พวกเขาจะไม่สามารถแก้ไขได้อย่างง่ายดายและจึงควรมากไม่ค่อยนำมาใช้


2
อาจเป็นข้อ จำกัด การตรวจสอบง่ายจะทำอย่างไร

1
และปัญหาของการจัดเก็บค่าเป็นสตริงคืออะไร?

5
@Grazer: ใน 9.1 คุณสามารถเพิ่มค่าให้กับ enum ( depesz.com/index.php/2010/10/27/ ...... ) - แต่คุณยังไม่สามารถลบค่าเก่าได้

3
@ WillSheppard - ฉันคิดว่าไม่เคย ฉันคิดว่าประเภทที่กำหนดเองตามข้อความที่มีข้อ จำกัด ในการตรวจสอบดีขึ้นมากในทุกกรณี

3
@ JackDouglas - แน่นอน ฉันจะจดโดเมนพร้อมเช็ค enum ทุกวัน

3

ไม่สามารถเพิ่มความคิดเห็นไปยังสถานที่ที่เหมาะสม แต่ALTER TABLE foo ALTER COLUMN bar TYPE new_enum_type USING bar::text::new_enum_typeมีค่าเริ่มต้นในคอลัมน์ล้มเหลว ฉันต้อง:

ALTER table ALTER COLUMN bar DROP DEFAULT;

แล้วมันก็ใช้งานได้


3

ในกรณีที่ถ้าคุณใช้ Rails และคุณมีข้อความมากมายคุณจะต้องดำเนินการทีละรายการเช่น:

execute "ALTER TYPE XXX ADD VALUE IF NOT EXISTS 'YYY';"
execute "ALTER TYPE XXX ADD VALUE IF NOT EXISTS 'ZZZ';"

1

นี่เป็นคำทั่วไปที่กว้างกว่า แต่เป็นวิธีแก้ปัญหาที่ค่อนข้างเร็วซึ่งนอกเหนือจากการเปลี่ยนชนิดตัวเองแล้วจะอัพเดตคอลัมน์ทั้งหมดในฐานข้อมูลโดยใช้ วิธีการนี้สามารถใช้ได้แม้ว่า 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 เก่า พวกเขาจะต้องถูกทิ้งและสร้างใหม่ซึ่งมีความซับซ้อนกว่าพิจารณามุมมองอื่น ๆ ขึ้นอยู่กับคนที่ถูกทิ้ง ไม่ได้พูดเกี่ยวกับประเภทคอมโพสิต ...
Ondřej Bouda

1

สำหรับผู้ที่มองหาวิธีแก้ไขปัญหาในการทำธุรกรรมสิ่งต่อไปนี้ดูเหมือนจะใช้ได้

แทนที่จะเป็นENUMa DOMAINจะใช้กับชนิดที่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;

ก่อนหน้านี้ฉันใช้โซลูชันที่คล้ายกับคำตอบที่ยอมรับ แต่มันก็ยังห่างไกลจากความดีเมื่อมุมมองหรือฟังก์ชั่นหรือประเภทคอมโพสิต (และโดยเฉพาะอย่างยิ่งมุมมองที่ใช้มุมมองอื่น ๆ คำตอบที่เสนอในคำตอบนี้ดูเหมือนจะทำงานภายใต้เงื่อนไขใด ๆ

ข้อเสียเปรียบเพียงอย่างเดียวคือไม่มีการตรวจสอบข้อมูลที่มีอยู่เมื่อค่าที่อนุญาตบางส่วนถูกลบออก (ซึ่งอาจยอมรับได้โดยเฉพาะอย่างยิ่งสำหรับคำถามนี้) (การเรียกเพื่อALTER DOMAIN test_domain VALIDATE CONSTRAINT val_checkจบลงด้วยข้อผิดพลาดเช่นเดียวกับการเพิ่มข้อ จำกัด ใหม่ให้กับโดเมนที่ใช้โดยคอมโพสิตประเภทน่าเสียดาย.)

โปรดทราบว่าการปรับเปลี่ยนเล็กน้อยเช่นCHECK (value = ANY(get_allowed_values()))ที่get_allowed_values()ฟังก์ชั่นกลับรายการค่าที่ได้รับอนุญาตก็จะไม่ทำงาน - ซึ่งเป็นที่แปลกประหลาดมากดังนั้นผมหวังว่าการแก้ปัญหาที่เสนอข้างต้นผลงานได้อย่างน่าเชื่อถือ (มันไม่สำหรับฉันเพื่อให้ห่างไกล ... ) (ใช้งานได้จริง - เป็นข้อผิดพลาดของฉัน)


0

ตามที่กล่าวไว้ข้างต้นALTERคำสั่งไม่สามารถเขียนในการทำธุรกรรม วิธีที่แนะนำคือการแทรกลงในตาราง pg_enum โดยตรงโดยretrieving the typelem from pg_type tableและcalculating the next enumsortorder number;

ต่อไปนี้เป็นรหัสที่ฉันใช้ (ตรวจสอบว่ามีค่าที่ซ้ำกันอยู่ก่อนการแทรก (ข้อ จำกัด ระหว่างชื่อ enumtypid และ enumlabel)

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 จะต้องเป็นตัวพิมพ์เล็กทั้งหมดในตำแหน่ง clause

ตอนนี้สามารถเขียนลงในสคริปต์การย้ายฐานข้อมูลของคุณได้อย่างปลอดภัย


-1

ฉันไม่รู้ว่ามีตัวเลือกอื่น แต่เราสามารถลดค่าโดยใช้:

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;

-2

เมื่อใช้ Navicat คุณสามารถไปที่ประเภท (ภายใต้มุมมอง -> อื่น ๆ -> ประเภท) - รับมุมมองการออกแบบของประเภท - และคลิกปุ่ม "เพิ่มป้ายกำกับ"


1
จะดี แต่ในชีวิตจริงมันไม่มีประโยชน์:ERROR: cannot drop type foo because other objects depend on it HINT: Use DROP ... CASCADE to drop the dependent objects too.
Ortwin Gentz

มันแปลกสำหรับฉัน (ไม่แน่ใจว่าทำไมคุณใช้ลดลงเมื่อ TS ต้องการเพียงเพื่อที่จะเพิ่มมูลค่าให้กับฟิลด์ enum)
jvv

1
ฉันไม่ได้ทำ DROP เป็นพิเศษ แต่ทำตามขั้นตอนของคุณอย่างแน่นอน ฉันถือว่า Navicat ทำ DROP อยู่เบื้องหลังและล้มเหลว ฉันใช้ Navicat 9.1.5 Lite
Ortwin Gentz
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.