ক্যাসকেড মুছে ফেলুন মাত্র একবার


199

আমার একটি পোস্টগ্র্যাস্কেল ডাটাবেস রয়েছে যার উপর আমি কয়েকটি ক্যাসকেডিং মুছতে চাই। যাইহোক, সারণিগুলি অন ডিলেট ক্যাসকেড বিধি দিয়ে সেট আপ করা হয়নি। আমি কি কোনও উপায় মুছে ফেলতে পারি এবং Postgresql কে কেবল একবার এটি ক্যাসকেড করতে বলতে পারি? সমান কিছু

DELETE FROM some_table CASCADE;

এই পুরানো প্রশ্নের উত্তরগুলি দেখে মনে হচ্ছে এ জাতীয় কোনও সমাধান নেই, তবে আমি অনুভব করেছি যে আমি এই প্রশ্নটি স্পষ্টভাবে জিজ্ঞাসা করেছিলাম নিশ্চিত হওয়ার জন্য।


নীচে আমার কাস্টম ফাংশন দেখুন। নির্দিষ্ট সীমাবদ্ধতার দ্বারা এটি সম্ভব possible
জো লাভ

উত্তর:


175

না, কেবল একবার এটি করার জন্য আপনি যে টেবিলটি ক্যাসকেড করতে চান তার জন্য মুছুন স্টেটমেন্টটি কেবল লিখবেন।

DELETE FROM some_child_table WHERE some_fk_field IN (SELECT some_id FROM some_Table);
DELETE FROM some_table;

12
মূল ক্যাসকেডিং (পুনরাবৃত্তি) থেকে অন্যান্য বিদেশী কীগুলি ক্যাসকেডিং হতে পারে বলে এটি অগত্যা কাজ করে না। এমনকি আপনি এমন একটি লুপে উঠতে পারেন যেখানে টেবিলটি একটি খকে বোঝায় যা a। সাধারণ অর্থে এটি অর্জন করতে নীচে আমার টেবিলটি দেখুন তবে এতে কিছুটা বিধিনিষেধ রয়েছে। যদি আপনার একটি সাধারণ টেবিল সেটআপ থাকে তবে উপরের কোডটি ব্যবহার করে দেখুন, আপনি কী করছেন তা বোঝা আরও সহজ।
জো লাভ

2
সহজ, নিরাপদ আপনার যদি ঘনত্ব সন্নিবেশ থাকে তবে আপনার সেগুলি একক লেনদেনে চালানো উচিত।
ইমেল ইয়াভুজ

40

যদি আপনি সত্যিকার DELETE FROM some_table CASCADE; অর্থে " টেবিল থেকে সমস্ত সারি সরিয়ে ফেলুনsome_table " চান তবে আপনি এরTRUNCATE পরিবর্তে ব্যবহার করতে পারেন DELETEএবং CASCADEসর্বদা সমর্থিত। যাইহোক, আপনি যদি একটি whereধারা সহ নির্বাচনী মুছুন ব্যবহার করতে চান , TRUNCATEযথেষ্ট ভাল নয়।

যত্ন সহ ব্যবহার করুন - এটি এমন সমস্ত টেবিলের সমস্ত সারি বাদ দেবে যা বিদেশী কী বাধা আছে some_tableএবং সমস্ত টেবিলগুলিতে এই টেবিলগুলিতে সীমাবদ্ধতা রয়েছে ইত্যাদি drop

পোস্টগ্রিস ট্রুনকেট কমান্ডেরCASCADE সাহায্যে সমর্থন করে :

TRUNCATE some_table CASCADE;

হ্যান্ডলি এটি লেনদেনিক (অর্থাত্‍ ঘুরিয়ে ফেলা যায়) যদিও এটি অন্যান্য সমবর্তী লেনদেনগুলি থেকে সম্পূর্ণ বিচ্ছিন্ন নয় এবং এর মধ্যে আরও বেশ কয়েকটি ক্যাভেট রয়েছে। বিশদ জন্য ডক্স পড়ুন।


226
পরিষ্কারভাবে "কয়েকটি ক্যাসকেডিং
মোছা

33
এটি এমন সমস্ত টেবিলের সারি সরিয়ে ফেলবে যা কিছু_ টেবিলের বিদেশী কী বাধা আছে এবং সমস্ত টেবিলগুলিতে এই টেবিলগুলিতে সীমাবদ্ধতা রয়েছে ... ইত্যাদি ... এটি সম্ভবত অত্যন্ত বিপজ্জনক।
এজেপি

