2010-10-01 23 views
38

पीएल/एसक्यूएल (ऑरैकल) में मौजूद नहीं होने पर एक पंक्ति को INSERT करने का सबसे आसान तरीका क्या है?ओरेकल: अगर कोई पंक्ति मौजूद नहीं है तो

मैं की तरह कुछ हैं:

IF NOT EXISTS (SELECT * FROM table WHERE name = 'jonny') THEN 
    INSERT INTO table VALUES ("jonny", null); 
END IF; 

लेकिन यह काम नहीं कर रहा।

नोट: इस तालिका में 2 फ़ील्ड हैं, कहें, नाम और आयु। लेकिन केवल नाम पीके है।

+0

क्या आप उम्मीद कर रहे हैं कि INSERT कथन आम तौर पर आवश्यक होगा (यानी आम तौर पर पंक्ति मौजूद नहीं होगी)? या वह पंक्ति आम तौर पर मौजूद होगी? –

+0

@justin: आम तौर पर पंक्ति मौजूद नहीं होगी। – Topera

+0

कूल। फिर यहां तीनों विकल्पों में से कोई भी आपके लिए काम करना चाहिए। –

उत्तर

59
INSERT INTO table 
SELECT 'jonny', NULL 
    FROM dual -- Not Oracle? No need for dual, drop that line 
WHERE NOT EXISTS (SELECT NULL -- canonical way, but you can select 
           -- anything as EXISTS only checks existence 
        FROM table 
        WHERE name = 'jonny' 
       ) 
+1

इस कोड में "दोहरी" क्या है? मेरा कुछ छूट रहा है। –

+0

