2009-07-16 29 views
41

में "डुप्लिकेट कुंजी" त्रुटि को अनदेखा कैसे करें मेरे पास एक लेनदेन है जिसमें एकाधिक SQL स्टेटमेंट्स (INSERT, UPDATE और/या DELETES) शामिल हैं। निष्पादित करते समय, मैं डुप्लिकेट त्रुटि कथनों को अनदेखा करना चाहता हूं और अगले कथन पर जारी रखना चाहता हूं। ऐसा करने का सबसे अच्छा तरीका क्या है?टी-एसक्यूएल (एसक्यूएल सर्वर)

उत्तर

13

यद्यपि आपकी जबरदस्त सलाह है कि आप अपने एसक्यूएल को ढांचा दें ताकि डुप्लिकेट आवेषणों का प्रयास न किया जा सके (फिलिप केली की स्निपेट शायद आपको चाहिए), मैं यह उल्लेख करना चाहता हूं कि किसी कथन पर एक त्रुटि रोलबैक का कारण नहीं है ।

XACT_ABORTON है, तो एक लेनदेन स्वचालित रूप से रोलबैक नहीं होगा यदि कोई त्रुटि तब तक नहीं आती जब तक कि कनेक्शन को मारने के लिए पर्याप्त गंभीर न हो। XACT_ABORTOFF पर डिफ़ॉल्ट।

create table x (y int not null primary key) 

begin transaction 
insert into x(y) 
values(1) 
insert into x(y) 
values(2) 
insert into x(y) 
values(2) 
insert into x(y) 
values(3) 
commit 

जब तक आप XACT_ABORT स्थापित कर रहे हैं, एक त्रुटि ग्राहक पर उठाया जा रहा है और रोलबैक के कारण:

उदाहरण के लिए, निम्नलिखित एसक्यूएल सफलतापूर्वक तालिका में तीन मानों सम्मिलित करता है। यदि कुछ भयानक कारणों से आप डुप्लिकेट डालने से नहीं बच सकते हैं, तो आपको क्लाइंट पर त्रुटि को फंसाने और इसे अनदेखा करने में सक्षम होना चाहिए।

0

कुंजी अद्वितीय होना चाहिए। ऐसा मत करो। आवश्यकतानुसार फिर से डिजाइन करें।

(यदि आप सम्मिलित करने का प्रयास कर रहे हैं, तो हटाएं, और सम्मिलित विफल हो जाता है ... बस पहले हटाएं। किसी भी कथन में त्रुटि पर रोलबैक)।

+0

नहीं मुझे नहीं लगता कि मैंने अपना प्रश्न स्पष्ट कर दिया है। INSERT INTO एक्स मूल्यों (वाई, जेड) में सम्मिलित X2 मूल्यों (Y2, Z2) X3 मानों में सम्मिलित करें (Y3, जेड 3) चलो कहते हैं कि दूसरा बयान एक नकली त्रुटि होती है करते हैं। मैं इसे अनदेखा करना चाहता हूं और तीसरे कथन को निष्पादित करना जारी रखना चाहता हूं। एक लेनदेन में व्यवहार है, यह एक त्रुटि फेंकता है और यह मौजूद है (वापस रोल)। – Kingamoon

8

से तो "डुप्लिकेट त्रुटि statments ध्यान न दें", trnsaction निरस्त तो बस प्रत्येक कथन के आसपास .. अंत प्रयास में शुरू रख बिना वर्तमान बयान गर्भपात और अगले बयान जारी रखने के लिए:

BEGIN TRY 
    INSERT ... 
END TRY 
BEGIN CATCH /*required, but you dont have to do anything */ END CATCH 
... 
+0

दुर्भाग्यवश, हम अभी SQL Server 2000 का उपयोग कर रहे हैं, इसलिए मुझे लगता है कि कोशिश नहीं है .. कैच स्टेटमेंट उस संस्करण में उपलब्ध हैं। – Kingamoon

55

मुझे लगता है कि आप अपनी अनुक्रमणिका पर IGNORE_DUP_KEY विकल्प ढूंढ रहे हैं। http://msdn.microsoft.com/en-us/library/ms186869.aspx पर प्रलेखित IGNORE_DUP_KEY विकल्प पर एक नज़र डालें जो डुप्लिकेट प्रविष्टि त्रुटि के बजाए चेतावनी उत्पन्न करने का प्रयास करता है।

+3

खराब विचार - आप एक अद्वितीय अनुक्रमणिका में डुप्लिकेट डेटा नहीं चाहते हैं। –

+32

@ जोनाथन लेफ्लर: 'IGNORE_DUP_KEY' डुप्लिकेट डेटा नहीं देगा। यह SQL सर्वर को डुप्लिकेट कुंजी को अनदेखा करने का कारण बनता है: इसे डेटाबेस में सम्मिलित नहीं करता है। –

+0