56
হুঁশিয়ার। এটি একটি বেপরোয়া উত্তর।
জর্দান আর্সেনো

4
মুছে ফেলার জন্য কেউ এই উত্তরটিকে পতাকাঙ্কিত করেছে - সম্ভবত তারা এর সাথে একমত না হওয়ার কারণে। সেক্ষেত্রে সঠিক ক্রিয়াকলাপটি পতাকাটি নয়, ডাউনভোট করা।
ওয়াই হা লি

7
তার উপরে সতর্কতা রয়েছে। আপনি যদি এটিকে অগ্রাহ্য করা চয়ন করেন তবে কেউ আপনাকে সহায়তা করতে পারে না। আমি মনে করি আপনার "কপিপাস্ট" ব্যবহারকারীরা এখানে আসল বিপদ।
ব্লু

28

আমি এর প্রাথমিক কী এর উপর ভিত্তি করে যে কোনও সারি মুছতে একটি (পুনরাবৃত্ত) ফাংশন লিখেছি। আমি এটি লিখেছিলাম কারণ আমি আমার সীমাবদ্ধতাগুলি "ক্যাসকেড মুছে ফেলুন" হিসাবে তৈরি করতে চাইনি। আমি চাইছিলাম জটিল সেট ডেটাগুলি মুছে ফেলতে সক্ষম হয়েছি (ডিবিএ হিসাবে) তবে আমার প্রোগ্রামারগুলিকে সমস্ত ফলস্বরূপ চিন্তা না করে মুছে ফেলতে সক্ষম হতে দেয় না। আমি এখনও এই ফাংশনটি পরীক্ষা করছি, সুতরাং এতে বাগগুলি থাকতে পারে - তবে আপনার ডিবিতে মাল্টি কলাম প্রাথমিক (এবং এইভাবে বিদেশী) কী থাকলে দয়া করে চেষ্টা করবেন না। এছাড়াও, কীগুলি সকলকে স্ট্রিং আকারে উপস্থাপন করতে সক্ষম হতে হবে, তবে এটি এমনভাবে লেখা যেতে পারে যাতে সেই সীমাবদ্ধতা নেই। আমি যাইহোক যাইহোক, খুব স্বল্পভাবেই এই ফাংশনটি ব্যবহার করি, সবকিছুতে ক্যাসকেডিং সীমাবদ্ধতা সক্ষম করতে আমি আমার ডেটাটিকে খুব বেশি মূল্য দিয়েছি। মূলত এই ফাংশনটি স্কিমা, সারণির নাম এবং প্রাথমিক মান (স্ট্রিং আকারে) এ পাস করা হয়েছে, এবং এটি সেই টেবিলে কোনও বিদেশী কীগুলি সন্ধানের মাধ্যমে শুরু হবে এবং নিশ্চিত করে যে ডেটা বিদ্যমান নেই - যদি তা হয়, তবে এটি পুনরুদ্ধার করে খুঁজে পাওয়া তথ্যে নিজেকে কল করে। এটি অসীম লুপগুলি প্রতিরোধ করতে মুছে ফেলার জন্য ইতিমধ্যে চিহ্নিত ডেটার একটি অ্যারে ব্যবহার করে। দয়া করে এটি পরীক্ষা করে দেখুন এবং এটি আপনার জন্য কীভাবে কাজ করে তা আমাকে জানান। দ্রষ্টব্য: এটি কিছুটা ধীর। আমি এটিকে এভাবে বলেছি: select delete_cascade('public','my_table','1');

create or replace function delete_cascade(p_schema varchar, p_table varchar, p_key varchar, p_recursion varchar[] default null)
 returns integer as $$
declare
    rx record;
    rd record;
    v_sql varchar;
    v_recursion_key varchar;
    recnum integer;
    v_primary_key varchar;
    v_rows integer;
