MERGE
बयान एक जटिल वाक्य रचना और एक और भी जटिल कार्यान्वयन है, लेकिन अनिवार्य रूप से विचार दो तालिकाओं में शामिल होने, पंक्तियों को बदल करने के लिए किया जा (डाला, अद्यतन या हटाए गए) की जरूरत के लिए नीचे की ओर फ़िल्टर है, और फिर अनुरोध किए गए परिवर्तन करने के लिए। निम्नलिखित नमूना आंकड़ों को देखते हुए:
DECLARE @CategoryItem AS TABLE
(
CategoryId integer NOT NULL,
ItemId integer NOT NULL,
PRIMARY KEY (CategoryId, ItemId),
UNIQUE (ItemId, CategoryId)
);
DECLARE @DataSource AS TABLE
(
CategoryId integer NOT NULL,
ItemId integer NOT NULL
PRIMARY KEY (CategoryId, ItemId)
);
INSERT @CategoryItem
(CategoryId, ItemId)
VALUES
(1, 1),
(1, 2),
(1, 3),
(2, 1),
(2, 3),
(3, 5),
(3, 6),
(4, 5);
INSERT @DataSource
(CategoryId, ItemId)
VALUES
(2, 2);
लक्ष्य
╔════════════╦════════╗
║ CategoryId ║ ItemId ║
╠════════════╬════════╣
║ 1 ║ 1 ║
║ 2 ║ 1 ║
║ 1 ║ 2 ║
║ 1 ║ 3 ║
║ 2 ║ 3 ║
║ 3 ║ 5 ║
║ 4 ║ 5 ║
║ 3 ║ 6 ║
╚════════════╩════════╝
स्रोत
╔════════════╦════════╗
║ CategoryId ║ ItemId ║
╠════════════╬════════╣
║ 2 ║ 2 ║
╚════════════╩════════╝
वांछित परिणाम स्रोत से डेटा के साथ लक्ष्य में डेटा को बदलने के लिए है, लेकिन केवल के लिए CategoryId = 2
। MERGE
ऊपर दिए गए विवरण के बाद , हमें एक प्रश्न लिखना चाहिए जो स्रोत से जुड़ता है और केवल कुंजियों पर लक्षित होता है, और पंक्तियों में केवल पंक्तियों को फ़िल्टर करता है WHEN
:
MERGE INTO @CategoryItem AS TARGET
USING @DataSource AS SOURCE ON
SOURCE.ItemId = TARGET.ItemId
AND SOURCE.CategoryId = TARGET.CategoryId
WHEN NOT MATCHED BY SOURCE
AND TARGET.CategoryId = 2
THEN DELETE
WHEN NOT MATCHED BY TARGET
AND SOURCE.CategoryId = 2
THEN INSERT (CategoryId, ItemId)
VALUES (CategoryId, ItemId)
OUTPUT
$ACTION,
ISNULL(INSERTED.CategoryId, DELETED.CategoryId) AS CategoryId,
ISNULL(INSERTED.ItemId, DELETED.ItemId) AS ItemId
;
यह निम्नलिखित परिणाम देता है:
╔═════════╦════════════╦════════╗
║ $ACTION ║ CategoryId ║ ItemId ║
╠═════════╬════════════╬════════╣
║ DELETE ║ 2 ║ 1 ║
║ INSERT ║ 2 ║ 2 ║
║ DELETE ║ 2 ║ 3 ║
╚═════════╩════════════╩════════╝
╔════════════╦════════╗
║ CategoryId ║ ItemId ║
╠════════════╬════════╣
║ 1 ║ 1 ║
║ 1 ║ 2 ║
║ 1 ║ 3 ║
║ 2 ║ 2 ║
║ 3 ║ 5 ║
║ 3 ║ 6 ║
║ 4 ║ 5 ║
╚════════════╩════════╝
निष्पादन योजना है:
ध्यान दें कि दोनों टेबल पूरी तरह से स्कैन की गई हैं। हम इसे अक्षम समझ सकते हैं, क्योंकि CategoryId = 2
लक्ष्य तालिका में केवल वे पंक्तियाँ ही प्रभावित होंगी। यह वह जगह है जहाँ पुस्तकें ऑनलाइन में चेतावनी आती हैं। लक्ष्य में केवल आवश्यक पंक्तियों को छूने के लिए अनुकूलन करने का एक गुमराह करने वाला प्रयास है:
MERGE INTO @CategoryItem AS TARGET
USING
(
SELECT CategoryId, ItemId
FROM @DataSource AS ds
WHERE CategoryId = 2
) AS SOURCE ON
SOURCE.ItemId = TARGET.ItemId
AND TARGET.CategoryId = 2
WHEN NOT MATCHED BY TARGET THEN
INSERT (CategoryId, ItemId)
VALUES (CategoryId, ItemId)
WHEN NOT MATCHED BY SOURCE THEN
DELETE
OUTPUT
$ACTION,
ISNULL(INSERTED.CategoryId, DELETED.CategoryId) AS CategoryId,
ISNULL(INSERTED.ItemId, DELETED.ItemId) AS ItemId
;
ON
क्लॉज में तर्क जुड़ने के हिस्से के रूप में लागू किया जाता है। इस मामले में, ज्वाइन एक पूर्ण बाहरी जुड़ाव है ( इस पुस्तक को ऑनलाइन प्रविष्टि क्यों देखें)। एक बाहरी भाग के रूप में लक्ष्य पंक्तियों पर श्रेणी 2 के लिए चेक को लागू करना अंततः पंक्तियों में परिणाम के साथ एक अलग मूल्य हटा दिया जाता है (क्योंकि वे स्रोत से मेल नहीं खाते):
╔═════════╦════════════╦════════╗
║ $ACTION ║ CategoryId ║ ItemId ║
╠═════════╬════════════╬════════╣
║ DELETE ║ 1 ║ 1 ║
║ DELETE ║ 1 ║ 2 ║
║ DELETE ║ 1 ║ 3 ║
║ DELETE ║ 2 ║ 1 ║
║ INSERT ║ 2 ║ 2 ║
║ DELETE ║ 2 ║ 3 ║
║ DELETE ║ 3 ║ 5 ║
║ DELETE ║ 3 ║ 6 ║
║ DELETE ║ 4 ║ 5 ║
╚═════════╩════════════╩════════╝
╔════════════╦════════╗
║ CategoryId ║ ItemId ║
╠════════════╬════════╣
║ 2 ║ 2 ║
╚════════════╩════════╝
मूल कारण एक ही कारण है ON
कि जब वे WHERE
क्लाज में निर्दिष्ट होते हैं तो बाहरी जुड़ाव खंड में अलग-अलग व्यवहार करते हैं । MERGE
वाक्य रचना (और कार्यान्वयन में शामिल होने के खंड निर्दिष्ट के आधार पर) सिर्फ यह मुश्किल देखने के लिए कि यह ऐसा है या नहीं।
पुस्तकें ऑनलाइन में मार्गदर्शन (में विस्तार का अनुकूलन प्रदर्शन प्रविष्टि) मार्गदर्शन है कि सही अर्थ यह सुनिश्चित करना होगा का उपयोग कर व्यक्त किया जाता है प्रदान करता है MERGE
, वाक्य रचना उपयोगकर्ता जरूरी सभी कार्यान्वयन विवरण, या तरीकों से अनुकूलक वैध तरीके से पुन: व्यवस्थित करने के लिए हो सकता है खाते को समझने के लिए बिना निष्पादन दक्षता कारणों के लिए चीजें।
प्रलेखन प्रारंभिक फ़िल्टरिंग को लागू करने के लिए तीन संभावित तरीके प्रदान करता है:
WHEN
क्लॉज में एक फ़िल्टरिंग स्थिति निर्दिष्ट करना सही परिणाम की गारंटी देता है, लेकिन इसका मतलब यह हो सकता है कि स्रोत से अधिक पंक्तियों को पढ़ा और संसाधित किया जाता है और लक्ष्य तालिकाओं की तुलना में कड़ाई से आवश्यक है (जैसा कि पहले उदाहरण में देखा गया है)।
फ़िल्टरिंग स्थिति वाले दृश्य के माध्यम से अपडेट करना भी सही परिणामों की गारंटी देता है (चूंकि दृश्य के माध्यम से अपडेट के लिए परिवर्तित पंक्तियों को एक्सेस करना आवश्यक है) लेकिन इसके लिए एक समर्पित दृश्य की आवश्यकता होती है, और एक वह जो विचारों को अपडेट करने के लिए विषम परिस्थितियों का पालन करता है।
एक सामान्य टेबल एक्सप्रेशन का उपयोग करकेON
क्लॉज़ के लिए विधेय को जोड़ने के लिए समान जोखिम उठाया जाता है , लेकिन थोड़े अलग कारणों से। कई मामलों में यह सुरक्षित होगा, लेकिन इसकी पुष्टि करने के लिए निष्पादन योजना के विशेषज्ञ विश्लेषण की आवश्यकता है (और व्यापक व्यावहारिक परीक्षण)। उदाहरण के लिए:
WITH TARGET AS
(
SELECT *
FROM @CategoryItem
WHERE CategoryId = 2
)
MERGE INTO TARGET
USING
(
SELECT CategoryId, ItemId
FROM @DataSource
WHERE CategoryId = 2
) AS SOURCE ON
SOURCE.ItemId = TARGET.ItemId
AND SOURCE.CategoryId = TARGET.CategoryId
WHEN NOT MATCHED BY TARGET THEN
INSERT (CategoryId, ItemId)
VALUES (CategoryId, ItemId)
WHEN NOT MATCHED BY SOURCE THEN
DELETE
OUTPUT
$ACTION,
ISNULL(INSERTED.CategoryId, DELETED.CategoryId) AS CategoryId,
ISNULL(INSERTED.ItemId, DELETED.ItemId) AS ItemId
;
अधिक सटीक योजना के साथ यह सही परिणाम (बार-बार नहीं) उत्पन्न करता है:
योजना केवल लक्ष्य तालिका से श्रेणी 2 के लिए पंक्तियों को पढ़ती है। यदि लक्ष्य तालिका बड़ी है, तो यह एक महत्वपूर्ण प्रदर्शन विचार हो सकता है, लेकिन MERGE
सिंटैक्स का उपयोग करके इस गलत को प्राप्त करना बहुत आसान है ।
कभी-कभी, MERGE
अलग-अलग डीएमएल संचालन को लिखना आसान होता है । यह दृष्टिकोण एकल से भी बेहतर प्रदर्शन कर सकता है MERGE
, एक ऐसा तथ्य जो अक्सर लोगों को आश्चर्यचकित करता है।
DELETE ci
FROM @CategoryItem AS ci
WHERE ci.CategoryId = 2
AND NOT EXISTS
(
SELECT 1
FROM @DataSource AS ds
WHERE
ds.ItemId = ci.ItemId
AND ds.CategoryId = ci.CategoryId
);
INSERT @CategoryItem
SELECT
ds.CategoryId,
ds.ItemId
FROM @DataSource AS ds
WHERE
ds.CategoryId = 2;