পোস্টগ্রিসে এনাম টাইপ মান কীভাবে মুছবেন?


109

আমি পোস্টগ্রেস্কল-এ তৈরি করা এনাম টাইপ মানটি কীভাবে মুছব?

create type admin_level1 as enum('classifier', 'moderator', 'god');

যেমন আমি moderatorতালিকা থেকে মুছে ফেলতে চাই ।

আমি ডক্সে কিছু খুঁজে পাচ্ছি না বলে মনে হচ্ছে।

আমি Postgresql 9.3.4 ব্যবহার করছি।


4
drop type admin_level1?
বেরিয়াল

1
থাম্বের বিধি: প্রত্যেকের create xxxজন্য একটিdrop xxx
অ_সৌনিক_বিহীন_নো নাম

আইএমও নির্বাচিত উত্তর অবশ্যই অন্য একটিতে পরিবর্তন করতে হবে।
রোমান পোদলিনভ

উত্তর:


180

আপনি অন্য প্রকারের মতো এনাম প্রকারগুলি (ড্রপ) মুছুন, এর সাথে DROP TYPE:

DROP TYPE admin_level1;

আপনি কি এনাম টাইপ থেকে আলাদা আলাদা মান সরিয়ে নেবেন সে সম্পর্কে আপনি কি জিজ্ঞাসা করছেন ? যদি তাই হয়, আপনি পারবেন না। এটি সমর্থিত নয় :

যদিও enumপ্রকারগুলি প্রাথমিকভাবে মানগুলির স্থির সেটগুলির জন্য উদ্দিষ্ট হয়, তবে বিদ্যমান এনাম প্রকারে নতুন মান যুক্ত করার জন্য এবং মানগুলির নাম পরিবর্তন করার জন্য (দেখুন ALTER TYPE) সমর্থন রয়েছে। এনাম টাইপ থেকে বিদ্যমান মানগুলি অপসারণ করা যাবে না এবং এনামের ধরণটি পুনরায় তৈরি করার মতো, এই জাতীয় মানগুলির ক্রমানুসারে পরিবর্তন করা যাবে না।

আপনাকে মানটি ছাড়াই একটি নতুন প্রকার তৈরি করতে হবে, নতুন প্রকারটি ব্যবহার করতে পুরানো প্রকারের সমস্ত বিদ্যমান ব্যবহারকে রূপান্তর করতে হবে, তারপরে পুরানো প্রকারটি ফেলে দিন।

যেমন

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;

1
এটা অসাধারণ! এটির সাহায্যে আমি আলেম্বিক মাইগ্রেশন সমস্যা সমাধান করতে সক্ষম হয়েছি। আমি না, কারণ নতুন enum টাইপ যোগ করতে পারিনি(psycopg2.InternalError) ALTER TYPE ... ADD cannot run inside a transaction block
karantan

disable_ddl_transaction যোগ করুন! মাইগ্রেশন ফাইলের শীর্ষে।
চেল

বালাহ থেকে মুছে ফেলুন যেখানে শক্তি = ''শ্বর'; আমার ক্ষেত্রে কাজ করছে না
অঙ্কিত

1
টিবিএইচ কেন এই উত্তরটি নির্বাচন করা হয়েছিল তা আমি বুঝতে পারি না। এই উত্তরটি সঠিক নয়! আপনি নির্দিষ্ট লেবেল সহ pg_enum থেকে মান মুছতে পারেন।
রোমান পোডলিনভ

2
@ রোমানপোলিনভ প্রত্যক্ষ ক্যাটালগ ম্যানিপুলেশন আমি আপনার নিজের ঝুঁকিতে আছি। পোস্টগ্রাগে এনাম মানগুলি স্থানীয়ভাবে মুছে ফেলার পক্ষে সমর্থন করে না এমন কারণ রয়েছে। অসমর্থিত এবং অনিরাপদ ক্যাটালগ হ্যাকের তুলনায় এটি কীভাবে "সঠিক নয়"?
ক্রেগ রিঞ্জার

41

এখানে খুব ভাল লেখা:

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;