begin
    recnum := 0;
    select ccu.column_name into v_primary_key
        from
        information_schema.table_constraints  tc
        join information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name and ccu.constraint_schema=tc.constraint_schema
        and tc.constraint_type='PRIMARY KEY'
        and tc.table_name=p_table
        and tc.table_schema=p_schema;

    for rx in (
        select kcu.table_name as foreign_table_name, 
        kcu.column_name as foreign_column_name, 
        kcu.table_schema foreign_table_schema,
        kcu2.column_name as foreign_table_primary_key
        from information_schema.constraint_column_usage ccu
        join information_schema.table_constraints tc on tc.constraint_name=ccu.constraint_name and tc.constraint_catalog=ccu.constraint_catalog and ccu.constraint_schema=ccu.constraint_schema 
        join information_schema.key_column_usage kcu on kcu.constraint_name=ccu.constraint_name and kcu.constraint_catalog=ccu.constraint_catalog and kcu.constraint_schema=ccu.constraint_schema
        join information_schema.table_constraints tc2 on tc2.table_name=kcu.table_name and tc2.table_schema=kcu.table_schema
        join information_schema.key_column_usage kcu2 on kcu2.constraint_name=tc2.constraint_name and kcu2.constraint_catalog=tc2.constraint_catalog and kcu2.constraint_schema=tc2.constraint_schema
        where ccu.table_name=p_table  and ccu.table_schema=p_schema
        and TC.CONSTRAINT_TYPE='FOREIGN KEY'
        and tc2.constraint_type='PRIMARY KEY'
)
    loop
        v_sql := 'select '||rx.foreign_table_primary_key||' as key from '||rx.foreign_table_schema||'.'||rx.foreign_table_name||'
            where '||rx.foreign_column_name||'='||quote_literal(p_key)||' for update';
        --raise notice '%',v_sql;
        --found a foreign key, now find the primary keys for any data that exists in any of those tables.
        for rd in execute v_sql
        loop
            v_recursion_key=rx.foreign_table_schema||'.'||rx.foreign_table_name||'.'||rx.foreign_column_name||'='||rd.key;
            if (v_recursion_key = any (p_recursion)) then
                --raise notice 'Avoiding infinite loop';
            else
                --raise notice 'Recursing to %,%',rx.foreign_table_name, rd.key;
                recnum:= recnum +delete_cascade(rx.foreign_table_schema::varchar, rx.foreign_table_name::varchar, rd.key::varchar, p_recursion||v_recursion_key);
            end if;
        end loop;
    end loop;
    begin
    --actually delete original record.
    v_sql := 'delete from '||p_schema||'.'||p_table||' where '||v_primary_key||'='||quote_literal(p_key);
    execute v_sql;
    get diagnostics v_rows= row_count;
    --raise notice 'Deleting %.% %=%',p_schema,p_table,v_primary_key,p_key;
    recnum:= recnum +v_rows;
    exception when others then recnum=0;
    end;

    return recnum;
end;
$$
language PLPGSQL;

এটি সর্বদা বিশেষত স্ব-রেফারেন্সিং টেবিলগুলির সাথে ঘটে। বিভিন্ন বিভাগে বিভিন্ন পরিচালনা স্তর, বা জেনেরিক হায়ারার্কিকাল ট্যাক্সোনমি সহ একটি সংস্থা বিবেচনা করুন। হ্যাঁ, আমি একমত যে এই ফাংশনটি কাটা রুটি থেকে পরম সর্বোত্তম জিনিস নয়, তবে এটি সঠিক পরিস্থিতিতে একটি দরকারী সরঞ্জাম।
জো লাভ

আপনি যদি নতুন করে লেখেন তবে এটি আইডির অ্যারে গ্রহণ করে এবং কোয়েরিও তৈরি করে যা INঅপারেটরটি উপ-নির্বাচনের পরিবর্তে উপ-নির্বাচনের সাথে ব্যবহার করবে =(সুতরাং সেট যুক্তি ব্যবহারের পদক্ষেপ) এটি আরও দ্রুত হয়ে উঠবে ।
হবিটাস

2
আপনার সমাধানের জন্য আপনাকে ধন্যবাদ। আমি কিছু পরীক্ষা লিখি এবং আমার একটি রেকর্ড মুছতে হবে এবং সেই মুছাটি ক্যাসকেড করতে আমার সমস্যা হচ্ছে। আপনার ফাংশন সত্যিই ভাল কাজ!
ফার্নান্দো কামারগো

1
@ জো লেভ আপনার কী গতির সমস্যা আছে? এই পরিস্থিতিতে পুনরাবৃত্তি আমার মনে একক সঠিক সমাধান।
হুবিটাস

1
@ আর্থার আপনি সম্ভবত এটির জন্য সারি -> জসন -> পাঠ্যের কিছু সংস্করণ ব্যবহার করতে পারেন, তবে আমি এখনও পর্যন্ত যাইনি। বহু বছর ধরে আমি জানতে পেরেছি যে একক একক প্রাথমিক কী (সম্ভাব্য মাধ্যমিক কী সহ) বিভিন্ন কারণে ভাল।
জো লাভ