@ जेफ वाकर: [इस सवाल को देखें] (http://stackoverflow.com/questions/3732422/select-from-nothing/3732466#3732466) –

+9

दोहरी ओरेकल में एक कॉलम और एक पंक्ति के साथ एक डमी टेबल है। यह खराब है (SQLite में आप बिना ओरेकल में चुन सकते हैं, कहीं भी चयन करते समय आपको दोहरी का उपयोग करना होगा)। – Benoit

14

यदि नाम एक पीके है, तो बस त्रुटि डालें और पकड़ें। किसी भी चेक के बजाय ऐसा करने का कारण यह है कि यह एक ही समय में कई ग्राहकों को सम्मिलित करने के साथ भी काम करेगा। यदि आप जांचते हैं और फिर सम्मिलित करते हैं, तो आपको उस समय के दौरान एक लॉक रखना होगा, या फिर भी त्रुटि की उम्मीद है।

इस के लिए कोड मान लिया जाये कि आप 10 ग्राम पर हैं की तरह

BEGIN 
    INSERT INTO table(name, age) 
    VALUES('johnny', null); 
EXCEPTION 
    WHEN dup_val_on_index 
    THEN 
    NULL; -- Intentionally ignore duplicates 
END; 
+0

कोड: 'तालिका मूल्यों में शामिल करें (' जॉनी ', शून्य); जब SQL स्कैनकोड!= -1 फिर राइस; अंत;/' sqlcode = -1 जब ओआरए -00001 – Benoit

+3

चाहे सम्मिलन को आज़माएं और अपवाद पकड़ने का अर्थ हो, इस पर निर्भर करता है कि आप कितनी बार INSERT को सफल होने की उम्मीद करते हैं। यदि 99% समय आप गैर-डुप्लिकेट मान डाल रहे हैं और यह केवल 1% त्रुटि को मिटा देगा, अपवाद को पकड़ने और अनदेखा करना एक अच्छा विकल्प है। यदि 99% बार पंक्ति पहले से मौजूद है, तो अपवाद को पकड़ना प्रदर्शन परिप्रेक्ष्य से समस्याग्रस्त हो सकता है। –

+0

इसके अलावा, मर्ज विधि एक पंक्ति में एकाधिक पंक्तियों के साथ काम करता है ... चुनें कि यह नहीं करता है। (मुझे पता है कि ओपी एक उदाहरण के रूप में एक पंक्ति बना रहा था, लेकिन इसके लिए (और जस्टिन गुफा द्वारा प्रदर्शित प्रदर्शन समस्या) मुझे लगता है कि विलय एक बेहतर समाधान है। – Adam

27

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

DECLARE 
    varTmp NUMBER:=0; 
BEGIN 
    -- checks 
    SELECT nvl((SELECT 1 FROM table WHERE name = 'john'), 0) INTO varTmp FROM dual; 

    -- insert 
    IF (varTmp = 1) THEN 
     INSERT INTO table (john, null) 
    END IF; 

END; 

क्षमा करें, लेकिन मैं IF जांच की जरूरत है क्योंकि मेरे कोड और अधिक जटिल है: @benoit जवाब का

SQL> create table foo (
    2 name varchar2(10) primary key, 
    3 age number 
    4 ); 

Table created. 

SQL> ed 
Wrote file afiedt.buf 

    1 merge into foo a 
    2 using (select 'johnny' name, null age from dual) b 
    3  on (a.name = b.name) 
    4 when not matched then 
    5 insert(name, age) 
    6* values(b.name, b.age) 
SQL>/

1 row merged. 

SQL>/

0 rows merged. 

SQL> select * from foo; 

NAME    AGE 
---------- ---------- 
johnny 
9

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

1

आप इस वाक्य विन्यास का उपयोग कर सकते हैं:

INSERT INTO table_name (name, age) 
select 'jonny', 18 from dual 
where not exists(select 1 from table_name where name = 'jonny'); 

अगर के रूप में "प्रतिस्थापन चर दर्ज करें" पूछने के लिए अपनी खुली एक पॉप फिर ऊपर प्रश्नों से पहले इस का उपयोग करें:

set define off; 
INSERT INTO table_name (name, age) 
select 'jonny', 18 from dual 
where not exists(select 1 from table_name where name = 'jonny'); 
+2

तीन साल पहले पोस्ट किए गए स्वीकृत उत्तर से अलग कैसे है? – Mat

3

इसके अलावा करने के लिए अब तक दिए गए सही और वैध उत्तरों में ignore_row_on_dupkey_index संकेत भी है जिसका उपयोग आप करना चाहते हैं:

create table tq84_a (
    name varchar2 (20) primary key, 
    age number 
); 

insert /*+ ignore_row_on_dupkey_index(tq84_a(name)) */ into tq84_a values ('Johnny', 77); 
insert /*+ ignore_row_on_dupkey_index(tq84_a(name)) */ into tq84_a values ('Pete' , 28); 
insert /*+ ignore_row_on_dupkey_index(tq84_a(name)) */ into tq84_a values ('Sue' , 35); 
insert /*+ ignore_row_on_dupkey_index(tq84_a(name)) */ into tq84_a values ('Johnny', null); 

select * from tq84_a; 

संकेत Tahiti पर वर्णित है।

5

मुझे उदाहरण के लिए उदाहरणों का पालन करना थोड़ा मुश्किल लगता है, जहां आप यह सुनिश्चित करना चाहते हैं कि गंतव्य तालिका में एक पंक्ति मौजूद है (विशेष रूप से जब आपके पास प्राथमिक कुंजी के रूप में दो कॉलम हों), लेकिन प्राथमिक कुंजी वहां मौजूद नहीं हो सकती है सब कुछ चुनने के लिए कुछ भी नहीं है।

यह वही मेरे लिए काम किया है:

MERGE INTO table1 D 
    USING (
     -- These are the row(s) you want to insert. 
     SELECT 
     'val1' AS FIELD_A, 
     'val2' AS FIELD_B 
     FROM DUAL 

    ) S ON (
     -- This is the criteria to find the above row(s) in the 
     -- destination table. S refers to the rows in the SELECT 
     -- statement above, D refers to the destination table. 
     D.FIELD_A = S.FIELD_A 
     AND D.FIELD_B = S.FIELD_B 
    ) 

    -- This is the INSERT statement to run for each row that 
    -- doesn't exist in the destination table. 
    WHEN NOT MATCHED THEN INSERT (
     FIELD_A, 
     FIELD_B, 
     FIELD_C 
    ) VALUES (
     S.FIELD_A, 
     S.FIELD_B, 
     'val3' 
    ) 

महत्वपूर्ण बिंदु हैं:

  • SELECT बयान USING ब्लॉक के अंदर हमेशा पंक्तियों को वापस करना होगा। यदि इस क्वेरी से कोई पंक्तियां वापस नहीं आती हैं, तो कोई भी पंक्तियां डाली या अपडेट नहीं की जाएंगी। यहां मैं DUAL से चुनता हूं, इसलिए हमेशा एक पंक्ति होगी।
  • ON स्थिति मिलान पंक्तियों के लिए मानदंड निर्धारित करती है। यदि ON में कोई मिलान नहीं है तो INSERT कथन चलाया जाएगा।
  • यदि आप अपडेट पर अधिक नियंत्रण चाहते हैं तो आप WHEN MATCHED THEN UPDATE क्लॉज भी जोड़ सकते हैं।
0

CTE और केवल CTE :-)

सिर्फ अतिरिक्त सामान बाहर फेंक देते हैं। जीवन के सभी मामलों के लिए यहां लगभग पूर्ण और क्रियात्मक रूप है। और आप किसी भी संक्षिप्त रूप का उपयोग कर सकते हैं।

INSERT INTO reports r 
    (r.id, r.name, r.key, r.param) 

-

-- Invoke this script from "WITH" to the end (";") 
    -- to debug and see prepared values. 
    WITH 

    -- Some new data to add. 
    newData AS(
      SELECT 'Name 1' name, 'key_new_1' key FROM DUAL 
    UNION SELECT 'Name 2' NAME, 'key_new_2' key FROM DUAL 
    UNION SELECT 'Name 3' NAME, 'key_new_3' key FROM DUAL 
    ), 
    -- Any single row for copying with each new row from "newData", 
    -- if you will of course. 
    copyData AS(
     SELECT r.* 
     FROM reports r 
     WHERE r.key = 'key_existing' 
     -- ! Prevent more than one row to return. 
     AND FALSE -- do something here for than! 
    ), 
    -- Last used ID from the "reports" table (it depends on your case). 
    -- (not going to work with concurrent transactions) 
    maxId AS (SELECT MAX(id) AS id FROM reports), 

-

-- Some construction of all data for insertion. 
    SELECT maxId.id + ROWNUM, newData.name, newData.key, copyData.param 
    FROM copyData 
    -- matrix multiplication :) 
    -- (or a recursion if you're imperative coder) 
    CROSS JOIN newData 
    CROSS JOIN maxId 

-

-- Let's prevent re-insertion. 
    WHERE NOT EXISTS (
     SELECT 1 FROM reports rs 
     WHERE rs.name IN(
     SELECT name FROM newData 
    )); 

मैं इसे "यदि मौजूद नहीं" स्टेरॉयड पर कहते हैं। तो, यह मेरी मदद करता है और मैं ज्यादातर ऐसा करता हूं।

+1

'चयन MAX से आईडी आईडी) आईडी समवर्ती लेनदेन के साथ काम नहीं करेगा –

+0

क्या आप कृपया कुछ ऑफर कर सकते हैं? मुझे बस अच्छी तरह से सभी चीजें नहीं पता हैं। – it3xl

+0

और निश्चित रूप से मुझे अनुक्रमों के बारे में पता है) – it3xl

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