2014-11-22 35 views
15

में MySQL ऑन डिप्लिकेट कुंजी अद्यतन के समतुल्य मैं SQL सर्वर (2012) में निम्न MySQL क्वेरी के बराबर खोजने की कोशिश कर रहा हूं?एसक्यूएल सर्वर

INSERT INTO mytable (COL_A, COL_B, COL_C, COL_D) 
VALUES ('VAL_A','VAL_B', 'VAL_C', 'VAL_D') 
ON DUPLICATE KEY UPDATE COL_D= VALUES(COL_D); 

क्या कोई मदद कर सकता है?

पीएस। मैंने पढ़ा है कि MERGE क्वेरी में समान कार्य है, लेकिन मुझे इसका बहुत ही सरल वाक्य मिलता है।

+1

सी [इस सवाल] (http: // सहायता के लिए stackoverflow.com/questions/108403/solutions-for-insert-or-update-on-sql-server)। – Phylogenesis

+1

यह भी उपयोगी हो सकता है: http://stackoverflow.com/questions/1197733/does-sql-server-offer-anything-like-mysqls-on-duplicate-key-update –

+0

क्या आपको सभी आवेषणों पर इस व्यवहार की आवश्यकता है, या सिर्फ विशिष्ट वाले? – StuartLC

उत्तर

6

इसे आजमाएं ... मैंने एसक्यूएल मर्ज स्टेटमेंट में क्या होता है, यह जानने और समझाने के लिए टिप्पणियां जोड़ दी हैं। स्रोत: MSDN : Merge Statement

मर्ज स्टेटमेंट ऑन डिप्लिकेट कुंजी अपडेट स्टेटमेंट से अलग है जिसमें आप यह बता सकते हैं कि मर्ज के लिए कौन से कॉलम का उपयोग करना है।

CREATE TABLE #mytable(COL_A VARCHAR(10), COL_B VARCHAR(10), COL_C VARCHAR(10), COL_D VARCHAR(10)) 
INSERT INTO #mytable VALUES('1','0.1', '0.2', '0.3'); --<These are the values we'll be updating 

SELECT * FROM #mytable --< Starting values (1 row) 

    MERGE #mytable AS target --< This is the target we want to merge into 
    USING (--< This is the source of your merge. Can me any select statement 
     SELECT '1' AS VAL_A,'1.1' AS VAL_B, '1.2' AS VAL_C, '1.3' AS VAL_D --<These are the values we'll use for the update. (Assuming column COL_A = '1' = Primary Key) 
     UNION 
     SELECT '2' AS VAL_A,'2.1' AS VAL_B, '2.2' AS VAL_C, '2.3' AS VAL_D) --<These values will be inserted (cause no COL_A = '2' exists) 
     AS source (VAL_A, VAL_B, VAL_C, VAL_D) --< Column Names of our virtual "Source" table 
    ON (target.COL_A = source.VAL_A) --< This is what we'll use to find a match "JOIN source on Target" using the Primary Key 
    WHEN MATCHED THEN --< This is what we'll do WHEN we find a match, in your example, UPDATE COL_D = VALUES(COL_D); 
     UPDATE SET 
      target.COL_B = source.VAL_B, 
      target.COL_C = source.VAL_C, 
      target.COL_D = source.VAL_D 
    WHEN NOT MATCHED THEN --< This is what we'll do when we didn't find a match 
    INSERT (COL_A, COL_B, COL_C, COL_D) 
    VALUES (source.VAL_A, source.VAL_B, source.VAL_C, source.VAL_D) 
    --OUTPUT deleted.*, $action, inserted.* --< Uncomment this if you want a summary of what was inserted on updated. 
    --INTO #Output --< Uncomment this if you want the results to be stored in another table. NOTE* The table must exists 
    ; 
SELECT * FROM #mytable --< Ending values (2 row, 1 new, 1 updated) 

आशा है कि

2

संग्रहित प्रक्रिया दिन की बचत होगी मदद करता है।

यहां मुझे लगता है कि COL_A और COL_B अद्वितीय कॉलम हैं और INT एनबी के प्रकार हैं! एसक्यूएल-सर्वर इंस्टेंस एटीएम नहीं है इसलिए सिंटैक्स की शुद्धता की गारंटी नहीं दे सकता है। अपडेट करें! यहाँ SQLFIDDLE

CREATE TABLE mytable 
(
COL_A int UNIQUE, 
COL_B int UNIQUE, 
COL_C int, 
COL_D int, 
) 

GO 

INSERT INTO mytable (COL_A, COL_B, COL_C, COL_D) 
VALUES (1,1,1,1), 
(2,2,2,2), 
(3,3,3,3), 
(4,4,4,4); 
GO 

CREATE PROCEDURE updateDuplicate(@COL_A INT, @COL_B INT, @COL_C INT, @COL_D INT) 
AS 
BEGIN 
    DECLARE @ret INT 
    SELECT @ret = COUNT(*) 
    FROM mytable p 
    WHERE p.COL_A = @COL_A 
     AND p.COL_B = @COL_B 

    IF (@ret = 0) 
     INSERT INTO mytable (COL_A, COL_B, COL_C, COL_D) 
     VALUES (@COL_A, @COL_B, @COL_C, @COL_D) 

    IF (@ret > 0) 
     UPDATE mytable SET COL_D = @COL_D WHERE col_A = @COL_A AND COL_B = @COL_B 
END; 
GO 

के लिए एक लिंक फिर अद्यतन बयान के बजाय आवश्यक मूल्यों के साथ इस प्रक्रिया को फोन

exec updateDuplicate 1, 1, 1, 2 
GO 
SELECT * from mytable 
GO 
+1

आप रिकॉर्ड को अपडेट करने का प्रयास करके इस समाधान को बेहतर बना सकते हैं, फिर जांचें कि @@ ROWCOUNT शून्य के बराबर है या नहीं, यदि बराबर है, तो आप रिकॉर्ड डाल सकते हैं। इस अनुकूलन के साथ, आप एक खोज (इंडेक्स खोज या इंडेक्स स्कैन) बचा सकते हैं। – Pred

+0

सहमत हैं, यह अधिक सुरुचिपूर्ण समाधान होगा – Artjoman

15

आप मूल रूप से एक सम्मिलित या अद्यतन पैटर्न की तलाश कर रहे है कभी कभी एक Upsert के रूप में भेजा ।

मैं इस अनुशंसा करते हैं: Insert or Update pattern for Sql Server - Sam Saffron

एक प्रक्रिया है जो एकल पंक्तियों के साथ काम किया जाएगा के लिए, या तो इन लेनदेनों में अच्छी तरह से काम करेगा:

सैम केसर का पहला समाधान (इस स्कीमा के लिए अनुकूलित):

begin tran 
if exists (
    select * 
    from mytable with (updlock,serializable) 
    where col_a = @val_a 
     and col_b = @val_b 
     and col_c = @val_c 
) 
    begin 
    update mytable 
     set col_d = @val_d 
     where col_a = @val_a 
     and col_b = @val_b 
     and col_c = @val_c; 
    end 
else 
    begin 
    insert into mytable (col_a, col_b, col_c, col_d) 
     values (@val_a, @val_b, @val_c, @val_d); 
    end 
commit tran 

सैम केसर का दूसरा समाधान (इस स्कीमा के लिए अनुकूलित):

begin tran 
    update mytable with (serializable) 
    set col_d = @val_d 
     where col_a = @val_a 
     and col_b = @val_b 
     and col_c = @val_c; 
    if @@rowcount = 0 
    begin 
     insert into mytable (col_a, col_b, col_c, col_d) 
      values (@val_a, @val_b, @val_c, @val_d); 
    end 
commit tran 

भी IGNORE_DUP_KEY के रचनात्मक उपयोग के साथ

, आप अभी भी एक सम्मिलित/अपडेट ब्लॉक या मर्ज कथन का उपयोग करने के लिए अटक सकता था।

update mytable 
    set col_d = 'val_d' 
    where col_a = 'val_a' 
    and col_b = 'val_b' 
    and col_c = 'val_c'; 

insert into mytable (col_a, col_b, col_c, col_d) 
    select 'val_a','val_b', 'val_c', 'val_d' 
    where not exists (select * 
    from mytable with (serializable) 
    where col_a = 'val_a' 
     and col_b = 'val_b' 
     and col_c = 'val_c' 
    ); 

The Merge answer provided by Spock आप क्या चाहते हैं क्या करना चाहिए।

मर्ज आवश्यक रूप से अनुशंसित नहीं है।मैं इसका इस्तेमाल करता हूं, लेकिन मैं कभी भी @AaronBertrand को स्वीकार नहीं करता।

1

आप एक INSTEAD OF TRIGGER का उपयोग कर एक के पास identitical व्यवहार अनुकरण कर सकते हैं:

CREATE TRIGGER tMyTable ON MyTable 
INSTEAD OF INSERT 
AS 
    BEGIN 
     SET NOCOUNT ON; 

     SELECT i.COL_A, i.COL_B, i.COL_C, i.COL_D, 
      CASE WHEN mt.COL_D IS NULL THEN 0 ELSE 1 END AS KeyExists 
      INTO #tmpMyTable 
      FROM INSERTED i 
      LEFT JOIN MyTable mt 
      ON i.COL_D = mt.COL_D; 

     INSERT INTO MyTable(COL_A, COL_B, COL_C, COL_D) 
      SELECT COL_A, COL_B, COL_C, COL_D 
       FROM #tmpMyTable 
       WHERE KeyExists = 0; 

     UPDATE mt 
      SET mt.COL_A = t.COL_A, mt.COL_B = t.COL_B, mt.COL_C = t.COL_C 
      FROM MyTable mt 
       INNER JOIN #tmpMyTable t 
       ON mt.COL_D = t.COL_D AND t.KeyExists = 1; 
    END; 

SqlFiddle here

यह कैसे काम करता

  • हम पहले सभी पंक्तियों की एक सूची पेश करने का प्रयास किया जा रहा है तालिका में #temp तालिका में डाला जाए, जिसमें से पहले से अंतर्निहित में हैं कुंजी कॉलम पर LEFT OUTER JOIN के माध्यम से तालिका COL_D जो डुप्लिकेशन मानदंडों का पता लगाती है।
  • हमें उन पंक्तियों को डालने से INSERT कथन के वास्तविक कार्य को दोहराने की आवश्यकता है, जो पहले से ही तालिका में नहीं हैं (INSTEAD OF की वजह से, हमने इंजन से सम्मिलन की ज़िम्मेदारी हटा दी है और इसे स्वयं करने की आवश्यकता है) ।
  • अंत में, हम मिलान किए गए पंक्तियों में नए 'सम्मिलित' डेटा के साथ सभी गैर-कुंजी कॉलम अपडेट करते हैं।

मुख्य अंक

  • यह कवर के तहत काम करता है, यानी जो तालिका में किसी भी डालने जबकि ट्रिगर सक्षम किया गया है ट्रिगर (जैसे आवेदन ORM, अन्य संग्रहित प्रक्रियाओं आदि) के अधीन किया जाएगा। कॉलर आम तौर पर अनवरत होगा कि INSTEAD OF ट्रिगर जगह में है।
  • डुप्लिकेट मानदंड (प्राकृतिक या सरोगेट) का पता लगाने के लिए एक प्रकार की कुंजी होनी चाहिए। मैंने इस मामले में COL_D माना है, लेकिन यह एक समग्र कुंजी हो सकता है। (कुंजी लेकिन, स्पष्ट कारणों के लिए IDENTITY नहीं किया जा सकता ग्राहक एक पहचान डालने नहीं किया जाएगा के बाद से)
  • ट्रिगर दोनों एकल और एकाधिक पंक्ति के लिए काम करता है

आवेषण नायब

  • standard disclaimers with triggers लागू होते हैं, और INSTEAD OF ट्रिगर्स के साथ - क्योंकि इससे एसक्यूएल सर्वर के अवलोकन व्यवहार में आश्चर्यजनक परिवर्तन हो सकते हैं, जैसे कि यह भी - INSTEAD OF ट्रिगर्स डेवलपर्स और डीबीए के लिए बर्बाद प्रयास और निराशा के घंटों का कारण बन सकता है जो आपकी मेज पर उनकी उपस्थिति से अवगत नहीं हैं।
  • इससे तालिका में सभी आवेषण प्रभावित होंगे। सिर्फ तुम्हारा नहीं।
+0

मुझे आश्चर्य है कि इस विकल्प में अधिक अपवर्तक नहीं हैं। यह एमएसएसक्यूएल में अप्सर्ट बनाने का एक रचनात्मक तरीका है। मेरी एकमात्र चिंता क्वेरी की दक्षता है, इस पर विचार करते हुए कि पंक्तियों को एक temp तालिका में डुप्लिकेट किया जाना चाहिए। यदि सम्मिलन सैकड़ों हजारों या लाखों पंक्तियों को प्रभावित कर रहा है, तो यह ट्रिगर कितना कुशल होगा, पहले हर प्रभावित पंक्ति को डुप्लिकेट करने की आवश्यकता है? –

0

वहाँ एसक्यूएल सर्वर में कोई DUPLICATE KEY UPDATE बराबर है, लेकिन आप मर्ज किए गए उपयोग कर सकते हैं और जब एसक्यूएल सर्वर से मेल खाने वाले इस, किया जाना यहाँ एक नजर है: multiple operations using merge

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