17

যদি আমি সঠিকভাবে বুঝতে পারি তবে বিদেশী কী সীমাবদ্ধতা বাদ দিয়ে, একটি নতুন যুক্ত করুন (যা ক্যাসকেড করবে) যুক্ত করে, আপনার স্টাফগুলি করে এবং সীমাবদ্ধ বিদেশী কী সীমাবদ্ধতা পুনরায় তৈরি করে আপনি যা করতে চান তা করতে সক্ষম হবেন।

উদাহরণ স্বরূপ:

testing=# create table a (id integer primary key);
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "a_pkey" for table "a"
CREATE TABLE
testing=# create table b (id integer references a);
CREATE TABLE

-- put some data in the table
testing=# insert into a values(1);
INSERT 0 1
testing=# insert into a values(2);
INSERT 0 1
testing=# insert into b values(2);
INSERT 0 1
testing=# insert into b values(1);
INSERT 0 1

-- restricting works
testing=# delete from a where id=1;
ERROR:  update or delete on table "a" violates foreign key constraint "b_id_fkey" on table "b"
DETAIL:  Key (id)=(1) is still referenced from table "b".

-- find the name of the constraint
testing=# \d b;
       Table "public.b"
 Column |  Type   | Modifiers 
--------+---------+-----------
 id     | integer | 
Foreign-key constraints:
    "b_id_fkey" FOREIGN KEY (id) REFERENCES a(id)

-- drop the constraint
testing=# alter table b drop constraint b_a_id_fkey;
ALTER TABLE

-- create a cascading one
testing=# alter table b add FOREIGN KEY (id) references a(id) on delete cascade; 
ALTER TABLE

testing=# delete from a where id=1;
DELETE 1
testing=# select * from a;
 id 
----
  2
(1 row)

testing=# select * from b;
 id 
----
  2
(1 row)

-- it works, do your stuff.
-- [stuff]

-- recreate the previous state
testing=# \d b;
       Table "public.b"
 Column |  Type   | Modifiers 
--------+---------+-----------
 id     | integer | 
Foreign-key constraints:
    "b_id_fkey" FOREIGN KEY (id) REFERENCES a(id) ON DELETE CASCADE

testing=# alter table b drop constraint b_id_fkey;
ALTER TABLE
testing=# alter table b add FOREIGN KEY (id) references a(id) on delete restrict; 
ALTER TABLE

অবশ্যই, আপনার মানসিক স্বাস্থ্যের স্বার্থে আপনার এমন বিমূর্ত জিনিসগুলি কোনও প্রক্রিয়া হিসাবে নেওয়া উচিত।


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

1
আপনি কি বোঝাতে চান? রেকর্ডগুলি ক্যাসকেডের মাধ্যমে মুছে ফেলা হবে সেখানে কোনও অসঙ্গতি থাকতে হবে না।
পেড্রো বোর্জেস

1
"দুষ্টু শার্ডস" সম্পর্কে উদ্বিগ্ন হওয়ার পরিবর্তে (ক্যাসকেডিং সীমাবদ্ধতাগুলি এখনও ধারাবাহিক থাকবে), ক্যাসকেডিং খুব বেশি এগিয়ে না যাওয়ার বিষয়ে আমি আরও উদ্বিগ্ন হব - যদি মুছে ফেলা রেকর্ডগুলিতে আরও মুছে ফেলা রেকর্ডের প্রয়োজন হয়, তবে সেই সীমাবদ্ধতাগুলি পরিবর্তন করা দরকার পাশাপাশি ক্যাসকেডিং নিশ্চিত করা। (বা এই দৃশ্যটি এড়াতে আমি উপরে লিখেছি ফাংশনটি ব্যবহার করুন) ... যে কোনও ক্ষেত্রে একটি সর্বশেষ সুপারিশ: একটি ট্রান্সঅ্যাকশন ব্যবহার করুন যাতে এটি খারাপ হয়ে যায় তবে আপনি এটি আবার রোল করতে পারেন।
জো লাভ

7

আমি প্যালহর্সের উত্তর মন্তব্য করতে পারি না তাই আমি নিজের উত্তর যুক্ত করেছি। প্যালহর্সের যুক্তি ঠিক আছে তবে দক্ষতা বড় ডেটা সেটগুলির সাথে খারাপ হতে পারে।

