2011-07-06 12 views
12

का उपयोग करते समय डुप्लिकेट रिकॉर्ड डालने से कैसे बचें मैं टी-एसक्यूएल के मेर्ज स्टेटमेंट का उपयोग करके कई रिकॉर्ड डालने का प्रयास कर रहा हूं, लेकिन स्रोत तालिका में डुप्लिकेट रिकॉर्ड होने पर मेरी क्वेरी INSERT में विफल हो जाती है।टी-एसक्यूएल मर्ज स्टेटमेंट

  1. लक्ष्य तालिका में दो कॉलम
  2. स्रोत तालिका डुप्लिकेट रिकॉर्ड है कि लक्ष्य तालिका के प्राथमिक कुंजी बाधा (का उल्लंघन "प्राथमिक KEY का उल्लंघन" हो सकती है के आधार पर एक प्राथमिक कुंजी है: विफलता के कारण होता है फेंक दिया)

मैं एक तरह से मेरी मर्ज बयान बदल इतना है कि यह या तो स्रोत तालिका में डुप्लिकेट रिकॉर्ड पर ध्यान नहीं देता और/या कोशिश/अपवाद है कि हो सकता पकड़ने के लिए सम्मिलित करें बयान पकड़ेगा तलाश कर रहा हूँ (यानी सभी अन्य आईएनएसईआरटी स्टेटमेंट्स कुछ खराब अंडे के बावजूद चलेंगे) - या शायद, एक बेहतर तरीका है टी ओ इस समस्या के बारे में जाओ?

यहां एक प्रश्नोत्तरी उदाहरण है जिसे मैं समझाने की कोशिश कर रहा हूं। उदाहरण के नीचे एक अस्थायी तालिका में 100k रिकॉर्ड जोड़ना होगा और उसके बाद लक्ष्य तालिका में उन रिकॉर्ड सम्मिलित करने का प्रयास करेंगे - अपने मूल पोस्ट में

संपादित मैं केवल उदाहरण तालिकाओं जो रास्ता दिया में दो क्षेत्रों को शामिल एसओ दोस्तों को मेरिज स्टेटमेंट में डुप्लिकेट से बचने के लिए एक डिस्टिंट समाधान देने के लिए। मुझे यह उल्लेख करना चाहिए था कि मेरी असली दुनिया की समस्या में टेबलों में 15 फ़ील्ड हैं और उनमें से 15, दो फ़ील्ड एक क्लस्टर प्राथमिक कुंजी हैं। तो DISTINCT कीवर्ड काम नहीं करता है क्योंकि मुझे सभी 15 फ़ील्ड चुनने और दो फ़ील्ड के आधार पर डुप्लिकेट को अनदेखा करने की आवश्यकता है।

मैंने एक और फ़ील्ड, col4 शामिल करने के लिए नीचे दी गई क्वेरी को अपडेट किया है। मुझे मेर्ज में कोलो 4 शामिल करने की आवश्यकता है, लेकिन मुझे केवल यह सुनिश्चित करने की आवश्यकता है कि केवल col2 और col3 अद्वितीय हैं।

-- Create the source table 
CREATE TABLE #tmp (
col2 datetime NOT NULL, 
col3 int NOT NULL, 
col4 int 
) 
GO 

-- Add a bunch of test data to the source table 
-- For testing purposes, allow duplicate records to be added to this table 
DECLARE @loopCount int = 100000 
DECLARE @loopCounter int = 0 
DECLARE @randDateOffset int 
DECLARE @col2 datetime 
DECLARE @col3 int 
DECLARE @col4 int 

WHILE (@loopCounter) < @loopCount 
BEGIN 
    SET @randDateOffset = RAND() * 100000 
    SET @col2 = DATEADD(MI,@randDateOffset,GETDATE()) 
    SET @col3 = RAND() * 1000 
    SET @col4 = RAND() * 10 
    INSERT INTO #tmp 
    (col2,col3,col4) 
    VALUES 
    (@col2,@col3,@col4); 

    SET @loopCounter = @loopCounter + 1 
END 