এই লিঙ্কটি এখন একটি 503 ফেরত দেয়
অলিভার ইভান্স

31

আপনি যদি এনাম টাইপের আইটেমটি মুছতে চান তবে আপনাকে অবশ্যই পোস্টগ্রিজ এসকিউএল এর সিস্টেম টেবিলটিতে পরিচালনা করতে হবে।

এই কমান্ডের সাহায্যে আপনি এনাম প্রকারের সমস্ত আইটেম প্রদর্শন করতে পারেন।

Pg_enum থেকে * নির্বাচন করুন;

তারপরে অনুসন্ধান করুন যে মানটি অনন্য। রেকেরু অপসারণের সময় স্বতন্ত্রতা বাড়াতে অবশ্যই 'এনামেলাবেল' ছাড়াও 'এনমিটিপিড' পাস করতে হবে।

এই কমান্ডটি এনাম প্রকারের এন্ট্রি সরিয়ে দেয়, যেখানে 'অনন্য' আপনার মান।

Pg_enum থেকে ডিলিট করুন যেখানে en.enumtypid = 124 এবং en.enumlabel = 'অনন্য';

দ্রষ্টব্য যে আমি বর্ণিত উদাহরণটি অবশ্যই ব্যবহার করা উচিত, যখন সুযোগক্রমে আমরা এনাম টাইপের জন্য নতুন মান যুক্ত করি এবং তবুও আমরা এটি ডেটাবেজে কোথাও ব্যবহার করি নি।


20
এটি একটি খুব বিপজ্জনক অপারেশন , তবে আপনি কী করছেন তা যদি আপনি জানেন তবে এনাম টাইপ থেকে কোনও মান সরিয়ে ফেলা খুব দ্রুত এবং সংক্ষেপে। প্রথমে নিশ্চিত করুন যে কোনও টেবিল আপনি যে এনাম মানটি সরাতে চান তা ব্যবহার করছে না। যদি আপনি এটি না করেন তবে আপনি এনামের মান উল্লেখ করে এমন সমস্ত সারণীটি খুব খারাপভাবে ভেঙে ফেলবেন (উদাহরণস্বরূপ এই জাতীয় সারণী থেকে নির্বাচন করা কোনও ফল দিবে ERROR: invalid internal value for enumএবং কোন ফল দেবে না ))
ক্লিন্ট পাচল

5
এটি ঠিক, এটি সবচেয়ে গুরুত্বপূর্ণ দিকটি বিবেচনায় নেওয়া উচিত। আমি যে উদাহরণটি বর্ণনা করেছি তা অবশ্যই ব্যবহার করা উচিত, যখন সুযোগক্রমে আমরা এনাম টাইপের ক্ষেত্রে নতুন মান যুক্ত করি এবং এখনও আমরা এটি ডেটাবেজে কোথাও ব্যবহার করি নি।
এলকুড্রো

1
এই কমান্ডটি কতটা বিপজ্জনক তা প্রদত্ত DELETE FROM pg_enum en WHERE en.enumtypid=124 AND en.enumlabel='unigue';নোটটি বোল্ডে থাকা উচিত, কমান্ড নয়। আপনি যদি কিছু টেবিলে মানটি ব্যবহার করেন তবে আপনি এ থেকে পুনরুদ্ধার করতে পারবেন না। আপনি মানগুলি ধারণ করে এমন সারিগুলি আপডেট করতে পারবেন না, আপনি রূপান্তর করতে পারবেন না। পুরো উপায়টি মুছে ফেলা একমাত্র উপায়।
সিলভাইন

8

যারা এনাম মানগুলি সংশোধন করতে চান তাদের জন্য এটি পুনরুক্তি করা কেবলমাত্র কার্যকর এবং নিরাপদ সমাধান বলে মনে হয়।

এটি অস্থায়ীভাবে এনাম কলামটিকে একটি স্ট্রিং ফর্ম্যাটে রূপান্তর করে, এনামটিকে পুনরায় তৈরি করে এবং তারপরে স্ট্রিং কলামটি এনাম টাইপটিতে পুনরায় রূপান্তর করে।

এখানে একটি উদাহরণ:

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;
ম্যানুয়েল ডারভো