DELETE FROM some_child_table sct 
 WHERE exists (SELECT FROM some_Table st 
                WHERE sct.some_fk_fiel=st.some_id);

DELETE FROM some_table;

আপনার কলামে সূচি এবং ডেটা সেট যদি কয়েকটি রেকর্ডের চেয়ে বড় হয় তবে এটি আরও দ্রুত is


7

হ্যাঁ, অন্যরা যেমন বলেছে, 'মাই_ টেবিল ... ক্যাসকেড' (বা সমতুল্য) থেকে কোনও সুবিধাজনক নেই। নন-ক্যাসকেডিং বিদেশী কী-সুরক্ষিত শিশু রেকর্ডস এবং তাদের রেফারেন্স করা পূর্বপুরুষদের মুছতে আপনার বিকল্পগুলিতে অন্তর্ভুক্ত রয়েছে:

  • সমস্ত মুছে ফেলা পরিষ্কারভাবে সঞ্চালন করুন, শিশু টেবিলগুলি দিয়ে শুরু করে একবারে একটি প্রশ্নের জন্য (যদিও আপনার বিজ্ঞপ্তিটি রেফারেন্স পেলে এটি উড়বে না); অথবা
  • সমস্ত মুছে ফেলা একটি একক (সম্ভাব্য বৃহত্তর) কোয়েরিতে স্পষ্টভাবে সম্পাদন করুন; অথবা
  • ধরে নেই যে আপনার অ-ক্যাসকেডিং বিদেশী কী বাধাগুলি 'অন ডিফল্ট ডিএকশন অ্যাকশন ডিফারালਬਲ' হিসাবে তৈরি করা হয়েছিল, সমস্ত বিলোপগুলি একক লেনদেনে স্পষ্টভাবে সম্পাদন করুন; অথবা
  • সাময়িকভাবে গ্রাফটিতে 'অ্যাকশন' এবং 'সীমাবদ্ধ' বিদেশী কী বাধাগুলি ফেলে দিন, তাদেরকে ক্যাসকেড হিসাবে পুনরায় তৈরি করুন, আপত্তিজনক পূর্বপুরুষদের মুছুন, বিদেশী কী বাধাগুলি আবার ফেলে দিন এবং অবশেষে সেগুলি মূল হিসাবে তাদের পুনরায় তৈরি করুন (এইভাবে অস্থায়ীভাবে অখণ্ডতার অখণ্ডতা দুর্বল করে দিন আপনার তথ্য); অথবা
  • কিছু সম্ভবত সমান মজা।

বিদেশী মূল সীমাবদ্ধতাগুলি দূর করার পক্ষে এটি সহজ উদ্দেশ্যে করা হয়নি, আমি ধরে নিই; তবে আমি বুঝতে পারি কেন বিশেষ পরিস্থিতিতে আপনি এটি করতে চান। যদি এটি এমন কিছু হয় যা আপনি কিছুটা ফ্রিকোয়েন্সি নিয়ে করছেন এবং আপনি যদি সর্বত্র ডিবিএর জ্ঞানকে আঘাত করতে চান তবে আপনি কোনও পদ্ধতিতে এটি স্বয়ংক্রিয় করতে চাইতে পারেন।

কয়েক মাস আগে আমি এখানে এসেছি "ক্যাসকেড মুছে ফেলুন মাত্র একবার" প্রশ্নের উত্তর (মূলত এক দশক আগে জিজ্ঞাসা করা হয়েছিল!)। জো লাভের চতুর সমাধান (এবং থমাস সিজি ডি ভিলেনার বৈকল্পিক) থেকে আমি কিছুটা মাইলেজ পেয়েছি, তবে শেষ পর্যন্ত আমার ব্যবহারের ক্ষেত্রে বিশেষ প্রয়োজনীয়তা ছিল (একটিতে অন্তর্-টেবিলের বিজ্ঞপ্তি রেফারেন্সগুলি পরিচালনা করা) যা আমাকে আলাদা দৃষ্টিভঙ্গি নিতে বাধ্য করেছিল। এই পদ্ধতির অবশেষে পুনরাবৃত্তভাবে_প্রেম হয়ে উঠেছে (পিজি 10.10)।

