यह आलेख तालिका भावों के बारे में श्रृंखला का ग्यारहवां भाग है। अब तक, मैंने व्युत्पन्न तालिकाओं और सीटीई को कवर किया है, और हाल ही में विचारों का कवरेज शुरू किया है। भाग 9 में मैंने विचारों की तुलना व्युत्पन्न तालिकाओं और CTE से की, और भाग 10 में मैंने DDL परिवर्तनों और दृश्य की आंतरिक क्वेरी में SELECT * का उपयोग करने के निहितार्थ पर चर्चा की। इस लेख में, मैं संशोधन विचारों पर ध्यान केंद्रित करता हूं।
जैसा कि आप शायद जानते हैं, आपको आधार तालिका में डेटा को अप्रत्यक्ष रूप से नामित तालिका अभिव्यक्तियों जैसे विचारों के माध्यम से संशोधित करने की अनुमति है। आप विचारों के विरुद्ध संशोधन अनुमतियों को नियंत्रित कर सकते हैं। वास्तव में, आप उपयोगकर्ताओं को सीधे अंतर्निहित तालिकाओं को संशोधित करने की अनुमति दिए बिना विचारों के माध्यम से डेटा को संशोधित करने की अनुमति दे सकते हैं।
आपको कुछ जटिलताओं और प्रतिबंधों से अवगत होने की आवश्यकता है जो विचारों के माध्यम से संशोधनों पर लागू होते हैं। दिलचस्प बात यह है कि कुछ समर्थित संशोधन आश्चर्यजनक परिणामों के साथ समाप्त हो सकते हैं, खासकर यदि डेटा को संशोधित करने वाले उपयोगकर्ता को पता नहीं है कि वे एक दृश्य के साथ बातचीत कर रहे हैं। आप CHECK OPTION नामक एक विकल्प का उपयोग करके विचारों के माध्यम से संशोधनों पर और प्रतिबंध लगा सकते हैं, जिसे मैं इस लेख में शामिल करूंगा। कवरेज के हिस्से के रूप में, मैं एक दृश्य में CHECK OPTION और एक टेबल हैंडल संशोधनों में एक CHECK बाधा के बीच एक जिज्ञासु असंगति का वर्णन करता हूँ - विशेष रूप से NULLs को शामिल करने वाले।
नमूना डेटा
इस आलेख के लिए नमूना डेटा के रूप में, मैं ऑर्डर और ऑर्डर विवरण नामक तालिकाओं का उपयोग करूंगा। इन तालिकाओं को tempdb में बनाने के लिए निम्न कोड का उपयोग करें और उन्हें कुछ प्रारंभिक नमूना डेटा के साथ पॉप्युलेट करें:
tempdb का उपयोग करें; यदि मौजूद है तो dbo.OrderDetails, dbo.Orders;GO क्रिएट टेबल dbo.Orders (ऑर्डरिड INT NOT NULL CONSTRAINT PK_Orders PRIMARY KEY, ऑर्डर डेट नॉट न्यूल, शिपडेट डेट न्यूल); INSERT INTO dbo.Orders(orderid, orderdate, Shipddate) VALUES(1, '20210802', '20210804'), (2, '20210802', '20210805'), (3, '20210804', '20210806'), ( 4, '20210826', NULL), (5, '20210827', NULL); तालिका डीबीओ बनाएं। ऑर्डर विवरण (ऑर्डरिड नॉट न्यूल कॉन्स्ट्रेंट एफके_ऑर्डर विवरण_ऑर्डर संदर्भ डीबीओ। ऑर्डर, प्रोडक्टिड INT नॉट न्यूल, मात्रा INT नॉट न्यूल, यूनिटप्राइस न्यूमेरिक (12, 2) न्यूल, डिस्काउंट न्यूमेरिक (5, 4) नॉट न्यूल, ऑर्डर डिटेल्स पीके कुंजी (ऑर्डरिड, प्रोडक्टिड)); INSERT INTO dbo.OrderDetails(orderid, productid, qty, Unitprice, छूट) VALUES(1, 1001, 5, 10.50, 0.05), (1, 1004, 2, 20.00, 0.00), (2, 1003, 1, 52.99, 0.10), (3, 1001, 1, 10.50, 0.05), (3, 1003, 2, 54.99, 0.10), (4, 1001, 2, 10.50, 0.05), (4, 1004, 1, 20.30, 0.00) , (4, 1005, 1, 30.10, 0.05), (5, 1003, 5, 54.99, 0.00), (5, 1006, 2, 12.30, 0.08);
ऑर्डर तालिका में ऑर्डर हेडर होते हैं, और ऑर्डर विवरण तालिका में ऑर्डर लाइन होती है। शिप नहीं किए गए ऑर्डर में शिप किए गए दिनांक कॉलम में एक NULL होता है। यदि आप एक ऐसा डिज़ाइन पसंद करते हैं जो NULLs का उपयोग नहीं करता है, तो आप "99991231" जैसे अनशिप किए गए ऑर्डर के लिए एक विशिष्ट भविष्य की तारीख का उपयोग कर सकते हैं।
विकल्प जांचें
उन परिस्थितियों को समझने के लिए जहां आप किसी दृश्य की परिभाषा के हिस्से के रूप में चेक विकल्प का उपयोग करना चाहते हैं, हम पहले यह जांचेंगे कि जब आप इसका उपयोग नहीं करते हैं तो क्या हो सकता है।
निम्नलिखित कोड FastOrders नामक एक दृश्य बनाता है जो सात दिनों के भीतर भेजे गए आदेशों का प्रतिनिधित्व करता है:
dbo बनाएं या बदलें।दिए जाने के दो दिन बाद शिप किए गए ऑर्डर को दृश्य के माध्यम से सम्मिलित करने के लिए निम्न कोड का उपयोग करें:
dbo.FastOrders में INSERT करें (ऑर्डरिड, ऑर्डरडेट, शिप की गई तारीख) VALUES(6, '20210805', '20210807');दृश्य को क्वेरी करें:
चुनें * dbo.FastOrders से;आपको निम्न आउटपुट मिलता है, जिसमें नया ऑर्डर शामिल है:
आदेश-आदेश भेजने की तिथि--------------------------------2021-08-02 2021-08-042 2021 -08-02 2021-08-053 2021-08-04 2021-08-066 2021-08-05 2021-08-07अंतर्निहित तालिका को क्वेरी करें:
चुनें * dbo.Orders से;आपको निम्न आउटपुट मिलता है, जिसमें नया ऑर्डर शामिल है:
आदेश-आदेश भेजने की तिथि--------------------------------2021-08-02 2021-08-042 2021 -08-02 2021-08-053 2021-08-04 2021-08-064 2021-08-26 NULL5 2021-08-27 NULL6 2021-08-05 2021-08-07पंक्ति को अंतर्निहित आधार तालिका में दृश्य के माध्यम से सम्मिलित किया गया था।
इसके बाद, दृश्य के आंतरिक क्वेरी फ़िल्टर का खंडन करते हुए, दृश्य के 10 दिनों के बाद शिप की गई पंक्ति को दृश्य के माध्यम से डालें:
dbo.FastOrders में INSERT करें (ऑर्डरिड, ऑर्डरडेट, शिप की गई तारीख) VALUES(7, '20210805', '20210815');एक पंक्ति प्रभावित होने की रिपोर्ट करते हुए, कथन सफलतापूर्वक पूरा हुआ।
दृश्य को क्वेरी करें:
चुनें * dbo.FastOrders से;आपको निम्न आउटपुट मिलता है, जिसमें नया ऑर्डर शामिल नहीं है:
आदेश-आदेश भेजने की तिथि--------------------------------2021-08-02 2021-08-042 2021 -08-02 2021-08-053 2021-08-04 2021-08-066 2021-08-05 2021-08-07यदि आप जानते हैं कि FastOrders एक दृश्य है, तो यह सब समझदार लग सकता है। आखिरकार, पंक्ति को अंतर्निहित तालिका में डाला गया था, और यह दृश्य के आंतरिक क्वेरी फ़िल्टर को संतुष्ट नहीं करता है। लेकिन अगर आप इस बात से अनजान हैं कि FastOrders एक दृश्य है और आधार तालिका नहीं है, तो यह व्यवहार आश्चर्यजनक प्रतीत होगा।
अंतर्निहित आदेश तालिका को क्वेरी करें:
चुनें * dbo.Orders से;आपको निम्न आउटपुट मिलता है, जिसमें नया ऑर्डर शामिल है:
आदेश-आदेश भेजने की तिथि--------------------------------2021-08-02 2021-08-042 2021 -08-02 2021-08-053 2021-08-04 2021-08-064 2021-08-26 NULL5 2021-08-27 NULL6 2021-08-05 2021-08-077 2021-08-05 2021-08- 15आप एक समान आश्चर्यजनक व्यवहार का अनुभव कर सकते हैं यदि आप दृश्य के माध्यम से उस पंक्ति में शिप किए गए दिनांक मान को अपडेट करते हैं जो वर्तमान में दृश्य का हिस्सा है जो इसे अब दृश्य के भाग के रूप में योग्य नहीं बनाता है। इस तरह के अपडेट को सामान्य रूप से अनुमति दी जाती है, लेकिन फिर से, यह अंतर्निहित आधार तालिका में होता है। यदि आप इस तरह के एक अद्यतन के बाद दृश्य से पूछताछ करते हैं, तो संशोधित पंक्ति चली गई प्रतीत होती है। व्यवहार में यह अभी भी अंतर्निहित तालिका में है, इसे अब दृश्य का हिस्सा नहीं माना जाता है।
आपके द्वारा पहले जोड़ी गई पंक्तियों को हटाने के लिए निम्न कोड चलाएँ:
dbo से हटाएं।आदेश जहां आदेश>=6;यदि आप उन संशोधनों को रोकना चाहते हैं जो दृश्य के आंतरिक क्वेरी फ़िल्टर के साथ विरोध करते हैं, तो दृश्य परिभाषा के भाग के रूप में आंतरिक क्वेरी के अंत में चेक विकल्प के साथ जोड़ें, जैसे:
डीबीओ बनाएं या बदलें। फास्ट ऑर्डर डीबीओ से ऑर्डर, ऑर्डर की तारीख, शिप की गई तारीख चुनें। ऑर्डर जहां दिनांकित (दिन, ऑर्डर की तारीख, शिप की गई तारीख) <=7 चेक विकल्प के साथ; जाओदृश्य के माध्यम से डालने और अपडेट की अनुमति तब तक दी जाती है जब तक वे आंतरिक क्वेरी के फ़िल्टर का अनुपालन करते हैं। अन्यथा, उन्हें अस्वीकार कर दिया जाता है।
उदाहरण के लिए, दृश्य के माध्यम से एक पंक्ति सम्मिलित करने के लिए निम्न कोड का उपयोग करें जो आंतरिक क्वेरी फ़िल्टर के साथ विरोध नहीं करता है:
dbo.FastOrders में INSERT करें (ऑर्डरिड, ऑर्डरडेट, शिप की गई तारीख) VALUES(6, '20210805', '20210807');पंक्ति सफलतापूर्वक जोड़ दी गई है।
एक पंक्ति सम्मिलित करने का प्रयास जो फ़िल्टर के साथ विरोध करता है:
dbo.FastOrders में INSERT करें (ऑर्डरिड, ऑर्डरडेट, शिप की गई तारीख) VALUES(7, '20210805', '20210815');इस बार पंक्ति को निम्न त्रुटि के साथ अस्वीकार कर दिया गया है:
स्तर 16, राज्य 1, पंक्ति 135
प्रयास किया गया सम्मिलित या अद्यतन विफल हुआ क्योंकि लक्ष्य दृश्य या तो CHECK विकल्प के साथ निर्दिष्ट करता है या एक ऐसे दृश्य का विस्तार करता है जो CHECK विकल्प के साथ निर्दिष्ट करता है और ऑपरेशन के परिणामस्वरूप एक या अधिक पंक्तियाँ योग्य नहीं थीं विकल्प बाधा की जाँच करें।पूर्ण विसंगतियां
यदि आप कुछ समय के लिए टी-एसक्यूएल के साथ काम कर रहे हैं, तो आप उपरोक्त संशोधन जटिलताओं के बारे में अच्छी तरह जानते हैं और फ़ंक्शन चेक विकल्प कार्य करता है। अक्सर, अनुभवी लोग भी CHECK Option की NULL हैंडलिंग को आश्चर्यजनक पाते हैं। वर्षों से मैं एक आधार तालिका की परिभाषा में CHECK बाधा के समान कार्य करने के रूप में CHECK विकल्प के बारे में सोचता था। इसी तरह मैं इस विकल्प के बारे में लिखते या पढ़ाते समय इसका वर्णन करता था। वास्तव में, जब तक फ़िल्टर विधेय में कोई NULL शामिल नहीं है, तब तक दोनों को समान शब्दों में सोचना सुविधाजनक है। वे ऐसे मामले में लगातार व्यवहार करते हैं- उन पंक्तियों को स्वीकार करते हैं जो विधेय से सहमत होते हैं और उन लोगों को अस्वीकार करते हैं जो इसके साथ संघर्ष करते हैं। हालांकि, दोनों एनयूएलएल को असंगत रूप से संभालते हैं।
चेक विकल्प का उपयोग करते समय, दृश्य के माध्यम से संशोधन की अनुमति तब तक दी जाती है जब तक कि विधेय सत्य का मूल्यांकन करता है, अन्यथा इसे अस्वीकार कर दिया जाता है। इसका मतलब यह है कि जब दृश्य का विधेय गलत या अज्ञात (जब एक NULL शामिल होता है) का मूल्यांकन करता है, तो इसे अस्वीकार कर दिया जाता है। एक CHECK बाधा के साथ, संशोधन की अनुमति तब दी जाती है जब बाधा का विधेय सत्य या अज्ञात का मूल्यांकन करता है, और जब विधेय का मूल्यांकन असत्य होता है तो उसे अस्वीकार कर दिया जाता है। यह एक दिलचस्प अंतर है! पहले, आइए इसे व्यवहार में देखें, फिर हम इस असंगति के पीछे के तर्क को समझने की कोशिश करेंगे।
दृश्य के माध्यम से एक पूर्ण शिप की गई तिथि के साथ एक पंक्ति सम्मिलित करने का प्रयास:
dbo.FastOrders में INSERT करें।दृश्य का विधेय अज्ञात का मूल्यांकन करता है, और पंक्ति को निम्न त्रुटि के साथ अस्वीकार कर दिया जाता है:
Msg 550, Level 16, State 1, Line 147
प्रयास किया गया इंसर्ट या अपडेट विफल रहा क्योंकि लक्ष्य दृश्य या तो CHECK OPTION के साथ निर्दिष्ट करता है या एक ऐसे दृश्य को फैलाता है जो CHECK OPTION के साथ निर्दिष्ट करता है और ऑपरेशन के परिणामस्वरूप एक या अधिक पंक्तियाँ नहीं होती हैं CHECK Option बाधा के तहत अर्हता प्राप्त करें।आइए एक CHECK बाधा के साथ आधार तालिका के विरुद्ध एक समान प्रविष्टि का प्रयास करें। हमारे आदेश की तालिका परिभाषा में ऐसी बाधा जोड़ने के लिए निम्नलिखित कोड का उपयोग करें:
ALTER TABLE dbo.Orders ADD CONSTRAINT CHK_Orders_FastOrder CHECK(DATEDIFF(दिन, ऑर्डर की तारीख, शिप करने की तारीख) <=7);सबसे पहले, यह सुनिश्चित करने के लिए कि जब कोई एनयूएलएल शामिल नहीं है तो बाधा काम करती है, ऑर्डर की तारीख से 10 दिन दूर शिप की गई तारीख के साथ निम्नलिखित ऑर्डर डालने का प्रयास करें:
dbo.Orders में INSERT करें (ऑर्डरिड, ऑर्डरडेट, शिप की गई तारीख) VALUES(7, '20210805', '20210815');इस प्रविष्टि का प्रयास निम्न त्रुटि के साथ अस्वीकार कर दिया गया है:
संदेश 547, स्तर 16, राज्य 0, पंक्ति 159
INSERT कथन CHECK बाधा "CHK_Orders_FastOrder" के विपरीत है। डेटाबेस "tempdb", तालिका "dbo.Orders" में विरोध हुआ।एक पूर्ण शिप की गई तिथि के साथ एक पंक्ति सम्मिलित करने के लिए निम्न कोड का उपयोग करें:
dbo.Orders में INSERT करें (ऑर्डरिड, ऑर्डरडेट, शिप की गई तारीख) VALUES(8, '20210828', NULL);एक CHECK बाधा को झूठे मामलों को अस्वीकार करने के लिए माना जाता है, लेकिन हमारे मामले में विधेय अज्ञात का मूल्यांकन करता है, इसलिए पंक्ति को सफलतापूर्वक जोड़ा जाता है।
आदेश तालिका को क्वेरी करें:
चुनें * dbo.Orders से;आप आउटपुट में नया ऑर्डर देख सकते हैं:
आदेश-आदेश भेजने की तिथि--------------------------------2021-08-02 2021-08-042 2021 -08-02 2021-08-053 2021-08-04 2021-08-064 2021-08-26 NULL5 2021-08-27 NULL6 2021-08-05 2021-08-078 2021-08-28 NULLइस असंगति के पीछे क्या तर्क है? आप तर्क दे सकते हैं कि एक CHECK बाधा केवल तभी लागू की जानी चाहिए जब बाधा के विधेय का स्पष्ट रूप से उल्लंघन किया जाता है, जिसका अर्थ है कि जब यह असत्य का मूल्यांकन करता है। इस तरह, यदि आप विचाराधीन कॉलम में NULLs को अनुमति देना चुनते हैं, तो कॉलम में NULLs वाली पंक्तियों को अनुमति दी जाती है, भले ही बाधा का विधेय अज्ञात का मूल्यांकन करता हो। हमारे मामले में, हम शिप किए गए ऑर्डर के कॉलम में NULL के साथ अनशिप्ड ऑर्डर का प्रतिनिधित्व करते हैं, और हम केवल शिप किए गए ऑर्डर के लिए "फास्ट ऑर्डर" नियम लागू करते हुए टेबल में अनशिप्ड ऑर्डर की अनुमति देते हैं।
एक दृश्य के साथ विभिन्न तर्कों का उपयोग करने का तर्क यह है कि दृश्य के माध्यम से संशोधन की अनुमति केवल तभी दी जानी चाहिए जब परिणाम पंक्ति दृश्य का एक मान्य हिस्सा हो। यदि दृश्य का विधेय अज्ञात का मूल्यांकन करता है, उदाहरण के लिए, जब शिप की गई तिथि NULL होती है, तो परिणाम पंक्ति दृश्य का मान्य भाग नहीं होती है, इसलिए इसे अस्वीकार कर दिया जाता है। केवल वे पंक्तियाँ जिनके लिए विधेय सत्य का मूल्यांकन करता है, वे दृश्य का एक मान्य हिस्सा हैं और इसलिए अनुमति दी जाती है।
एनयूएलएल भाषा में बहुत जटिलता जोड़ते हैं। उन्हें पसंद करें या नहीं, अगर आपका डेटा उनका समर्थन करता है, तो आप यह सुनिश्चित करना चाहते हैं कि आप समझते हैं कि टी-एसक्यूएल उन्हें कैसे संभालता है।
इस बिंदु पर आप ऑर्डर तालिका से CHECK बाधा को छोड़ सकते हैं और सफाई के लिए FastOrders दृश्य को भी छोड़ सकते हैं:
ALTER TABLE dbo.Orders DROP CONSTRAINT CHK_Orders_FastOrder;DBO.FastOrders मौजूद होने पर ड्रॉप व्यू;टॉप/ऑफसेट-फ़ेच प्रतिबंध
टॉप और ऑफ़सेट-फ़ेच फ़िल्टर वाले दृश्यों के माध्यम से संशोधनों की सामान्य रूप से अनुमति है। हालांकि, चेक विकल्प के बिना परिभाषित विचारों के बारे में हमारी पिछली चर्चा की तरह, इस तरह के संशोधन का परिणाम उपयोगकर्ता को अजीब लग सकता है यदि वे अनजान हैं कि वे एक दृश्य के साथ बातचीत कर रहे हैं।
एक उदाहरण के रूप में हाल के आदेशों का प्रतिनिधित्व करने वाले निम्नलिखित दृश्य पर विचार करें:
dbo.RecentOrders देखें या बनाएं। शीर्ष (5) ऑर्डर करें, ऑर्डर करने की तारीख, डीबीओ से शिप करने की तारीख। ऑर्डर की तारीख डीईएससी के अनुसार ऑर्डर करें, डीईएससी को ऑर्डर करें;जाओहाल के आदेशों के माध्यम से सम्मिलित करने के लिए निम्नलिखित कोड का उपयोग करें छह आदेश देखें:
dbo.RecentOrders में INSERT करें। ), (12, '20210830', '20210902'), (13, '20210830', '20210903'), (14, '20210831', '20210903');दृश्य को क्वेरी करें:
चुनें* dbo.RecentOrders से;आपको निम्न आउटपुट मिलता है:
आदेश ऑर्डर करने की तिथि शिप करने की तिथि----------- ------------------------- 2021-08-31 2021-09-0313 2021 -08-30 2021-09-0312 2021-08-30 2021-09-0211 2021-08-29 2021-08-318 2021-08-28 NULLसम्मिलित किए गए छह आदेशों में से, केवल चार दृश्य का हिस्सा हैं। यह पूरी तरह से समझदार लगता है यदि आप जानते हैं कि आप एक ऐसे दृश्य को क्वेरी कर रहे हैं जो एक TOP फ़िल्टर वाली क्वेरी पर आधारित है। लेकिन यह अजीब लग सकता है यदि आप सोच रहे हैं कि आप आधार तालिका को क्वेरी कर रहे हैं।
अंतर्निहित आदेश तालिका को सीधे क्वेरी करें:
चुनें * dbo.Orders से;आपको सभी जोड़े गए ऑर्डर दिखाते हुए निम्न आउटपुट मिलता है:
आदेश-आदेश भेजने की तिथि--------------------------------2021-08-02 2021-08-042 2021 -08-02 2021-08-053 2021-08-04 2021-08-064 2021-08-26 NULL5 2021-08-27 NULL6 2021-08-05 2021-08-078 2021-08-28 NULL9 2021-08 -01 2021-08-0310 2021-08-02 2021-08-0411 2021-08-29 2021-08-3112 2021-08-30 2021-09-0213 2021-08-30 2021-09-0314 2021-08 -31 2021-09-03यदि आप दृश्य परिभाषा में चेक विकल्प जोड़ते हैं, तो दृश्य के विरुद्ध INSERT और अद्यतन विवरण अस्वीकार कर दिए जाएंगे। इस परिवर्तन को लागू करने के लिए निम्नलिखित कोड का प्रयोग करें:
डीबीओ बनाएं या बदलें। हाल के आदेश जैसे शीर्ष (5) का चयन करें, ऑर्डर की तारीख, डीबीओ से शिप की गई तारीख। ऑर्डर की तारीख डीईएससी के अनुसार ऑर्डर करें, चेक विकल्प के साथ डीईएससी का ऑर्डर करें;जाओदृश्य के माध्यम से एक आदेश जोड़ने का प्रयास करें:
dbo में डालें।आपको निम्न त्रुटि मिलती है:
Msg 4427, स्तर 16, राज्य 1, पंक्ति 247
दृश्य "dbo.RecentOrders" को अद्यतन नहीं कर सकता क्योंकि यह या इसके संदर्भ में एक दृश्य चेक विकल्प के साथ बनाया गया था और इसकी परिभाषा में एक TOP या OFFSET खंड शामिल है।SQL सर्वर यहाँ बहुत स्मार्ट होने का प्रयास नहीं करता है। यह परिवर्तन को अस्वीकार करने वाला है, भले ही आप जिस पंक्ति को सम्मिलित करने का प्रयास करते हैं वह उस बिंदु पर दृश्य का एक मान्य हिस्सा बन जाएगा। उदाहरण के लिए, अधिक हाल की तारीख वाला एक ऑर्डर जोड़ने का प्रयास करें जो इस समय शीर्ष 5 में आ जाएगा:
dbo में सम्मिलित करें।सम्मिलित करने का प्रयास अभी भी निम्न त्रुटि के साथ अस्वीकृत है:
संदेश 4427, स्तर 16, राज्य 1, पंक्ति 254
"dbo.RecentOrders" दृश्य को अद्यतन नहीं कर सकता क्योंकि यह या इसके संदर्भ में एक दृश्य चेक विकल्प के साथ बनाया गया था और इसकी परिभाषा में एक TOP या OFFSET खंड शामिल है।दृश्य के माध्यम से एक पंक्ति को अद्यतन करने का प्रयास करें:
अद्यतन dbo.RecentOrders SET शिपडेट =DATEADD(दिन, 2, ऑर्डरडेट);इस मामले में निम्न त्रुटि के साथ प्रयास किए गए परिवर्तन को भी अस्वीकार कर दिया गया है:
संदेश 4427, स्तर 16, राज्य 1, पंक्ति 260
"dbo.RecentOrders" दृश्य को अद्यतन नहीं कर सकता क्योंकि यह या इसके संदर्भ में एक दृश्य चेक विकल्प के साथ बनाया गया था और इसकी परिभाषा में एक TOP या OFFSET खंड शामिल है।ध्यान रखें कि TOP या OFFSET-FETCH और CHECK विकल्प वाली क्वेरी के आधार पर किसी दृश्य को परिभाषित करने से दृश्य के माध्यम से INSERT और UPDATE स्टेटमेंट के लिए समर्थन की कमी हो जाएगी।
ऐसे दृश्य के माध्यम से हटाने का समर्थन किया जाता है। सभी मौजूदा पांच सबसे हाल के आदेशों को हटाने के लिए निम्न कोड चलाएँ:
dbo.RecentOrders से हटाएं;आदेश सफलतापूर्वक पूरा हुआ।
तालिका को क्वेरी करें:
चुनें * dbo.Orders से;आईडी 8, 11, 12, 13, और 14 के साथ ऑर्डर को हटाने के बाद आपको निम्न आउटपुट मिलता है।
आदेश-आदेश भेजने की तिथि--------------------------------2021-08-02 2021-08-042 2021 -08-02 2021-08-053 2021-08-04 2021-08-064 2021-08-26 NULL5 2021-08-27 NULL6 2021-08-05 2021-08-079 2021-08-01 2021-08- 0310 2021-08-02 2021-08-04इस बिंदु पर, अगले भाग में उदाहरण चलाने से पहले सफाई के लिए निम्न कोड चलाएँ:
dbo से हटाएं।आदेश जहां आदेश> 5; ड्रॉप व्यू अगर मौजूद है dbo.RecentOrders;जुड़ता है
एक से अधिक तालिकाओं को जोड़ने वाले दृश्य को अद्यतन करना समर्थित है, जब तक कि अंतर्निहित आधार तालिकाओं में से केवल एक परिवर्तन से प्रभावित होता है।
एक उदाहरण के रूप में ऑर्डर और ऑर्डर विवरण में शामिल होने के निम्नलिखित दृश्य पर विचार करें:
dbo बनाएं या बदलें। O.orderid पर OD =OD.orderid;GOदृश्य के माध्यम से एक पंक्ति सम्मिलित करने का प्रयास करें, ताकि दोनों अंतर्निहित आधार तालिकाएं प्रभावित हों:
dbo.OrdersOrderDetails में INSERT करें (ऑर्डरिड, ऑर्डरडेट, शिपडेट, प्रोडक्टिड, मात्रा, यूनिटप्राइस, डिस्काउंट) VALUES(6, '20210828', NULL, 1001, 5, 10.50, 0.05);आपको निम्न त्रुटि मिलती है:
संदेश 4405, स्तर 16, राज्य 1, पंक्ति 306
देखें या कार्य करें 'dbo.OrdersOrderDetails' अद्यतन योग्य नहीं है क्योंकि संशोधन एकाधिक आधार तालिकाओं को प्रभावित करता है।दृश्य के माध्यम से एक पंक्ति सम्मिलित करने का प्रयास करें, ताकि केवल आदेश तालिका प्रभावित हो:
डाबो में सम्मिलित करें।यह आदेश सफलतापूर्वक पूरा होता है, और पंक्ति को अंतर्निहित आदेश तालिका में सम्मिलित किया जाता है।
लेकिन क्या होगा यदि आप ऑर्डर विवरण तालिका में दृश्य को एक पंक्ति डालने में सक्षम होना चाहते हैं? वर्तमान दृश्य परिभाषा के साथ, यह असंभव है (एक तरफ ट्रिगर करने के बजाय) क्योंकि दृश्य ऑर्डर तालिका से ऑर्डरिड कॉलम देता है न कि ऑर्डर विवरण तालिका से। पर्याप्त है कि ऑर्डर विवरण तालिका से एक कॉलम जो किसी भी तरह से अपना मूल्य स्वचालित रूप से प्राप्त नहीं कर सकता है वह दृश्य के माध्यम से ऑर्डर विवरण में सम्मिलन को रोकने के लिए दृश्य का हिस्सा नहीं है। बेशक, आप हमेशा यह तय कर सकते हैं कि दृश्य में ऑर्डर से ऑर्डर और ऑर्डर विवरण से ऑर्डरिड दोनों शामिल होंगे। ऐसी स्थिति में, आपको अलग-अलग उपनामों के साथ दो कॉलम असाइन करने होंगे क्योंकि दृश्य द्वारा दर्शाए गए तालिका के शीर्षक में अद्वितीय कॉलम नाम होने चाहिए।
दोनों स्तंभों को शामिल करने के लिए दृश्य परिभाषा को बदलने के लिए निम्न कोड का उपयोग करें, ऑर्डर से एक को O_orderid के रूप में और एक को OrderDetails से OD_orderid के रूप में अलियासिंग करें:
डीबीओ बनाएं या बदलें। O.orderid =OD.orderid;GOपर OD के रूप में dbo.OrderDetails के रूप में शामिल होंलक्ष्य कॉलम सूची किस तालिका से आ रही है, इस पर निर्भर करते हुए अब आप ऑर्डर या ऑर्डर विवरण में दृश्य के माध्यम से पंक्तियां सम्मिलित कर सकते हैं। ऑर्डर विवरण में दृश्य के माध्यम से ऑर्डर 6 से जुड़ी कुछ ऑर्डर लाइन डालने के लिए यहां एक उदाहरण दिया गया है:
dbo.OrdersOrderDetails में डालें(OD_orderid, productid, qty, Unitprice, छूट) VALUES(6, 1001, 5, 10.50, 0.05), (6, 1002, 5, 20.00, 0.05);पंक्तियों को सफलतापूर्वक जोड़ दिया गया है।
दृश्य को क्वेरी करें:
चुनें * dbo.OrdersOrderDetails से जहां O_orderid =6;आपको निम्न आउटपुट मिलता है:
O_orderid आदेश शिप करने की तिथि OD_orderid उत्पादआईडी मात्रा इकाई मूल्य छूट---------------------------------------- ------------------------------------------- 2021-08-28 नल 6 1001 5 10.50 0.05006 2021-08-28 नल 6 1002 5 20.00 0.0500दृश्य के माध्यम से अद्यतन विवरण पर एक समान प्रतिबंध लागू होता है। अद्यतनों की अनुमति तब तक है जब तक केवल एक अंतर्निहित आधार तालिका प्रभावित होती है। लेकिन आपको स्टेटमेंट में दोनों तरफ से कॉलम को संदर्भित करने की अनुमति है, जब तक कि केवल एक पक्ष को संशोधित किया जाता है।
एक उदाहरण के रूप में, निम्नलिखित अद्यतन विवरण दृश्य के माध्यम से उस पंक्ति की ऑर्डर तिथि निर्धारित करता है जहां ऑर्डर लाइन की ऑर्डर आईडी 6 है और उत्पाद आईडी 1001 से "2021901:" है।
अद्यतन dbo.OrdersOrderDetails SET orderdate ='2021901' जहां OD_orderid =6 और productid =1001;हम इस स्टेटमेंट को अपडेट स्टेटमेंट 1 कहेंगे।
अपडेट निम्न संदेश के साथ सफलतापूर्वक पूर्ण होता है:
(1 पंक्ति प्रभावित)यहां ध्यान देने योग्य बात यह है कि ऑर्डर विवरण तालिका के तत्वों द्वारा स्टेटमेंट फ़िल्टर किया गया है, फिर भी संशोधित कॉलम ऑर्डरडेट ऑर्डर टेबल से है। इसलिए, SQL सर्वर इस कथन के लिए जो योजना बनाता है, उसमें यह पता लगाना होता है कि ऑर्डर तालिका में किन आदेशों को संशोधित करने की आवश्यकता है। इस कथन की योजना चित्र 1 में दिखाई गई है।
चित्र 1:अद्यतन विवरण 1 के लिए योजना
आप देख सकते हैं कि ऑर्डर विवरण पक्ष को ऑर्डरिड =6 और प्रोडक्टिड =1001 और ऑर्डर पक्ष को ऑर्डरिड =6, दोनों को मिलाकर फ़िल्टर करके योजना कैसे शुरू होती है। परिणाम केवल एक पंक्ति है। इस गतिविधि से बचने का एकमात्र प्रासंगिक हिस्सा यह है कि ऑर्डर तालिका में कौन सी ऑर्डर आईडी उन पंक्तियों का प्रतिनिधित्व करती है जिन्हें अद्यतन करने की आवश्यकता है। हमारे मामले में, यह ऑर्डर आईडी 6 के साथ ऑर्डर है। इसके अलावा, कंप्यूट स्केलर ऑपरेटर एक्सप्र 1002 नामक एक सदस्य को उस मूल्य के साथ तैयार करता है जो स्टेटमेंट लक्ष्य ऑर्डर के ऑर्डरडेट कॉलम को असाइन करेगा। क्लस्टर्ड इंडेक्स अपडेट ऑपरेटर के साथ योजना का अंतिम भाग ऑर्डर आईडी 6 के साथ ऑर्डर में वास्तविक अपडेट को लागू करता है, इसके ऑर्डरडेट मान को Expr1002 पर सेट करता है।
यहां पर जोर देने के लिए मुख्य बिंदु केवल एक पंक्ति है जिसमें ऑर्डर तालिका में ऑर्डर 6 अपडेट किया गया है। फिर भी इस पंक्ति में ऑर्डर विवरण तालिका के साथ जुड़ने के परिणाम में दो मिलान हैं- एक उत्पाद आईडी 1001 (जिसे मूल अपडेट फ़िल्टर किया गया) और दूसरा उत्पाद आईडी 1002 (जिसे मूल अपडेट फ़िल्टर नहीं किया गया था) के साथ। इस बिंदु पर दृश्य को क्वेरी करें, क्रम आईडी 6 के साथ सभी पंक्तियों को फ़िल्टर करें:
चुनें * dbo.OrdersOrderDetails से जहां O_orderid =6;आपको निम्न आउटपुट मिलता है:
O_orderid आदेश शिप करने की तिथि OD_orderid उत्पादआईडी मात्रा इकाई मूल्य छूट---------------------------------------- ------------------------------------------- 2021-09-01 NULL 6 1001 5 10.50 0.05006 2021-09-01 नल 6 1002 5 20.00 0.0500दोनों पंक्तियाँ नई ऑर्डर तिथि दिखाती हैं, भले ही मूल अपडेट ने केवल उत्पाद आईडी 1001 के साथ पंक्ति को फ़िल्टर किया हो। फिर भी, यह पूरी तरह से समझदार प्रतीत होना चाहिए यदि आप जानते हैं कि आप एक ऐसे दृश्य के साथ बातचीत कर रहे हैं जो कवर के नीचे दो आधार तालिकाओं को जोड़ता है, लेकिन अगर आपको इसका एहसास नहीं है तो यह बहुत अजीब लग सकता है।
मजे की बात यह है कि SQL सर्वर नॉनडेटर्मिनिस्टिक अपडेट का भी समर्थन करता है जहां कई स्रोत पंक्तियाँ (हमारे मामले में ऑर्डर विवरण से) एक लक्ष्य पंक्ति (हमारे मामले में ऑर्डर में) से मेल खाती हैं। सैद्धांतिक रूप से, ऐसे मामले को संभालने का एक तरीका इसे अस्वीकार करना होगा। दरअसल, एक MERGE स्टेटमेंट के साथ जहां कई स्रोत पंक्तियाँ एक लक्ष्य पंक्ति से मेल खाती हैं, SQL सर्वर प्रयास को अस्वीकार कर देता है। लेकिन शामिल होने के आधार पर अद्यतन के साथ नहीं, चाहे प्रत्यक्ष या परोक्ष रूप से नामित तालिका अभिव्यक्ति के माध्यम से एक दृश्य। SQL सर्वर इसे केवल एक नियतात्मक अद्यतन के रूप में संभालता है।
निम्नलिखित उदाहरण पर विचार करें, जिसे हम कथन 2 के रूप में संदर्भित करेंगे:
अद्यतन dbo.OrderDetails SET orderdate =मामला जब इकाई मूल्य>=20.00 तब '20210902' ELSE '20210903' END जहां OD_orderid =6;उम्मीद है कि आप मुझे क्षमा करेंगे कि यह एक काल्पनिक उदाहरण है, लेकिन यह बात को स्पष्ट करता है।
दृश्य में दो क्वालिफाइंग पंक्तियां हैं, जो अंतर्निहित ऑर्डर विवरण तालिका से दो क्वालिफाइंग स्रोत ऑर्डर लाइन पंक्तियों का प्रतिनिधित्व करती हैं। लेकिन अंतर्निहित आदेश तालिका में केवल एक योग्यता लक्ष्य पंक्ति है। इसके अलावा, एक स्रोत ऑर्डर विवरण पंक्ति में, असाइन किया गया केस अभिव्यक्ति एक मान ('20210902') देता है और दूसरे स्रोत ऑर्डर विवरण पंक्ति में यह एक और मान ('20210903') देता है। इस मामले में SQL सर्वर को क्या करना चाहिए? जैसा कि उल्लेख किया गया है, मेर्ज स्टेटमेंट के साथ एक समान स्थिति के परिणामस्वरूप एक त्रुटि होगी, प्रयास किए गए परिवर्तन को अस्वीकार कर दिया जाएगा। फिर भी एक अद्यतन विवरण के साथ, SQL सर्वर बस एक सिक्का फ़्लिप करता है। तकनीकी रूप से, यह किसी भी नामक आंतरिक समग्र फ़ंक्शन का उपयोग करके किया जाता है।
इसलिए, हमारा अपडेट सफलतापूर्वक पूरा होता है, 1 पंक्ति प्रभावित होने की रिपोर्ट करता है। इस कथन की योजना चित्र 2 में दिखाई गई है।
चित्र 2:अद्यतन विवरण 2 के लिए योजनाशामिल होने के परिणाम में दो पंक्तियाँ हैं। ये दो पंक्तियाँ अद्यतन के लिए स्रोत पंक्तियाँ बन जाती हैं। लेकिन फिर किसी भी फ़ंक्शन को लागू करने वाला एक समग्र ऑपरेटर इन स्रोत पंक्तियों से एक (कोई भी) ऑर्डरिड मान और एक (कोई भी) यूनिटप्राइस मान चुनता है। दोनों स्रोत पंक्तियों का क्रमांक समान है, इसलिए सही क्रम को संशोधित किया जाएगा। लेकिन यह इस बात पर निर्भर करता है कि कौन सा स्रोत यूनिटप्राइस वैल्यू को कोई एग्रीगेट चुनना समाप्त करता है, यह निर्धारित करेगा कि CASE एक्सप्रेशन किस मूल्य पर वापस आएगा, फिर लक्ष्य ऑर्डर में अपडेटेड ऑर्डरडेट वैल्यू के रूप में उपयोग किया जाएगा। आप निश्चित रूप से इस तरह के अपडेट का समर्थन करने के खिलाफ एक तर्क देख सकते हैं, लेकिन यह SQL सर्वर में पूरी तरह से समर्थित है।
आइए इस परिवर्तन के परिणाम को देखने के लिए दृश्य से पूछें (अब परिणाम के लिए अपना दांव लगाने का समय है):
चुनें * dbo.OrdersOrderDetails से जहां O_orderid =6;मुझे निम्न आउटपुट मिला:
O_orderid आदेश शिप करने की तिथि OD_orderid उत्पादआईडी मात्रा इकाई मूल्य छूट---------------------------------------- -------------------------------------------- 2021-09-03 नल 6 1001 5 10.50 0.05006 2021-09-03 नल 6 1002 5 20.00 0.0500दो स्रोत यूनिटप्राइस मानों में से केवल एक को चुना गया था और एकल लक्ष्य ऑर्डर के ऑर्डरडेट को निर्धारित करने के लिए उपयोग किया गया था, फिर भी दृश्य को क्वेरी करते समय, ऑर्डरडेट मान दोनों मिलान ऑर्डर लाइनों के लिए दोहराया जाता है। जैसा कि आप महसूस कर सकते हैं, परिणाम दूसरी तारीख (2021-09-02) के समान ही हो सकता था क्योंकि इकाई मूल्य मूल्य का चुनाव गैर-निर्धारक था। निराला सामान!
इसलिए, कुछ शर्तों के तहत, कई अंतर्निहित तालिकाओं में शामिल होने वाले विचारों के माध्यम से INSERT और UPDATE कथनों की अनुमति है। हालांकि, ऐसे विचारों के खिलाफ हटाने की अनुमति नहीं है। SQL सर्वर कैसे बता सकता है कि किन पक्षों को हटाने का लक्ष्य माना जाता है?
इस तरह के डिलीट को व्यू के माध्यम से लागू करने का प्रयास यहां दिया गया है:
dbo.OrdersOrderDetails से हटाएं जहां O_orderid =6;यह प्रयास निम्न त्रुटि के साथ अस्वीकार कर दिया गया है:
संदेश 4405, स्तर 16, राज्य 1, पंक्ति 377
देखें या कार्य करें 'dbo.OrdersOrderDetails' अद्यतन योग्य नहीं है क्योंकि संशोधन एकाधिक आधार तालिकाओं को प्रभावित करता है।इस समय, सफाई के लिए निम्न कोड चलाएँ:
डीबीओ से हटाएं। ऑर्डर विवरण जहां ऑर्डरिड =6; डीबीओ से हटाएं। ऑर्डर जहां ऑर्डर =6; डीबीओ मौजूद है तो ड्रॉप व्यू। ऑर्डर ऑर्डर विवरण;व्युत्पन्न कॉलम
विचारों के माध्यम से संशोधन के लिए एक और प्रतिबंध व्युत्पन्न कॉलम के साथ करना है। यदि कोई दृश्य स्तंभ एक गणना का परिणाम है, तो जब आप दृश्य के माध्यम से डेटा डालने या अपडेट करने का प्रयास करते हैं तो SQL सर्वर इसके सूत्र को उलटने का प्रयास नहीं करेगा-बल्कि, यह ऐसे संशोधनों को अस्वीकार कर देगा।
एक उदाहरण के रूप में निम्नलिखित दृश्य पर विचार करें:
डीबीओ बनाएं या देखें।दृश्य अंतर्निहित ऑर्डर विवरण तालिका कॉलम इकाई मूल्य और छूट के आधार पर netunitprice कॉलम की गणना करता है।
दृश्य को क्वेरी करें:
चुनें* dbo.OrderDetailsNetPrice से;आपको निम्न आउटपुट मिलता है:
आर्डरिड प्रोडक्टिड मात्रा netunitprice डिस्काउंट-------------------------------------------------- ---- ---------1 1001 5 9.975000 0.05001 1004 2 20.000000 0.00002 1003 1 47.691000 0.10003 1001 1 9.975000 0.05003 1003 2 49.491000 0.10004 1001 2 9.975000 0.05004 1004 1 20.300000 0.00004 1005 1 28.595000 0.05005 1003 5 54.990000 0.00005 1006 2 11.316000 0.0800दृश्य के माध्यम से एक पंक्ति सम्मिलित करने का प्रयास करें:
dbo.OrderDetailsNetPrice(orderid, productid, qty, netunitprice, छूट) VALUES(1, 1005, 1, 28.595, 0.05);सैद्धांतिक रूप से, आप यह पता लगा सकते हैं कि व्यू के नेटुनिटप्राइस और डिस्काउंट वैल्यू से बेस टेबल के यूनिटप्राइस वैल्यू को रिवर्स इंजीनियरिंग द्वारा अंतर्निहित ऑर्डरडिटेल टेबल में किस पंक्ति को सम्मिलित करने की आवश्यकता है। SQL सर्वर ऐसी रिवर्स इंजीनियरिंग का प्रयास नहीं करता है, लेकिन निम्न त्रुटि के साथ प्रयास किए गए सम्मिलन को अस्वीकार करता है:
संदेश 4406, स्तर 16, राज्य 1, पंक्ति 412
दृश्य या कार्य का अद्यतन या सम्मिलित करना 'dbo.OrderDetailsNetPrice' विफल रहा क्योंकि इसमें एक व्युत्पन्न या स्थिर फ़ील्ड है।सम्मिलन से गणना किए गए कॉलम को छोड़ने का प्रयास करें:
dbo.OrderDetailsNetPrice(orderid, productid, qty, छूट) VALUES(1, 1005, 1, 0.05);अब हम इस आवश्यकता पर वापस आ गए हैं कि अंतर्निहित तालिका के सभी कॉलम जो किसी भी तरह से अपने मान प्राप्त नहीं करते हैं, उन्हें स्वचालित रूप से सम्मिलन का हिस्सा होना चाहिए, और यहां हम यूनिटप्राइस कॉलम को याद कर रहे हैं। यह प्रविष्टि निम्न त्रुटि के साथ विफल हो जाती है:
संदेश 515, स्तर 16, राज्य 2, पंक्ति 421
NULL मान को 'unitprice', तालिका 'tempdb.dbo.OrderDetails' में सम्मिलित नहीं कर सकता; कॉलम नल की अनुमति नहीं देता है। INSERT विफल रहता है।If you want to support insertions through the view, you basically have two options. One is to include the unitprice column in the view definition. Another is to create an instead of trigger on the view where you handle the reverse engineering logic yourself.
At this point, run the following code for cleanup:
DROP VIEW IF EXISTS dbo.OrderDetailsNetPrice;Set Operators
As mentioned in the last section, you’re not allowed to modify a column in a view if the column is a result of a computation. The columns modified in the view using INSERT and UPDATE statements have to map directly to the underlying base table’s columns with no manipulation. In the list of restrictions to modifications through views, T-SQL’s documentation specifies that columns formed by using the set operators UNION, UNION ALL, EXCEPT, and INTERSECT amount to a computation and therefore are also not updatable.
One exception to this restriction is when using the UNION ALL operator to combine rows from different tables to form an updatable partitioned view. That’s a big topic in its own right. I’ll cover it briefly here to give you a sense, and you can investigate it further if you like in the product’s documentation.
Partitioned views predates table and index partitioning in SQL Server. The basic idea is that you can store disjoint subsets of rows in different base tables and have a view that unifies the rows from the different tables using a UNION ALL operator. If certain requirements are met, you can not only read the data through the view but also modify it through the view. SQL Server will figure out how to direct the modifications through the view to the right underlying tables.
The requirements for supporting modifications through such a view include having a partitioning column. Each of the underlying tables needs to have a CHECK constraint based on the partitioning column that defines a disjoint subset of rows. Also, the partitioning column needs to be part of the table’s primary key, meaning it cannot allow NULLs.
Consider the Orders table you used earlier in this article. Suppose that instead of holding all orders in one table, you want to store unshipped orders in one table (called UnshippedOrders) and shipped orders in another table (called ShippedOrders). You also want to create a view called Orders combining the rows from both tables. You want the view to be updatable.
Let’s start by removing any existing objects before creating the new ones:
DROP VIEW IF EXISTS dbo.Orders;DROP TABLE IF EXISTS dbo.OrderDetails, dbo.Orders;DROP TABLE IF EXISTS dbo.ShippedOrders, dbo.UnshippedOrders;The partitioning column in our example is the shippeddate column. Our first obstacle is that we want to represent unshipped orders with a NULL shippeddate, but the partitioning column cannot allow NULLs. One possible workaround is to decide on some specific future date to represent unshipped orders. For example, the maximum supported date December 31st, 9999. Then you could have a CHECK constraint in the UnshippedOrders table checking that the shipped date is this specific one, and a CHECK constraint in the ShippedOrders table checking that the shipped date is before this one. This will meet the requirement for disjoint sets of rows.
Another obstacle is that the partitioning column needs to be part of the primary key. Originally the primary key was based on the orderid column alone. Now it will need to be extended to be based on (orderid, shippeddate). You will probably still want to enforce uniqueness based on orderid alone. To achieve this, you’ll need to add a unique constraint based on orderid.
With all this in mind, here are the definitions of the ShippedOrders and UnshippedOrders tables:
CREATE TABLE dbo.ShippedOrders( orderid INT NOT NULL, orderdate DATE NOT NULL, shippeddate DATE NOT NULL, CONSTRAINT PK_ShippedOrders PRIMARY KEY(orderid, shippeddate), CONSTRAINT UNQ_ShippedOrders_orderid UNIQUE(orderid), CONSTRAINT CHK_ShippedOrders_shippeddate CHECK(shippeddate <'99991231')); CREATE TABLE dbo.UnshippedOrders( orderid INT NOT NULL, orderdate DATE NOT NULL, shippeddate DATE NOT NULL DEFAULT('99991231'), CONSTRAINT PK_UnshippedOrders PRIMARY KEY(orderid, shippeddate), CONSTRAINT UNQ_UnshippedOrders_orderid UNIQUE(orderid), CONSTRAINT CHK_UnshippedOrders_shippeddate CHECK(shippeddate ='99991231'));You then create the Orders view, unifying the rows from the two tables using the UNION ALL operator, like so:
CREATE OR ALTER VIEW dbo.OrdersAS SELECT orderid, orderdate, shippeddate FROM dbo.ShippedOrders UNION ALL SELECT orderid, orderdate, shippeddate FROM dbo.UnshippedOrders;GOSince this view meets all requirements for updatability, you can insert, update, and delete rows through the view. SQL Server will direct the changes to the right underlying tables. As an example, the following statement inserts a few rows, including both shipped and unshipped orders:
INSERT INTO dbo.Orders(orderid, orderdate, shippeddate) VALUES(1, '20210802', '20210804'), (2, '20210802', '20210805'), (3, '20210804', '20210806'), (4, '20210826', '99991231'), (5, '20210827', '99991231');The plan for this code is shown in Figure 3.
Figure 3:Plan for INSERT statement against partitioned view
As you can see, a Compute Scalar operator computes for each source row a member called Ptn1018. This member is set to 0 for shipped orders (shippeddate <'9999-12-31') and 1 for unshipped orders (shippeddate ='9999-12-31'). The rows are spooled along with the member Ptn1018, and then the spool is read twice. Once filtering the rows where Ptn1018 =0, inserting those into the underlying ShippedOrders table, and another time filtering the rows where Ptn1018 =1, inserting those into the underlying UnshippedOrders table.If this seems like an attractive option, consider it very carefully. Remember this is an old feature, predating table and index partitioning. There are many requirements, restrictions, and complications, including optimization complications, integrity enforcement complications, and others. As mentioned, here I just wanted to cover it briefly to describe the exception to the modification restriction involving set operators.When you’re done, run the following code for cleanup:
DROP VIEW IF EXISTS dbo.Orders;DROP TABLE IF EXISTS dbo.OrderDetails, dbo.Orders;DROP TABLE IF EXISTS dbo.ShippedOrders, dbo.UnshippedOrders;सारांश
When I started the coverage of views, one of the first things I explained was that a view is a table. You can read data from a view and you can modify data through a view. But you need to understand that modifications through the view are restricted in a few ways, and the outcome of such modifications could be surprising in some cases.
Using the CHECK OPTION, you’re only allowed to update and insert rows through the view as long as the result rows are considered a valid part of the view. This means unlike a CHECK constraint in a table, the CHECK OPTION rejects changes where the inner query’s filter evaluates to unknown (when a NULL is involved). You’re not allowed to insert or update rows through a view if it’s defined with the CHECK OPTION and uses the TOP or OFFSET-FETCH filters. But you’re allowed to delete rows through such a view.
If a view joins multiple base tables, inserts and updates through the view are allowed provided that only one underlying base table is affected. Oddly, if a modification of a single target row involves multiple related source rows, the modification is allowed but is processed as a nondeterministic one. In such a case, SQL Server uses the internal ANY aggregate the pick a single value from the source rows.
You cannot update or insert rows through a view where at least one of the updated columns is a derived one resulting from a computation. The same applies when using a set operator, with an exception when using the UNION ALL operator to create an updatable partitioned view.