-- Insert the source data into the target table 
-- How do we make sure we don't attempt to INSERT a duplicate record? Or how can we 
-- catch exceptions? Or? 
MERGE INTO dbo.tbl1 AS tbl 
    USING (SELECT * FROM #tmp) AS src 
    ON (tbl.col2 = src.col2 AND tbl.col3 = src.col3) 
    WHEN NOT MATCHED THEN 
     INSERT (col2,col3,col4) 
     VALUES (src.col2,src.col3,src.col4); 
GO 
+0

आपको यह तय करना होगा कि कॉल 2 और col3 में colt और col3 में डुप्लीकेट होने पर आपको कॉल 4 चुनना चाहिए। उदाहरण के लिए, आप col4' के रूप में 'col2, col3' और 'min (col4) द्वारा समूह का उपयोग कर सकते हैं। –

उत्तर

15

अपने नए विनिर्देश के हल नहीं है। केवल col4 का उच्चतम मूल्य डालना: इस बार मैंने डुप्लिकेट पंक्तियों को रोकने के लिए समूह का उपयोग किया था।

MERGE INTO dbo.tbl1 AS tbl 
USING (SELECT col2,col3, max(col4) col4 FROM #tmp group by col2,col3) AS src 
ON (tbl.col2 = src.col2 AND tbl.col3 = src.col3) 
WHEN NOT MATCHED THEN 
    INSERT (col2,col3,col4) 
    VALUES (src.col2,src.col3,src.col4); 
+0

मैंने अपने क्वेरी उदाहरण में केवल दो फ़ील्ड का उपयोग करने की गलती की है। तथ्य यह है कि, मेरी लक्ष्य तालिका में दो से अधिक क्षेत्र हैं। हालांकि, यह केवल दो फ़ील्ड है जो पीके क्लस्टर बनाते हैं। तो आपके द्वारा सुझाए गए DISTINCT समाधान पर्याप्त नहीं होंगे। मैंने अतिरिक्त फ़ील्ड को प्रतिबिंबित करने के लिए अपनी मूल पोस्ट अपडेट की। भले ही, आपके और उत्तर के लिए धन्यवाद (प्रश्न का उत्तर देने के लिए +1)। – Jed

+1

ठीक है, मैंने इसे एक नया प्रयास दिया। मुझे उम्मीद है कि मैं इसे सही समझ गया। –

7

स्रोत को देखते हुए डुप्लिकेट है और आप उपयोग नहीं कर रहे पूरी तरह से मर्ज, मैं एक सम्मिलित करें का उपयोग करेंगे।

INSERT dbo.tbl1 (col2,col3) 
SELECT DISTINCT col2,col3 
FROM #tmp src 
WHERE NOT EXISTS (
     SELECT * 
     FROM dbo.tbl1 tbl 
     WHERE tbl.col2 = src.col2 AND tbl.col3 = src.col3) 

कारण मेर्ज विफल रहता है कि यह पंक्ति द्वारा पंक्ति की जांच नहीं की जाती है। सभी गैर-मैचों पाए जाते हैं, फिर यह इन सभी को शामिल करने का प्रयास करता है। यह उसी बैच में पंक्तियों की जांच नहीं करता है जो पहले से मेल खाता है।

यह मैं "Halloween problem" का एक सा याद दिलाता है जहां एक परमाणु आपरेशन के प्रारंभिक डेटा परिवर्तन बाद में डेटा परिवर्तनों को प्रभावित: यह सही

+0

मैंने अपनी खुद की लिपि का परीक्षण नहीं किया है, क्या आप कह रहे हैं कि यह विफल हो जाता है? –

+0

@ t-clausen.dk: आपके पास एक डिस्टिंट भी है, इसलिए ठीक होना चाहिए। MERGE की सीमाओं को देखते हुए क्यों न केवल एक INSERT I का उपयोग करें ... – gbn

+0

प्रश्न के शीर्षक के कारण –

2
ग्रुप द्वारा आप एक विश्लेषणात्मक समारोह का उपयोग कर सकते हैं, तो आप डुप्लिकेट रिकॉर्ड के सेट विलय करने में एक विशिष्ट रिकॉर्ड चयन करने की अनुमति के बजाय

MERGE INTO dbo.tbl1 AS tbl 
USING (
    SELECT * 
    FROM (
     SELECT *, ROW_NUMBER() OVER (PARTITION BY col2, col3 ORDER BY ModifiedDate DESC) AS Rn 
     FROM #tmp 
    ) t 
    WHERE Rn = 1 --choose the most recently modified record 
) AS src 
ON (tbl.col2 = src.col2 AND tbl.col3 = src.col3) 
संबंधित मुद्दे