আমি এখন সময়ের জন্য উত্পাদনে পুনরাবৃত্তভাবে_প্রেমীটি ব্যবহার করছি, এবং অবশেষে ধারণাগুলির সন্ধানে এখানে বয়ে যেতে পারে এমন অন্যদের জন্য এটি উপলব্ধ করার পক্ষে যথেষ্ট আত্মবিশ্বাসী বোধ করছি war জো লাভের সমাধান হিসাবে, এটি আপনাকে পুরো ডেটা গ্রাফগুলি মুছে ফেলতে দেয় যেমন আপনার ডাটাবেসে সমস্ত বিদেশী কী বাধাগুলি মুহূর্তের জন্য ক্যাসকেডে সেট করা হয়েছে তবে কয়েকটি অতিরিক্ত বৈশিষ্ট্য সরবরাহ করে:

  • মুছে ফেলা লক্ষ্য এবং এর নির্ভরশীলদের গ্রাফের একটি ASCII পূর্বরূপ সরবরাহ করে।
  • রিকার্সিভ সিটিই ব্যবহার করে একটি একক ক্যোয়ারিতে মোছার কাজ করে।
  • বিজ্ঞপ্তি নির্ভরতা, অন্তঃ- এবং আন্ত-সারণী পরিচালনা করে।
  • যৌগিক কীগুলি পরিচালনা করে।
  • 'সেট ডিফল্ট' এবং 'সেট নাল' সীমাবদ্ধতা এড়িয়ে যায়।

আমি একটি ত্রুটি পেয়েছি: এরিআরআরআর: অ্যারেতে এমন অনেকগুলি উপাদান থাকা আবশ্যক যেখানে: পিএল / পিজিএসকিউএল ফাংশন _recursively_delete (রেগ্লাস, পাঠ্য [], পূর্ণসংখ্যা, জসনব, পূর্ণসংখ্যা, পাঠ্য [], জসনব, জসনব) লাইন 15 এসকিউএল বিবৃতিতে "নির্বাচন করুন * থেকে _ পুনরাবৃত্তভাবে_পরিবর্তন করুন (এআরজি_সারণযোগ্য, VAR_pk_col_names)" পিএল / পিজিএসকিউএল ফাংশন পুনরাবৃত্তভাবে_ডিলেট (রেজক্লাস, যে কোনও উপাদান, বুলিয়ান) এসকিউএল বিবৃতিতে 73 লাইন
জো লাভ

ওহে, জো জোভ! এটি চেষ্টা করার জন্য ধন্যবাদ। আপনি আমাকে পুনরুত্পাদন পদক্ষেপ দিতে পারেন? এবং আপনার পিজির সংস্করণটি কী?
টিআরএল

আমি নিশ্চিত না যে এটি সাহায্য করবে। তবে আমি সবেমাত্র আপনার ফাংশন তৈরি করেছি এবং তারপরে নিম্নলিখিত কোডটি চালিয়েছি: পুনরাবৃত্তভাবে_প্লেট নির্বাচন করুন ('ডালাস.ভেন্ডার', 1094, ভুয়া) কিছু ডিবাগিংয়ের পরে, আমি দেখতে পাচ্ছি যে এই ব্যাটের ডানদিকেই মারা যায় - মানে, মনে হয় এটি প্রথম কল like একাধিক কাজ করার পরে নয়, ফাংশনে। রেফারেন্সের জন্য আমি পিজি 10.8 চালাচ্ছি
জো লাভ

@ জোওলোভ, দয়া করে শাখা ট্রল-ফিক্স-অ্যারে_মাস্ট_হভে_ইভেন_নম্বার_অফলেট ( গিথুব / ট্রলোরেনজ / পিজি- রেকর্ডিভলি_ডিলেট / পুল / ২ ) চেষ্টা করুন।
টিআরএল

সেই শাখার চেষ্টা করে এবং এটি মূল ত্রুটিটি ঠিক করেছিল। দুঃখের বিষয়, এটি আমার আসল সংস্করণটির চেয়ে দ্রুততর নয় (এটি সম্ভবত এটি লেখার ক্ষেত্রে আপনার বক্তব্য নাও থাকতে পারে)। আমি আরেকটি প্রয়াসে কাজ করছি যা "অনধিকৃত ক্যাসকেড মুছে ফেলুন" দিয়ে নকল বিদেশী কী তৈরি করে, তারপরে আসল রেকর্ডটি মুছে ফেলা, তারপরে সদ্য নির্মিত সমস্ত বিদেশী কী বাদ দিয়ে,
জো লাভ

3

আপনি এটি স্বয়ংক্রিয় করতে ব্যবহার করতে পারেন, আপনি এর সাথে বিদেশী কী সীমাবদ্ধতার সংজ্ঞা দিতে পারেন ON DELETE CASCADE
আমি বিদেশী কী সীমাবদ্ধতার ম্যানুয়ালটি উদ্ধৃত করেছি :