@ इयान बॉयड: ठीक है - रहने और सीखना एसओ संस्कृति का हिस्सा है। जानकारी के लिए धन्यवाद।(मुझे यकीन नहीं है कि अगर मैं आईएनएसईआरटी को डालने के बिना पूछता हूं और मुझे बताए बिना सफल हुआ तो मैं विश्वसनीय कोड लिख सकता हूं; संभवतः, कम से कम एक चेतावनी वापस आ गई है। हालांकि, मुझे लगता है कि सुविधा क्या करती है।) –

19

SquareCog के उत्तर के लिए अपनी टिप्पणी पर विस्तार, तुम कर सकते हो:

INSERT INTO X VALUES(Y,Z) WHERE Y NOT IN (SELECT Y FROM X) 
INSERT INTO X2 VALUES(Y2,Z2) WHERE Y2 NOT IN (SELECT Y FROM X2) 
INSERT INTO X3 VALUES(Y3,Z3) WHERE Y3 NOT IN (SELECT Y FROM X3) 

यहाँ, मुझे लगता है कि स्तंभ Y सभी तीन तालिकाओं में मौजूद है मान लेते हैं। ध्यान दें कि प्रदर्शन खराब हो सकता है अगर टेबल वाई

ओह, हाँ पर सूचीबद्ध नहीं कर रहे हैं, वाई उस पर एक अद्वितीय बाधा है - तो वे अनुक्रमित रहे हैं, और यह बेहतर प्रदर्शन करना चाहिए।

+2

मुझे यह पसंद है - हमारी परिनियोजन स्क्रिप्ट को कई बार सुरक्षित रूप से चलाने के लिए डिज़ाइन किया गया है, इसलिए INSERT के पास टकराव से बचने के लिए हमेशा मानदंड होते हैं। – n8wrl

+2

मैंने इस दृष्टिकोण को आजमाया लेकिन मेरे एमएसएसक्यूएल सर्वर (2008 आर 2) कॉमपलेन्स "कीवर्ड के पास गलत वाक्यविन्यास" कहां है - यह ऐसा लगता है कि INERERT के बाद WHERE क्यों नहीं है। क्या आप सुनिश्चित हैं कि आपका समाधान सही है? – Dai

+0

हाँ, मैं हूं। अपने कोड को, एक नए प्रश्न के रूप में प्राथमिकता से पोस्ट करें, और कोई आपको समस्या का पता लगाने में मदद करेगा। –

4

ठीक है। कुछ त्रुटि प्रबंधन की कोशिश करने के बाद, मुझे पता चला कि मेरे पास क्या समस्या हल हो रही है।

SET XACT_ABORT OFF ; -- > really important to set that to OFF 
BEGIN 
DECLARE @Any_error int 
DECLARE @SSQL varchar(4000) 
BEGIN TRANSACTION 
    INSERT INTO Table1(Value1) VALUES('Value1') 
    SELECT @Any_error = @@ERROR 
    IF @Any_error<> 0 AND @Any_error<>2627 GOTO ErrorHandler 

    INSERT INTO Table1(Value1) VALUES('Value1') 
    SELECT @Any_error = @@ERROR 
    IF @Any_error<> 0 AND @Any_error<>2627 GOTO ErrorHandler 

    INSERT INTO Table1(Value1) VALUES('Value2') 
    SELECT @Any_error = @@ERROR 
    IF @Any_error<> 0 AND @Any_error<>2627 GOTO ErrorHandler 

    ErrorHandler: 
     IF @Any_error = 0 OR @Any_error=2627 
     BEGIN 
      PRINT @ssql 
      COMMIT TRAN 
     END 
     ELSE 
     BEGIN 
      PRINT @ssql 
      ROLLBACK TRAN 
     END 
END 

ऊपर लेन-देन का एक परिणाम के रूप में, Table1 निम्न मान value1, value2 होगा:

यहां इस काम करने के लिए का एक उदाहरण है (मुझे पता है कि वहाँ कुछ मैं याद कर रहा हूँ अगर है) ।

2627 रास्ते में डुप्लिकेट कुंजी के लिए त्रुटि कोड है।

त्वरित उत्तर और सहायक सुझावों के लिए सभी को धन्यवाद।

7

मैं निम्नलिखित में शामिल होना चाहता हूं: यदि आपका 99% डेटा पहले से चुनने में त्रुटि के बिना डालने जा रहा है तो परिणामस्वरूप भारी प्रदर्शन ड्रॉप (जैसे, मेरे मामले में, 200 लाइन/सेकंड से) मेरे मामले में 20 लाइन/सेकंड तक) "गूंगा" आवेषण की तुलना में और कभी-कभी त्रुटि को पकड़ने की तुलना में।

"प्राथमिक कुंजी बाधा का उल्लंघन" अनदेखा करने के बाद त्रुटियों को अन्य संसाधनों द्वारा बाधित होने के लिए वापस चला गया (हेडरूम को परिभाषित किया जा रहा है कि "बाधा संसाधनों के पास क्या नहीं है")।

