यह विदेशी कुंजी बाधाओं का पूरा बिंदु है: वे आपको डेटा को हटाने से रोकते हैं जो संदर्भात्मक अखंडता बनाए रखने के लिए कहीं और भेजा जाता है।
दो विकल्प हैं:
INVENTORY_ITEMS
पहले पंक्तियों को हटाएं , फिर पंक्तियों को STOCK_ARTICLES
।
ON DELETE CASCADE
कुंजी परिभाषा में उपयोग करें ।
1: सही क्रम में हटाना
ऐसा करने का सबसे कुशल तरीका क्वेरी की जटिलता के आधार पर भिन्न होता है जो यह तय करता है कि कौन सी पंक्तियों को हटाना है। एक सामान्य पैटर्न हो सकता है:
BEGIN TRANSACTION
SET XACT_ABORT ON
DELETE INVENTORY_ITEMS WHERE STOCK_ARTICLE IN (<select statement that returns stock_article.id for the rows you are about to delete>)
DELETE STOCK_ARTICLES WHERE <the rest of your current delete statement>
COMMIT TRANSACTION
यह सरल प्रश्नों के लिए या किसी एकल स्टॉक आइटम को हटाने के लिए ठीक है, लेकिन आपके डिलीट स्टेटमेंट में एक WHERE NOT EXISTS
क्लॉज नेस्टिंग है कि भीतर WHERE IN
एक बहुत ही अकुशल योजना का उत्पादन हो सकता है इसलिए एक यथार्थवादी डेटा सेट आकार के साथ परीक्षण करें और यदि आवश्यक हो तो क्वेरी को पुनर्व्यवस्थित करें।
ट्रांजेक्शन स्टेटमेंट पर भी ध्यान दें: आप यह सुनिश्चित करना चाहते हैं कि दोनों डिलीट पूरी हो जाएं या दोनों में से कोई भी ऐसा न करें। यदि ऑपरेशन पहले से ही एक लेन-देन के भीतर हो रहा है, तो आपको अपने वर्तमान लेनदेन और त्रुटि से निपटने की प्रक्रिया से मेल खाने के लिए स्पष्ट रूप से इसे बदलना होगा।
2: का उपयोग करें ON DELETE CASCADE
यदि आप अपनी विदेशी कुंजी में कैस्केड विकल्प जोड़ते हैं तो SQL सर्वर स्वचालित रूप से आपके लिए ऐसा करेगा, INVENTORY_ITEMS
बाधाओं को हटाने के लिए उन बाधाओं को संतुष्ट करने के लिए जो आपके द्वारा हटाए जा रहे पंक्तियों के लिए कुछ भी नहीं होना चाहिए। बस ON DELETE CASCADE
FK की परिभाषा में इस तरह जोड़ें :
ALTER TABLE <child_table> WITH CHECK
ADD CONSTRAINT <fk_name> FOREIGN KEY(<column(s)>)
REFERENCES <parent_table> (<column(s)>)
ON DELETE CASCADE
यहां एक फायदा यह है कि डिलीट एक एटॉमिक स्टेटमेंट रिड्यूस है (हालांकि, हमेशा की तरह, 100% रिमूवल नहीं) ट्रांजैक्शन और लॉक सेटिंग्स के बारे में चिंता करने की जरूरत है। कैसकेड कई माता-पिता / बच्चे / भव्य-बच्चे / ... के स्तर पर भी संचालित हो सकता है यदि माता-पिता और सभी वंशजों के बीच केवल एक ही रास्ता है (जहां यह काम नहीं कर सकता है, उदाहरण के लिए "कई कैस्केड पथ की खोज")।
नोट: मैं, और कई अन्य, कैस्केड हटाए जाने को खतरनाक मानते हैं, इसलिए यदि आप इस विकल्प का उपयोग करते हैं तो इसे अपने डेटाबेस डिज़ाइन में ठीक से दस्तावेज़ करने के लिए बहुत सावधानी बरतें ताकि आप और अन्य डेवलपर्स बाद में खतरे से अधिक यात्रा न करें । मैं इस कारण से जहां भी संभव हो कैस्केडिंग डिलीट से बचता हूं।
जब किसी को छोड़ने और पुनः पंक्तियों के बजाय का उपयोग करके डेटा अद्यतन करता है एक आम सोपानी हटाए साथ की वजह से समस्या है UPDATE
या MERGE
। यह अक्सर देखा जाता है जहां "उन पंक्तियों को अपडेट करें जो पहले से मौजूद हैं, उन्हें डालें जो नहीं हैं" (कभी-कभी यूपीएसईआरटी ऑपरेशन कहा जाता है) की आवश्यकता होती है और MERGE
बयान से अनजान लोगों को यह करना आसान लगता है:
DELETE <all rows that match IDs in the new data>
INSERT <all rows from the new data>
से
-- updates
UPDATE target
SET <col1> = source.<col1>
, <col2> = source.<col2>
...
, <colN> = source.<colN>
FROM <target_table> AS target JOIN <source_table_or_view_or_statement> AS source ON source.ID = target.ID
-- inserts
INSERT <target_table>
SELECT *
FROM <source_table_or_other> AS source
LEFT OUTER JOIN
<target_table> AS target
ON target.ID = source.ID
WHERE target.ID IS NULL
यहाँ समस्या यह है कि डिलीट स्टेटमेंट चाइल्ड रो को कैस्केड करेगा, और इंसर्ट स्टेटमेंट उन्हें रीक्रिएट नहीं करेगा, इसलिए पैरेंट टेबल को अपडेट करते समय आप गलती से चाइल्ड टेबल (एस) से डेटा खो देते हैं।
सारांश
हां, आपको पहले चाइल्ड रो को डिलीट करना होगा।
एक और विकल्प है ON DELETE CASCADE
:।
लेकिन ON DELETE CASCADE
खतरनाक हो सकता है , इसलिए देखभाल के साथ उपयोग करें।
साइड नोट: उपयोग MERGE
(या- UPDATE
और- INSERT
जहां MERGE
उपलब्ध नहीं है) जब आपको UPSERT
ऑपरेशन की आवश्यकता होती है , तो नहीं DELETE
-जगह-के साथ-साथ INSERT
अन्य लोगों द्वारा उपयोग किए गए जाल में गिरने से बचने के लिए ON DELETE CASCADE
।
INVENTORY_ITEMS
दोनोंDELETE
एस के बीच नए जोड़े जा रहे त्रुटियों को देख सकते हैं ।