ฉันจะลบค่าประเภท enum ที่ฉันสร้างใน postgresql ได้อย่างไร
create type admin_level1 as enum('classifier', 'moderator', 'god');
เช่นฉันต้องการลบออกmoderator
จากรายการ
ฉันไม่พบสิ่งใดในเอกสาร
ฉันใช้ Postgresql 9.3.4
create xxx
มีdrop xxx
ฉันจะลบค่าประเภท enum ที่ฉันสร้างใน postgresql ได้อย่างไร
create type admin_level1 as enum('classifier', 'moderator', 'god');
เช่นฉันต้องการลบออกmoderator
จากรายการ
ฉันไม่พบสิ่งใดในเอกสาร
ฉันใช้ Postgresql 9.3.4
create xxx
มีdrop xxx
คำตอบ:
คุณลบ (วาง) ประเภท enum เหมือนกับประเภทอื่น ๆ ด้วยDROP TYPE
:
DROP TYPE admin_level1;
มันเป็นไปได้ที่คุณจริงถามเกี่ยวกับวิธีการลบค่าบุคคลจากประเภท enum ? ถ้าเป็นเช่นนั้นคุณทำไม่ได้ ไม่รองรับ :
แม้ว่า
enum
ประเภทจะมีจุดประสงค์หลักสำหรับชุดค่าคงที่ แต่ก็มีการสนับสนุนสำหรับการเพิ่มค่าใหม่ให้กับประเภท enum ที่มีอยู่และสำหรับการเปลี่ยนชื่อค่า (ดูALTER TYPE
) ค่าที่มีอยู่ไม่สามารถลบออกจากชนิด enum ได้และไม่สามารถเปลี่ยนแปลงลำดับการเรียงของค่าดังกล่าวได้โดยไม่ต้องวางและสร้างประเภท enum ขึ้นมาใหม่
คุณต้องสร้างประเภทใหม่โดยไม่มีค่าแปลงการใช้งานประเภทเก่าทั้งหมดที่มีอยู่เพื่อใช้ประเภทใหม่จากนั้นจึงปล่อยประเภทเก่า
เช่น
CREATE TYPE admin_level1 AS ENUM ('classifier', 'moderator');
CREATE TABLE blah (
user_id integer primary key,
power admin_level1 not null
);
INSERT INTO blah(user_id, power) VALUES (1, 'moderator'), (10, 'classifier');
ALTER TYPE admin_level1 ADD VALUE 'god';
INSERT INTO blah(user_id, power) VALUES (42, 'god');
-- .... oops, maybe that was a bad idea
CREATE TYPE admin_level1_new AS ENUM ('classifier', 'moderator');
-- Remove values that won't be compatible with new definition
-- You don't have to delete, you might update instead
DELETE FROM blah WHERE power = 'god';
-- Convert to new type, casting via text representation
ALTER TABLE blah
ALTER COLUMN power TYPE admin_level1_new
USING (power::text::admin_level1_new);
-- and swap the types
DROP TYPE admin_level1;
ALTER TYPE admin_level1_new RENAME TO admin_level1;
(psycopg2.InternalError) ALTER TYPE ... ADD cannot run inside a transaction block
เขียนได้ดีมากที่นี่:
http://blog.yo1.dog/updating-enum-values-in-postgresql-the-safe-and-easy-way/
เปลี่ยนชื่อประเภทที่มีอยู่
ALTER TYPE status_enum RENAME TO status_enum_old;
สร้างประเภทใหม่
CREATE TYPE status_enum AS ENUM('queued', 'running', 'done');
อัปเดตคอลัมน์เพื่อใช้ประเภทใหม่
ALTER TABLE job ALTER COLUMN job_status TYPE status_enum USING job_status::text::status_enum;
ลบประเภทเก่า
DROP TYPE status_enum_old;
หากคุณต้องการลบรายการประเภท enum คุณต้องดำเนินการบนตารางระบบของ PostgreSQL
ด้วยคำสั่งนี้คุณสามารถแสดงประเภท enum รายการทั้งหมด
เลือก * จาก pg_enum;
จากนั้นตรวจสอบว่าค่าที่ค้นหานั้นไม่ซ้ำกัน เพื่อเพิ่มความเป็นเอกลักษณ์ระหว่างการกำจัด rekoru จะต้องผ่าน 'enumtypid' นอกเหนือจาก 'enumlabel'
คำสั่งนี้จะลบรายการในประเภท enum โดยที่ 'unique' คือค่าของคุณ
ลบจาก pg_enum en WHERE en.enumtypid = 124 AND en.enumlabel = 'unique';
หมายเหตุ ต้องใช้ตัวอย่างที่ฉันอธิบายไว้เมื่อเราเพิ่มค่าใหม่ให้กับประเภท enum โดยบังเอิญ แต่เรายังไม่ได้ใช้ที่ใดในฐานข้อมูล
ERROR: invalid internal value for enum
และให้ผลลัพธ์NO )
DELETE FROM pg_enum en WHERE en.enumtypid=124 AND en.enumlabel='unigue';
NOTE ควรอยู่ใน BOLD ไม่ใช่คำสั่ง หากคุณใช้ค่าในบางตารางคุณจะไม่สามารถกู้คืนได้ คุณไม่สามารถอัปเดตแถวที่มีค่าคุณไม่สามารถแปลงได้ วิธีเดียวคือลบทั้งแถว
สำหรับผู้ที่ต้องการแก้ไขค่า enum การสร้างใหม่ดูเหมือนจะเป็นวิธีเดียวที่ใช้ได้ผลและปลอดภัย
ประกอบด้วยในการแปลงคอลัมน์ enum เป็นรูปแบบสตริงชั่วคราวสร้าง enum ใหม่แล้วแปลงคอลัมน์สตริงกลับเป็นชนิด enum
นี่คือตัวอย่าง:
ALTER TABLE your_schema.your_table ALTER COLUMN your_column TYPE varchar(255);
ALTER TABLE your_schema.your_table ALTER COLUMN your_column SET DEFAULT('your_default_enum_value');
DROP TYPE your_schema.your_enum_name;
CREATE TYPE your_schema.your_enum_name AS ENUM ('enum1', 'enum2', 'enum3');
ALTER TABLE your_schema.your_table ALTER your_column DROP DEFAULT;
ALTER TABLE your_schema.your_table ALTER COLUMN your_column TYPE your_schema.your_enum_name USING your_enum_name::your_schema.your_column;
ALTER TABLE your_schema.your_table ALTER COLUMN your_column SET DEFAULT('your_default_enum_value');
ALTER TABLE your_schema.your_table ALTER COLUMN your_column TYPE your_schema.your_enum_name USING your_enum_name::your_schema.your_column;
ควรจะเป็นALTER TABLE your_schema.your_table ALTER COLUMN your_column TYPE your_schema.your_enum_name USING your_schema.your_column::your_enum_name;
ใช้แบบสอบถามต่อไปนี้เพื่อลบค่า ENUM จากประเภท Postgresql
DELETE FROM pg_enum
WHERE enumlabel = 'moderator'
AND enumtypid = ( SELECT oid FROM pg_type WHERE typname = 'admin_level1');
เพียงแค่ข้อมูลสำหรับประเภทและมูลค่าอะไร
DELETE FROM pg_enum
WHERE enumlabel = 'ENUM_VALUE'
AND enumtypid = ( SELECT oid FROM pg_type WHERE typname = 'ENUM_TYPE')
คุณควรเปลี่ยนค่าที่มีอยู่เป็นค่าอื่น สำหรับสิ่งนั้นหากคุณต้องการเพิ่มค่าใหม่ให้ใช้:
ALTER TYPE **ENUM_TYPE** ADD VALUE '**ENUM_VALUE2**';
ก่อนที่จะลบให้อัปเดตค่าประเภทเป็นค่าประเภทใหม่หรือค่าที่มีอยู่
SELECT oid FROM pg_type WHERE typname = 'enum_type'
วิธีการแบบเป็นโปรแกรมในการดำเนินการมีดังนี้ ขั้นตอนทั่วไปเช่นเดียวกับที่ระบุในhttps://stackoverflow.com/a/47305844/629272นั้นเหมาะสม แต่เป็นขั้นตอนแบบแมนนวลมากกว่าที่เหมาะสมสำหรับจุดประสงค์ของฉัน (การเขียนการย้ายข้อมูลแบบไม่ใช้สัญญาณ) my_type
, my_type_old
และvalue_to_delete
ควรของหลักสูตรจะมีการเปลี่ยนแปลงตามความเหมาะสม
เปลี่ยนชื่อประเภทของคุณ
ALTER TYPE my_type RENAME TO my_type_old;
สร้างประเภทใหม่ด้วยค่าจากประเภทเก่าของคุณยกเว้นประเภทที่คุณต้องการลบ
DO $$
BEGIN
EXECUTE format(
'CREATE TYPE my_type AS ENUM (%s)',
(
SELECT string_agg(quote_literal(value), ',')
FROM unnest(enum_range(NULL::my_type_old)) value
WHERE value <> 'value_to_delete'
)
);
END $$;
เปลี่ยนคอลัมน์ที่มีอยู่ทั้งหมดซึ่งใช้ประเภทเก่าเพื่อใช้คอลัมน์ใหม่
DO $$
DECLARE
column_data record;
table_name varchar(255);
column_name varchar(255);
BEGIN
FOR column_data IN
SELECT cols.table_name, cols.column_name
FROM information_schema.columns cols
WHERE udt_name = 'my_type_old'
LOOP
table_name := column_data.table_name;
column_name := column_data.column_name;
EXECUTE format(
'
ALTER TABLE %s
ALTER COLUMN %s
TYPE my_type
USING %s::text::my_type;
',
table_name, column_name, column_name
);
END LOOP;
END $$;
ลบประเภทเก่า
DROP TYPE my_type_old;
หากชุดข้อมูลของคุณไม่ใหญ่มากคุณสามารถถ่ายโอนข้อมูลด้วยการ--column-inserts
แก้ไขการถ่ายโอนข้อมูลด้วยโปรแกรมแก้ไขข้อความลบค่าและนำเข้าการถ่ายโอนข้อมูลอีกครั้ง
มีปัญหาเดียวกันในเวอร์ชัน 10 postgres. การลบต้องใช้ขั้นตอนบางอย่างและหากลำดับไม่ถูกต้องก็จะมีโอกาสที่ตารางจะถูกล็อคไม่ให้อ่านได้
เขียนสคริปต์ที่สะดวกในการลบ พิสูจน์ประสิทธิภาพมาแล้วหลายครั้ง อย่างไรก็ตามโพรซีเดอร์นี้เกี่ยวข้องกับการแทนที่ค่าที่ถูกลบด้วยค่าใหม่ (อาจเป็น NULL หากฟิลด์ตารางอนุญาต)
ในการใช้งานคุณต้องกรอก 3 ค่า
DO $$
DECLARE
enumTypeName VARCHAR := 'enum_name'; -- VALUE #1, set yor value!
enumOldFieldValue varchar := 'old_enum_value'; -- VALUE #2, enum value which have to be deleted
enumNewFieldValue varchar := null; -- VALUE #3, which new value must be instead of deleted
sql varchar:='';
rec record;
BEGIN
raise info 'Check on old and new enum values.';
IF exists(select * FROM pg_enum -- check existing of OLD enum value
WHERE enumtypid = (select oid from pg_type where typName=cast(enumTypeName as varchar) limit 1) and enumlabel=cast(enumOldFieldValue as varchar))
AND
(exists(select *
FROM pg_enum -- check existing of NEW enum value
WHERE enumtypid = (select oid from pg_type where typName = cast(enumTypeName as varchar) limit 1)
and enumlabel = cast(enumNewFieldValue as varchar))
OR
enumNewFieldValue IS NULL)
THEN
raise info 'Check passed!';
-- selecting all tables with schemas which has column with enum relation
create temporary table tmp_table_names
as SELECT concat(c.table_schema,'.',c.table_name ) as table_name, c.column_name
FROM information_schema.columns c
WHERE c.udt_name = cast(enumTypeName as varchar)
and c.table_schema=c.udt_schema and data_type = 'USER-DEFINED';
-- if we have table(s) that uses such enum
if exists(select * from tmp_table_names)
then
FOR rec in (select table_name, column_name from tmp_table_names) LOOP
sql:= format('UPDATE %1$s set %2$s = %3$L where %2$s=%4$L',rec.table_name, rec.column_name, enumNewFieldValue, enumOldFieldValue);
raise info 'Update by looping: %', sql;
EXECUTE sql;
END LOOP;
end if;
-- just after changing all old values in all tables we can delete old enum value
sql := format('DELETE FROM pg_enum WHERE enumtypid = (select oid from pg_type where typName=%1$L limit 1) and enumlabel=%2$L',enumTypeName,enumOldFieldValue);
raise info 'Delete enum value: %', sql;
EXECUTE sql;
drop table tmp_table_names;
ELSE
raise info 'Old or new enum values is missing.';
end if;
END $$;
ไม่สามารถลบแต่ละค่าออกจาก ENUM ได้วิธีเดียวที่เป็นไปได้คือการ DROP และสร้าง ENUM ใหม่ด้วยค่าที่จำเป็น
DELETE FROM pg_enum WHERE enumlabel='saml' AND enumsortorder=4;
drop type admin_level1
เหรอ?