114

PostgreSQL 8 में बाद में ड्रॉप किए बिना निम्न तालिका में दोनों विदेशी कुंजी को "कैस्केड हटाने पर" जोड़ना संभव है?"डिलीट कैस्केड" बाधाओं को कैसे जोड़ा जाए?

# \d pref_scores 
     Table "public.pref_scores" 
Column |   Type   | Modifiers 
---------+-----------------------+----------- 
id  | character varying(32) | 
gid  | integer    | 
money | integer    | not null 
quit | boolean    | 
last_ip | inet     | 
Foreign-key constraints: 
    "pref_scores_gid_fkey" FOREIGN KEY (gid) REFERENCES pref_games(gid) 
    "pref_scores_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 

दोनों संदर्भित टेबल में नीचे हैं - यहाँ:

# \d pref_games 
            Table "public.pref_games" 
    Column |   Type    |      Modifiers 
----------+-----------------------------+---------------------------------------------------------- 
gid  | integer      | not null default nextval('pref_games_gid_seq'::regclass) 
rounds | integer      | not null 
finished | timestamp without time zone | default now() 
Indexes: 
    "pref_games_pkey" PRIMARY KEY, btree (gid) 
Referenced by: 
    TABLE "pref_scores" CONSTRAINT "pref_scores_gid_fkey" FOREIGN KEY (gid) REFERENCES pref_games(gid) 

और यहाँ:

# \d pref_users 
       Table "public.pref_users" 
    Column |   Type    | Modifiers 
------------+-----------------------------+--------------- 
id   | character varying(32)  | not null 
first_name | character varying(64)  | 
last_name | character varying(64)  | 
female  | boolean      | 
avatar  | character varying(128)  | 
city  | character varying(64)  | 
login  | timestamp without time zone | default now() 
last_ip | inet      | 
logout  | timestamp without time zone | 
vip  | timestamp without time zone | 
mail  | character varying(254)  | 
Indexes: 
    "pref_users_pkey" PRIMARY KEY, btree (id) 
Referenced by: 
    TABLE "pref_cards" CONSTRAINT "pref_cards_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_catch" CONSTRAINT "pref_catch_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_chat" CONSTRAINT "pref_chat_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_game" CONSTRAINT "pref_game_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_hand" CONSTRAINT "pref_hand_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_luck" CONSTRAINT "pref_luck_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_match" CONSTRAINT "pref_match_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_misere" CONSTRAINT "pref_misere_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_money" CONSTRAINT "pref_money_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_pass" CONSTRAINT "pref_pass_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_payment" CONSTRAINT "pref_payment_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_rep" CONSTRAINT "pref_rep_author_fkey" FOREIGN KEY (author) REFERENCES pref_users(id) 
    TABLE "pref_rep" CONSTRAINT "pref_rep_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_scores" CONSTRAINT "pref_scores_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 
    TABLE "pref_status" CONSTRAINT "pref_status_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id) 

और यह भी मुझे आश्चर्य है कि अगर यह पूर्व मेज पर 2 index'es जोड़ने के लिए समझ में आता है ?

अद्यतन: लिए धन्यवाद, और भी मैं मेलिंग सूची पर सलाह की कोई जरूरत नहीं एक सौदे मिल गया है, कि मैं इसे 1 बयान में प्रबंधन कर सकते हैं और इस प्रकार:

ALTER TABLE public.pref_scores 
DROP CONSTRAINT pref_scores_gid_fkey, 
ADD CONSTRAINT pref_scores_gid_fkey 
    FOREIGN KEY (gid) 
    REFERENCES pref_games(gid) 
    ON DELETE CASCADE; 
+1

थोड़ा ओटी, लेकिन मुझे लगता है कि आपने कॉलम संदर्भ देने पर इंडेक्स नहीं बनाए हैं (उदाहरण के लिए, 'pref_scores.gid')। यदि आप उन तालिकाओं में कई पंक्तियां प्राप्त करते हैं, तो संदर्भित तालिका पर हटाए गए लोगों के बिना लंबा समय लगेगा। कुछ डेटाबेस स्वचालित रूप से संदर्भ कॉलम पर एक अनुक्रमणिका बनाते हैं; PostgreSQL आपको छोड़ देता है, क्योंकि कुछ ऐसे मामले हैं जहां यह सार्थक नहीं है। – kgrittn

+1

धन्यवाद! मैंने वास्तव में देखा कि हटाए जाने में लंबा समय लगता है, लेकिन यह नहीं पता था कि –

+1

क्या कारण होगा, जब विदेशी कुंजी पर इंडेक्स सार्थक नहीं होंगे? –

उत्तर

144