CASCADE উল্লেখ করে যে যখন একটি রেফারেন্সড সারি মুছে ফেলা হয়, সারি (গুলি) উল্লেখ করলে তা স্বয়ংক্রিয়ভাবে মোছাও উচিত।


1
যদিও এটি ওপিকে সম্বোধন করে না, বিদেশী কীগুলির সাথে সারিগুলি কখন মুছতে হবে তার জন্য এটি ভাল পরিকল্পনা। যেমনটি বেন ফ্রাঙ্কলিন বলেছিলেন, "প্রতি আউন্স প্রতিরোধের জন্য এক পাউন্ড নিরাময়ের মূল্য রয়েছে।"
জেসুইসমে

1
আমি খুঁজে পেয়েছি যে এই সমাধানটি বেশ বিপজ্জনক হতে পারে যদি আপনার অ্যাপ্লিকেশন প্রচুর ভাইবোনদের সাথে রেকর্ডটি মুছে ফেলে এবং কোনও ছোট্ট ত্রুটির পরিবর্তে, আপনি স্থায়ীভাবে একটি বিশাল ডেটাसेट মুছে ফেলেছেন।
জো লাভ

2

আমি জো লাভের উত্তর নিয়েছি এবং ফাংশনটি দ্রুত করার INপরিবর্তে সাব- =সিলেক্টর সহ অপারেটরটি ব্যবহার করে এটি পুনরায় লিখেছিলাম (হুবিটাসের পরামর্শ অনুসারে):

create or replace function delete_cascade(p_schema varchar, p_table varchar, p_keys varchar, p_subquery varchar default null, p_foreign_keys varchar[] default array[]::varchar[])
 returns integer as $$
declare

    rx record;
    rd record;
    v_sql varchar;
    v_subquery varchar;
    v_primary_key varchar;
    v_foreign_key varchar;
    v_rows integer;
    recnum integer;

begin

    recnum := 0;
    select ccu.column_name into v_primary_key
        from
        information_schema.table_constraints  tc
        join information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name and ccu.constraint_schema=tc.constraint_schema
        and tc.constraint_type='PRIMARY KEY'
        and tc.table_name=p_table
        and tc.table_schema=p_schema;

    for rx in (
        select kcu.table_name as foreign_table_name, 
        kcu.column_name as foreign_column_name, 
        kcu.table_schema foreign_table_schema,
        kcu2.column_name as foreign_table_primary_key
        from information_schema.constraint_column_usage ccu
        join information_schema.table_constraints tc on tc.constraint_name=ccu.constraint_name and tc.constraint_catalog=ccu.constraint_catalog and ccu.constraint_schema=ccu.constraint_schema 
        join information_schema.key_column_usage kcu on kcu.constraint_name=ccu.constraint_name and kcu.constraint_catalog=ccu.constraint_catalog and kcu.constraint_schema=ccu.constraint_schema
        join information_schema.table_constraints tc2 on tc2.table_name=kcu.table_name and tc2.table_schema=kcu.table_schema
        join information_schema.key_column_usage kcu2 on kcu2.constraint_name=tc2.constraint_name and kcu2.constraint_catalog=tc2.constraint_catalog and kcu2.constraint_schema=tc2.constraint_schema
        where ccu.table_name=p_table  and ccu.table_schema=p_schema
        and TC.CONSTRAINT_TYPE='FOREIGN KEY'
        and tc2.constraint_type='PRIMARY KEY'
)
    loop
        v_foreign_key := rx.foreign_table_schema||'.'||rx.foreign_table_name||'.'||rx.foreign_column_name;
        v_subquery := 'select "'||rx.foreign_table_primary_key||'" as key from '||rx.foreign_table_schema||'."'||rx.foreign_table_name||'"
             where "'||rx.foreign_column_name||'"in('||coalesce(p_keys, p_subquery)||') for update';
        if p_foreign_keys @> ARRAY[v_foreign_key] then
            --raise notice 'circular recursion detected';
        else
            p_foreign_keys := array_append(p_foreign_keys, v_foreign_key);
            recnum:= recnum + delete_cascade(rx.foreign_table_schema, rx.foreign_table_name, null, v_subquery, p_foreign_keys);
            p_foreign_keys := array_remove(p_foreign_keys, v_foreign_key);
        end if;
    end loop;

    begin
        if (coalesce(p_keys, p_subquery) <> '') then
            v_sql := 'delete from '||p_schema||'."'||p_table||'" where "'||v_primary_key||'"in('||coalesce(p_keys, p_subquery)||')';
            --raise notice '%',v_sql;
            execute v_sql;
            get diagnostics v_rows = row_count;
            recnum := recnum + v_rows;
        end if;
        exception when others then recnum=0;
    end;

    return recnum;