मैं इस चर्चा पर पहली जगह पर उतरने का पूरा कारण हूं।

1
INSERT INTO KeyedTable(KeyField, Otherfield) 
SELECT n.* FROM 
    (SELECT 'PossibleDupeLiteral' AS KeyField, 'OtherfieldValue' AS Otherfield 
    UNION ALL 
    SELECT 'PossibleDupeLiteral', 'OtherfieldValue2' 
    ) 
LEFT JOIN KeyedTable k 
    ON k.KeyField=n.KeyField 
WHERE k.KeyField IS NULL 

यह सर्वर एक ही डेटा (उम्मीद ही तेजी से जिस तरह से यह डुप्लिकेट चाबी के लिए जाँच करने के लिए करता है) और अगर यह यह पाता है कुछ भी नहीं डालने के लिए देखने के लिए कहता है।

मुझे IGNORE_DUP_KEY समाधान भी पसंद है, लेकिन फिर कोई भी जो समस्याओं को पकड़ने के लिए त्रुटियों पर निर्भर करता है, तब रहस्यमय हो जाएगा जब सर्वर चुपचाप उनकी डुप्लिक-कुंजी त्रुटियों को अनदेखा करता है।

कारण मैं फिलिप केली के समाधान पर इस चुनाव करने पर आपके डेटा की कई पंक्तियों प्रदान कर सकते हैं और केवल लापता लोगों वास्तव में प्राप्त में है:

0

मैं यहाँ आया क्योंकि मैं एक ही बात करने के लिए कोशिश कर रहा था; मुझे पता था कि मेरे पास स्रोत डेटा में डुप्लिकेट था लेकिन केवल लक्ष्य डेटा अपडेट करना था और डुप्लिकेट नहीं जोड़ना था।

मुझे लगता है कि एक मेर्ज यहां बहुत अच्छा काम करता है क्योंकि आप अलग-अलग चीजों को अपडेट या हटा सकते हैं जो गायब हैं।

मैंने ऐसा करने का अंत किया और यह बहुत अच्छा काम किया। मैं एसएसआईएस का उपयोग Excel फ़ाइलों के माध्यम से लूप करने के लिए करता हूं और उन्हें "रॉ" SQL तालिका में डुप्लिकेट और सभी के साथ लोड करता हूं। फिर मैं उत्पादन तालिका के साथ "कच्ची" तालिका मर्ज करने के लिए एक मेर्ज चलाता हूं। फिर मैं "कच्ची" तालिका को छोटा करता हूं और अगली एक्सेल फ़ाइल में जाता हूं।

+2

उस समाधान का कोई कोड उदाहरण? – ForceMagic

+0

यदि आप इस तालिका में बहुत कुछ लोड कर रहे हैं, तो क्यों न केवल मौजूदा तालिका को IGNORE_DUP_KEY = ON के साथ एक अद्वितीय अनुक्रमणिका के साथ एक नई तालिका में लोड करके डुप्लिकेट को साफ करें। अपनी मूल तालिका हटाएं और नई तालिका का नाम बदलें। आप सीधे डुप्ली-फ्री टेबल में लोड कर सकते हैं। ऐसा लगता है कि यह कम से कम प्रयास के लिए भविष्य में काफी समय बचाएगा। – Mark

0

डालने के दौरान डुप्लिकेट को अनदेखा करने के लिए प्राथमिक कुंजी परिभाषा के दौरान IGNORE_DUP_KEY = OFF का उपयोग करें। उदाहरण

create table X(col1.....) 

CONSTRAINT [pk_X] PRIMARY KEY CLUSTERED 
(
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 70) ON [PRIMARY] 
) ON [PRIMARY] 
0

एसक्यूएल सर्वर 2000 के लिए के लिए :

 INSERT INTO t1 (ID, NAME) 
     SELECT valueid, valuename 
     WHERE NOT EXISTS 
       (SELECT 0 
       FROM t1 as t2 
       WHERE t2.ID = valueid AND t2.name = valuename) 
0

वैसे आप एक अस्थायी तालिका के साथ इस का समाधान कर सकता ..

DECLARE @RoleToAdds TABLE 
([RoleID] int, [PageID] int) 

INSERT INTO @RoleToAdds ([RoleID], [PageID]) 
    VALUES 
    (1, 2), 
    (1, 3), 
    (1, 4), 
    (2, 5) 

INSERT INTO [dbo].[RolePages] ([RoleID], [PageID]) 
    SELECT rta.[RoleID], rta.[PageID] FROM @RoleToAdds rta WHERE NOT EXISTS 
     (SELECT * FROM [RolePages] rp WHERE rp.PageID = rta.PageID AND rp.RoleID = rta.RoleID) 

इस डेटा की बड़ी मात्रा के लिए काम नहीं कर सकते, लेकिन कुछ पंक्तियों के लिए यह काम करना चाहिए!

संबंधित मुद्दे