मैं बहुत हूँ सुनिश्चित करें कि आप मौजूदा विदेशी कुंजी बाधा में on delete cascade जोड़ नहीं सकते हैं। आपको पहले बाधा छोड़नी है, फिर सही संस्करण जोड़ें। मानक SQL में, मेरा मानना ​​है कि ऐसा करने के लिए सबसे आसान तरीका है

    है
  • एक सौदे शुरू,
  • ड्रॉप विदेशी कुंजी,
  • on delete cascade के साथ एक विदेशी कुंजी जोड़ने के लिए, और अंत में
  • लेन-देन के लिए प्रतिबद्ध

प्रत्येक विदेशी कुंजी के लिए दोहराएं जिसे आप बदलना चाहते हैं।

लेकिन पोस्टग्रेएसक्यूएल में एक गैर-मानक एक्सटेंशन है जो आपको एक एकल SQL कथन में एकाधिक बाधा खंडों का उपयोग करने देता है। उदाहरण के लिए

alter table public.pref_scores 
drop constraint pref_scores_gid_fkey, 
add constraint pref_scores_gid_fkey 
    foreign key (gid) 
    references pref_games(gid) 
    on delete cascade; 

आप विदेशी कुंजी बाधा आप ड्रॉप करना चाहते हैं उसका नाम पता नहीं है, तो आप या तो इसे देख सकते हैं pgAdminIII में (सिर्फ तालिका नाम पर क्लिक करें और DDL को देखो, या विस्तार पदानुक्रम जब तक आप "बाधाएं" नहीं देखते), या आप query the information schema कर सकते हैं।

select * 
from information_schema.key_column_usage 
where position_in_unique_constraint is not null 
+0

धन्यवाद, यही मैंने सोचा था - लेकिन विदेशी कुंजी के साथ क्या करना है? क्या वे केवल बाधाएं हैं (नॉट न्यूल के समान) जिन्हें आसानी से गिराया जा सकता है और आसानी से पढ़ा जा सकता है? –

+2

@AlexanderFarber: हां, उन्हें बाधाओं का नाम दिया गया है जिन्हें आप आसानी से छोड़ सकते हैं और जोड़ सकते हैं। लेकिन आप शायद लेनदेन के भीतर ऐसा करना चाहते हैं। अधिक जानकारी के साथ मेरा जवाब अपडेट किया गया। PgAdminIII में ot up देखने के लिए –

+0

+1। यह आपको ड्रोप कंसस्ट्रेंट भी देता है और कंसस्ट्रेंट कमांड जोड़ता है, ताकि आप केवल एक क्वेरी विंडो में कॉपी और पेस्ट कर सकें और जो भी आप चाहते हैं उसे कमांड संपादित कर सकें। –

3

उपयोग:

select replace_foreign_key('user_rates_posts', 'post_id', 'ON DELETE CASCADE'); 

फंक्शन:

CREATE OR REPLACE FUNCTION 
    replace_foreign_key(f_table VARCHAR, f_column VARCHAR, new_options VARCHAR) 
RETURNS VARCHAR 
AS $$ 
DECLARE constraint_name varchar; 
DECLARE reftable varchar; 
DECLARE refcolumn varchar; 
BEGIN 

SELECT tc.constraint_name, ccu.table_name AS foreign_table_name, ccu.column_name AS foreign_column_name 
FROM 
    information_schema.table_constraints AS tc 
    JOIN information_schema.key_column_usage AS kcu 
     ON tc.constraint_name = kcu.constraint_name 
    JOIN information_schema.constraint_column_usage AS ccu 
     ON ccu.constraint_name = tc.constraint_name 
WHERE constraint_type = 'FOREIGN KEY' 
    AND tc.table_name= f_table AND kcu.column_name= f_column 
INTO constraint_name, reftable, refcolumn; 

EXECUTE 'alter table ' || f_table || ' drop constraint ' || constraint_name || 
', ADD CONSTRAINT ' || constraint_name || ' FOREIGN KEY (' || f_column || ') ' || 
' REFERENCES ' || reftable || '(' || refcolumn || ') ' || new_options || ';'; 

RETURN 'Constraint replaced: ' || constraint_name || ' (' || f_table || '.' || f_column || 
' -> ' || reftable || '.' || refcolumn || '); New options: ' || new_options; 

END; 
$$ LANGUAGE plpgsql; 

प्रति सचेत रहें: इस समारोह प्रारंभिक विदेशी कुंजी के गुण कॉपी नहीं करेंगे। यह केवल विदेशी तालिका का नाम/कॉलम नाम लेता है, वर्तमान कुंजी छोड़ देता है और को नए के साथ बदल देता है।