6

পোস্টগ্রেসকিএল টাইপ থেকে ENUM মান মুছতে নিম্নলিখিত কোয়েরি ব্যবহার করুন

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**'; 

মোছার আগে, প্রকারের মানকে নতুন ধরণের মান বা বিদ্যমান মানকে আপডেট করুন।


একমাত্র ইস্যুতে pg_type টাইপের নাম হ'ল লোয়ার কেস। সুতরাং এটি কার্যকর হয় না, যদি না নিম্ন কেস এনাম_ টাইপ ব্যবহার না করে SELECT oid FROM pg_type WHERE typname = 'enum_type'
fzerorubigd

2

এটি করার প্রোগ্রাম্যাটিক পদ্ধতিটি নীচে রয়েছে। Https://stackoverflow.com/a/47305844/629272 এ দেওয়া একই সাধারণ পদক্ষেপগুলি যথাযথ, তবে সেগুলি আমার উদ্দেশ্যগুলির জন্য বুদ্ধিমানের চেয়ে বেশি ম্যানুয়াল (মাইগ্রেশন ডাউন এলেম্বিক লিখে)। my_type, my_type_oldএবং value_to_delete, অবশ্যই যথাযথ হিসাবে পরিবর্তন করা উচিত।

  1. আপনার টাইপটির নতুন নাম দিন।

    ALTER TYPE my_type RENAME TO my_type_old;
  2. আপনি মুছতে চান এমনটি বাদ দিয়ে আপনার পুরানো প্রকারের মানগুলি সহ একটি নতুন প্রকার তৈরি করুন।

    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 $$;
  3. পুরানো প্রকারটি নতুন ব্যবহার করতে ব্যবহৃত সমস্ত বিদ্যমান কলাম পরিবর্তন করুন।

    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 $$;
  4. পুরানো টাইপ মুছুন।

    DROP TYPE my_type_old;

0

যদি আপনার ডেটাসেটটি এত বড় না হয় আপনি --column-insertsকোনও পাঠ্য সম্পাদক দ্বারা ডাম্প সম্পাদনা করে ডাম্প করতে পারেন, মানটি সরিয়ে এবং ডাম্পটি আবার আমদানি করতে পারেন


0

V.10 এ একই সমস্যা ছিল। postgres। মুছে ফেলার জন্য কিছু নির্দিষ্ট পদ্ধতি প্রয়োজন এবং যদি ক্রমটি সঠিক না হয়, তবে টেবিলটি পড়ার জন্য লক হওয়ারও সুযোগ থাকবে chance

মুছতে সুবিধাজনক স্ক্রিপ্ট লিখেছিলেন। ইতিমধ্যে বেশ কয়েকবার এর কার্যকারিতা প্রমাণিত। যাইহোক, এই পদ্ধতিতে মুছে যাওয়া মানটিকে একটি নতুনের সাথে প্রতিস্থাপন করা হয় (টেবিল ক্ষেত্র এটির অনুমতি দেয় তবে এটি নুল হতে পারে)।

ব্যবহার করতে, আপনাকে কেবল 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 $$;
  1. তালিকাবদ্ধ

-1

ENUM থেকে পৃথক মান মুছে ফেলা সম্ভব নয়, একমাত্র সম্ভাব্য সমাধান হ'ল DROP এবং প্রয়োজনীয় মান সহ ENUM পুনরায় তৈরি করা।


এটি খুব সম্ভব, আপনি সম্ভবত যা বোঝাতে চেয়েছেন তা হ'ল "সরকারীভাবে সমর্থিত নয়"।
রিকুডউ_সেনিন

@ রিকুডউ_সেনিন আপনি কি এমন একটি কোড সরবরাহ করতে আপত্তি করবেন যা ENUM থেকে একটি সঠিক মান সরিয়ে ফেলতে পারে?
জায়েতসেভ দিমিত্রি 9'19

2
@ জায়টসেভডিমিট্রি এখানে আপনি:DELETE FROM pg_enum WHERE enumlabel='saml' AND enumsortorder=4;
রোমান পোডলিনভ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.