end;
$$
language PLPGSQL;

2
আমি এটি দেখতে যাব এবং এটি স্ব-রেফারেন্সিং সীমাবদ্ধতা এবং এর মতো কতটা ভাল কাজ করে তা দেখুন see আমি অনুরূপ কিছু করার চেষ্টা করেছি তবে এটি সম্পূর্ণরূপে কাজ করা বন্ধ করে দিয়েছিল। যদি আপনার সমাধানটি আমার পক্ষে কাজ করে তবে আমি এটি বাস্তবায়ন করতে যাচ্ছি। এটি এমন অনেকগুলি ডিবিএ সরঞ্জামগুলির মধ্যে একটি যা প্যাকেজ করে গিথুব বা কোনও কিছুর উপরে রাখা উচিত।
জো লাভ

মাল্টি-টেন্যান্ট সিএমএসের জন্য আমার কাছে মাঝারি আকারের ডাটাবেস রয়েছে (ক্লায়েন্টরা সকলেই একই টেবিল ভাগ করে নিয়েছেন)। আমার সংস্করণটি ("ইন" সহ) পুরানো ক্লায়েন্টের সমস্ত চিহ্ন মুছে ফেলার জন্য বেশ ধীর গতিতে চলেছে বলে মনে হচ্ছে ... আমি গতির তুলনায় কিছু মকআপ ডেটা দিয়ে এটি চেষ্টা করতে আগ্রহী। আপনার ব্যবহারের ক্ষেত্রে লক্ষ্য করা গতির পার্থক্য সম্পর্কে আপনি কিছু বলতে পারেন?
জো লাভ

আমার ব্যবহারের ক্ষেত্রে আমি inঅপারেটর এবং সাব-কোয়েরিগুলি ব্যবহার করার সময় 10x ক্রমের গতি লক্ষ্য করেছি ।
থমাস সিজি ডি ভিলেনা

1

ক্যাসকেড বিকল্পটি মুছুন কেবলমাত্র বিদেশী কী সংজ্ঞায়িত টেবিলগুলিতে প্রয়োগ করা হবে। যদি আপনি কোনও মুছুনটি করেন এবং এটি বলে যে এটি বৈদেশিক কী সীমাবদ্ধতা লঙ্ঘন করবে তাই আপনি করতে পারবেন না, ক্যাসকেড এটির জন্য আপত্তিকর সারিগুলি মুছে ফেলবে।

আপনি যদি এইভাবে সম্পর্কিত সারিগুলি মুছতে চান তবে আপনাকে প্রথমে বিদেশী কীগুলি সংজ্ঞায়িত করতে হবে। এছাড়াও, মনে রাখবেন যে আপনি স্পষ্টভাবে লেনদেন শুরু করার নির্দেশ না দিলে বা আপনি ডিফল্টগুলি পরিবর্তন না করেন এটি একটি অটো-কমিট করবে, যা পরিষ্কার করতে খুব সময়সাপেক্ষ হতে পারে।


2
অনুদানের উত্তর আংশিকভাবে ভুল - পোস্টগ্র্যাস্কেল মুছে ফেলা প্রশ্নাবলীতে ক্যাসকেড সমর্থন করে না। postgresql.org/docs/8.4/static/dml-delete.html
ফ্রেডরিক ওয়েন্ড্ট

কোনও ধারণা কেন এটি মোছা ক্যোয়ারিতে সমর্থিত নয়?
টাইফিয়ন

2
কোনও টেবিলে "ক্যাসকেড দিয়ে মুছে ফেলার" কোনও উপায় নেই যা সেই অনুসারে সেট আপ করা হয়নি, অর্থাত্ বিদেশী কী বাধাটিকে ডিএনএলটি ক্যাসকেড হিসাবে সংজ্ঞায়িত করা হয়নি, যা মূলত এই প্রশ্নটিই ছিল।
লেন্সভেট

এই প্রশ্নের উত্তর হিসাবে , এটি সম্পূর্ণ ভুল। একবার ক্যাসকেড করার উপায় নেই।
জেরেমি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.