ওরাকল: কীভাবে ইউপিএসআরটি করা যায় (আপডেট বা কোনও টেবিলের মধ্যে সন্নিবেশ করা যায়?)


293

ইউপিএসআরটি অপারেশনটি কোনও সারণীতে আপডেট করে বা সারি সন্নিবেশ করে, যদি টেবিলে ইতিমধ্যে ডেটার সাথে মেলে এমন একটি সারি থাকে তবে তা নির্ভর করে:

if table t has a row exists that has key X:
    update t set mystuff... where mykey=X
else
    insert into t mystuff...

যেহেতু ওরাকল একটি নির্দিষ্ট ইউপিএসইআরটি বিবৃতি নেই, এটি করার সর্বোত্তম উপায় কী?

উত্তর:


60

মার্জ ("পুরানো ফ্যাশন উপায়") এর বিকল্প:

begin
   insert into t (mykey, mystuff) 
      values ('X', 123);
exception
   when dup_val_on_index then
      update t 
      set    mystuff = 123 
      where  mykey = 'X';
end;   

3
@ চটচকি: সত্যি? একটি ব্যাখ্যা সহায়ক হবে।
টনি অ্যান্ড্রুজ

15
সমস্যাটি হ'ল আপনার সন্নিবেশ এবং আপডেটের মধ্যে একটি উইন্ডো রয়েছে যেখানে অন্য কোনও প্রক্রিয়া সফলভাবে মুছতে মুছতে পারে। তবে আমি এই প্যাটার্নটি কোনও টেবিলটিতে ব্যবহার করেছি যা এর বিপরীতে মুছে ফেলা হয়নি।
chotchki

2
ঠিক আছে আমি রাজি. কেন জানি এটা আমার কাছে স্পষ্ট ছিল না।
টনি অ্যান্ড্রুজ

4
চটচির সাথে আমি একমত নই। "লক সময়কাল: লেনদেনের মধ্যে বিবৃতি দ্বারা অর্জিত সমস্ত লকগুলি লেনদেনের সময়কালের জন্য রাখা হয়, নোংরা পাঠ্য, হারানো আপডেট এবং ধ্বংসাত্মক ডিডিএল ক্রিয়াকলাপ সহকারী লেনদেন থেকে ধ্বংসাত্মক হস্তক্ষেপ রোধ করে।" স্যুইস: লিঙ্ক
yohannc

5
@ ওহ্যাঙ্ক: আমি মনে করি মূল বক্তব্যটি হ'ল আমরা চেষ্টা করে এবং একটি সারি toোকাতে ব্যর্থ হয়ে কোনও লকই অর্জন করতে পারি নি।
টনি অ্যান্ড্রুজ

211

মার্জ বিবৃতি দুই টেবিল মধ্যে ডেটা সংমিশ্রণে খেলা হয়। DUAL ব্যবহার করে আমাদের এই কমান্ডটি ব্যবহার করতে দেয়। মনে রাখবেন যে এটি সমবর্তী অ্যাক্সেসের বিরুদ্ধে সুরক্ষিত নয়।

create or replace
procedure ups(xa number)
as
begin
    merge into mergetest m using dual on (a = xa)
         when not matched then insert (a,b) values (xa,1)
             when matched then update set b = b+1;
end ups;
/
drop table mergetest;
create table mergetest(a number, b number);
call ups(10);
call ups(10);
call ups(20);
select * from mergetest;

A                      B
---------------------- ----------------------
10                     2
20                     1

57
স্পষ্টতই "মার্জ" বিবৃতিটি পারমাণবিক নয়। এটি একই সাথে ব্যবহার করা হলে "ORA-0001: অনন্য প্রতিবন্ধকতা" এর ফলস্বরূপ হতে পারে। কোনও ম্যাচের অস্তিত্বের জন্য পরীক্ষা এবং নতুন রেকর্ড সন্নিবেশ করানো কোনও লক দ্বারা সুরক্ষিত নয়, তাই রেসের শর্ত রয়েছে। নির্ভরযোগ্যভাবে এটি করার জন্য, আপনাকে এই ব্যতিক্রমটি ধরতে হবে এবং হয় মার্জটি আবার চালাতে হবে বা পরিবর্তে একটি সাধারণ আপডেট করতে হবে। ওরাকল 10-এ, "লগ ত্রুটিগুলি" শুল্কটি আপনি যখন কোনও ত্রুটি দেখা দেয় তখন বাকী সারিগুলির সাথে চালিয়ে যাওয়ার জন্য এবং আপত্তিজনক সারিটি কেবল থামিয়ে রাখার পরিবর্তে অন্য টেবিলে লগ করতে পারেন।
টিম সিলভেস্টার

1
হাই, আমি আমার ক্যোয়ারীতে একই ক্যোয়ারী প্যাটার্নটি ব্যবহার করার চেষ্টা করেছি তবে কোনওভাবে আমার কোয়েরিটি সদৃশ সারিগুলি সন্নিবেশ করছে। আমি ডুয়াল টেবিল সম্পর্কে আরও তথ্য সন্ধান করতে সক্ষম নই। কেউ দয়া করে আমাকে বলতে পারেন আমি কোথায় ডুয়াল সম্পর্কিত তথ্য এবং মার্জ বাক্য গঠন সম্পর্কেও পেতে পারি?
শেখর

5
@ শেখর ডুয়াল একটি ডামি টেবিল যা একটি একক সারি এবং কলামন adp-gmbh.ch/ora/misc/dual.html
যোগোগুনো

7
@ টিমসিলভেস্টার - ওরাকল লেনদেনগুলি ব্যবহার করে, সুতরাং লেনদেনের শুরুতে ডেটা স্ন্যাপশটের গ্যারান্টি দেয় যে কোনও লেনদেনের মধ্যে এটির মধ্যে যে কোনও পরিবর্তনগুলি সংরক্ষণ করে throughout ডাটাবেসে সমকালীন কলগুলি পূর্বাবস্থায় স্ট্যাক ব্যবহার করে; সুতরাং ওরাকল কখন সমবর্তী লেনদেন শুরু / সমাপ্ত হয়েছে তার ক্রমের ভিত্তিতে চূড়ান্ত অবস্থা পরিচালনা করবে। সুতরাং, একই এসকিউএল কোডে কতগুলি সমবর্তী কল করা হচ্ছে তা নির্বিশেষে সন্নিবেশ করার আগে যদি সীমাবদ্ধতা পরীক্ষা করা হয় তবে আপনার কখনই রেসের শর্ত থাকবে না। সবচেয়ে খারাপ ক্ষেত্রে, আপনি প্রচুর বিতর্ক পেতে পারেন এবং চূড়ান্ত অবস্থায় পৌঁছতে ওরাকলকে আরও বেশি সময় লাগবে।
নিও

2
@ র্যান্ডিমগ্রুডার এটি কি এর 2015 এবং আমরা এখনও ওরাকলে নির্ভরযোগ্যভাবে একটি উপস্থাপনা করতে পারি না! আপনি কি একযোগে নিরাপদ সমাধান জানেন?
ডান বি

105

পিএল / এসকিউএল-র উপরের দ্বৈত উদাহরণটি দুর্দান্ত ছিল কারণ আমি অনুরূপ কিছু করতে চেয়েছিলাম, তবে আমি এটি ক্লায়েন্টের পক্ষেই চেয়েছিলাম ... সুতরাং এসকিউএল আমি এখানে কিছু সি থেকে সরাসরি অনুরূপ বিবৃতি প্রেরণ করেছি is

MERGE INTO Employee USING dual ON ( "id"=2097153 )
WHEN MATCHED THEN UPDATE SET "last"="smith" , "name"="john"
WHEN NOT MATCHED THEN INSERT ("id","last","name") 
    VALUES ( 2097153,"smith", "john" )

তবে একটি সি # দৃষ্টিকোণ থেকে এটি আপডেট করার চেয়ে ধীরে ধীরে সরবরাহ করে এবং দেখায় যে সারিগুলিতে 0 টি প্রভাবিত হয়েছিল এবং এটি যদি সন্নিবেশ করছিল তবে তা করা হচ্ছে।


10
আমি এই প্যাটার্নটি আবার পরীক্ষা করে দেখতে এখানে ফিরে এসেছি। একসাথে সন্নিবেশ করার চেষ্টা করা হলে এটি নিঃশব্দে ব্যর্থ হয়। একটি সন্নিবেশ কার্যকর হয়, দ্বিতীয় মার্জ .োকানো বা আপডেট করা হয় না। যাইহোক, দুটি পৃথক বিবৃতি করার দ্রুত পদ্ধতির নিরাপদ।
সেনেসো

3
আমার মত oralcle নতুনদের কি এই জিজ্ঞাসা করতে পারেন দ্বৈত : টেবিল এই দেখতে stackoverflow.com/q/73751/808698
হাজো Thelen

5
খুব খারাপ যে এই প্যাটার্নটি সহ আমাদের দ্বিগুণ ডেটা লিখতে হবে (জন, স্মিথ ...)। এই ক্ষেত্রে, আমি ব্যবহার করে কিছুই জিততে পারি না এবং আমি তখন আরও সহজ ব্যবহার পছন্দ করি । MERGEDELETEINSERT
নিকোলাস বারবুলেসকো

: @NicolasBarbulesco এই উত্তর দুইবার ডেটা লিখতে দরকার নেই stackoverflow.com/a/4015315/8307814
whyer

@NicolasBarbulescoMERGE INTO mytable d USING (SELECT 1 id, 'x' name from dual) s ON (d.id = s.id) WHEN MATCHED THEN UPDATE SET d.name = s.name WHEN NOT MATCHED THEN INSERT (id, name) VALUES (s.id, s.name);
whyer

46

ব্যতিক্রম চেক ছাড়া অন্য বিকল্প:

UPDATE tablename
    SET val1 = in_val1,
        val2 = in_val2
    WHERE val3 = in_val3;

IF ( sql%rowcount = 0 )
    THEN
    INSERT INTO tablename
        VALUES (in_val1, in_val2, in_val3);
END IF;

আপনার প্রদত্ত সমাধান আমার পক্ষে কাজ করে না। % সারি গণনা কি কেবল সুস্পষ্ট কার্সার দিয়ে কাজ করে?
সিনেসো

আপডেটটি যদি 0 টি সারি পরিবর্তিত হয় তবে রেকর্ডটি ইতিমধ্যে ছিল এবং মানগুলি একই ছিল?
অ্যাড্রিয়ানো ভারোলি পিয়াজা

10
@ অ্যাড্রিয়ানো: স্কেল% সারি গণনা তখনও ফিরে আসবে> 0 যদি বিধিটি কোনও সারিগুলির সাথে মেলে, যদিও আপডেটটি আসলে এই সারিগুলির কোনও ডেটা পরিবর্তন করে না।
টনি অ্যান্ড্রুজ

কাজ করে না: PLS-00207: সনাক্তকারী 'COUNT', অন্তর্ভুক্ত কার্সার এসকিউএল এর জন্য প্রয়োগ করা, কোনও আইনী কার্সার বৈশিষ্ট্য নয়
প্যাট্রিক বেক

সিনট্যাক্স ত্রুটিগুলি এখানে :(
ইলিমারন

27
  1. উপস্থিত না থাকলে sertোকান
  2. হালনাগাদ:
    
Mytable মধ্যে অন্তর্ভুক্ত করুন (আইডি 1, টি 1) 
  ডুয়াল থেকে 11, 'x1' নির্বাচন করুন 
  যেখানে নেই (মাইটিবল থেকে আইডি 1 নির্বাচন করুন যেখানে আইডি 1 = 11); 

MyTable SET t1 আপডেট করুন = 'x1' যেখানে আইডি 1 = 11;

26

টিম সিলভেস্টারের মন্তব্যে যেমন উল্লেখ করা হয়েছে, এখনও অবধি দেওয়া উত্তরের কোনও উত্তরই সমবর্তী অ্যাক্সেসের মুখে নিরাপদ নয় এবং বর্ণের ক্ষেত্রে ব্যতিক্রম বাড়াবে। এটি ঠিক করার জন্য, সন্নিবেশ / আপডেট কম্বো অবশ্যই কোনও ধরণের লুপ স্টেটমেন্টে আবৃত থাকতে হবে, যাতে কোনও ব্যতিক্রমের ক্ষেত্রে পুরো জিনিসটি আবার চেষ্টা করা হয়।

উদাহরণস্বরূপ, একই সাথে চালানোর সময় গ্রোমিট কোডটি কীভাবে একটি লুপে মুড়িয়ে ফেলা যায় তা এখানে:

PROCEDURE MyProc (
 ...
) IS
BEGIN
 LOOP
  BEGIN
    MERGE INTO Employee USING dual ON ( "id"=2097153 )
      WHEN MATCHED THEN UPDATE SET "last"="smith" , "name"="john"
      WHEN NOT MATCHED THEN INSERT ("id","last","name") 
        VALUES ( 2097153,"smith", "john" );
    EXIT; -- success? -> exit loop
  EXCEPTION
    WHEN NO_DATA_FOUND THEN -- the entry was concurrently deleted
      NULL; -- exception? -> no op, i.e. continue looping
    WHEN DUP_VAL_ON_INDEX THEN -- an entry was concurrently inserted
      NULL; -- exception? -> no op, i.e. continue looping
  END;
 END LOOP;
END; 

এনবি লেনদেনের মোডে SERIALIZABLE, আমি বিটিডব্লিউর প্রস্তাব দিই না, আপনি ওআরএ -08177 এ চলে যেতে পারেন: পরিবর্তে এই লেনদেন ব্যতিক্রমের অ্যাক্সেসকে সিরিয়ালাইজ করতে পারবেন না


3
অসাধারণ! অবশেষে, একযোগে নিরাপদ উত্তর অ্যাক্সেস করে। কোনও ক্লায়েন্টের (যেমন জাভা ক্লায়েন্টের কাছ থেকে) এরকম কনস্ট্রাক্ট ব্যবহারের কোনও উপায়?
সেবিয়ান

1
আপনি একটি স্টোর প্রোক না কল করতে চান? ঠিক আছে, সেই ক্ষেত্রে আপনি নির্দিষ্ট জাভা ব্যতিক্রমগুলি ধরতে পারেন এবং জাভা লুপে আবার চেষ্টা করতে পারেন। এটি ওরাকলের এসকিউএল-এর চেয়ে জাভাতে অনেক বেশি সুবিধাজনক a
ইউজিন বেরেসভস্কি

আমি দুঃখিত: আমি যথেষ্ট নির্দিষ্ট ছিল না। তবে আপনি সঠিক উপায়টি বুঝতে পেরেছিলেন। আপনি যেমন বলেছিলেন তেমনভাবে আমি পদত্যাগ করেছি। তবে আমি ১০০% সন্তুষ্ট নই কারণ এটি আরও এসকিউএল ক্যোয়ারী, আরও ক্লায়েন্ট / সার্ভার রাউন্ডট্রিপগুলি উত্পন্ন করে। এটি কার্য সম্পাদন-ভিত্তিক কোনও ভাল সমাধান নয়। তবে আমার লক্ষ্যটি হ'ল আমার প্রকল্পের জাভা বিকাশকারীরা যে কোনও সারণীতে উপস্থাপনের জন্য আমার পদ্ধতিটি ব্যবহার করতে দিন (আমি প্রতি টেবিলের জন্য একটি পিএলএসকিউএল সঞ্চিত প্রক্রিয়া তৈরি করতে পারি না, বা প্রতি পৃষ্ঠার লেখার জন্য একটি পদ্ধতি তৈরি করতে পারি)।
সেবিয়ান

@ সিবিয়েন আমি সম্মত, এটি এসকিউএল রাজ্যে অন্তর্ভুক্ত করা ভাল লাগবে এবং আমি মনে করি আপনি এটি করতে পারেন। আমি কেবল এটি সন্ধান করার জন্য স্বেচ্ছাসেবকই করছি না ... :) প্লাস, বাস্তবে এই ব্যতিক্রমগুলি সম্ভবত নীল চাঁদে একাধিকবার কম ঘটবে, সুতরাং আপনার 99.9% ক্ষেত্রে পারফরম্যান্সের উপর প্রভাব দেখা উচিত নয়। অবশ্যই লোড টেস্টিং করার সময় ...
ইউজিন বেরেসভস্কি

24

আমি গ্রোমিট উত্তর চাই, এটির জন্য ডুপ মানের দরকার হয়। আমি এটির সমাধান খুঁজে পেয়েছি যেখানে এটি একবার উপস্থিত হতে পারে: http://forums.devshed.com/showpost.php?p=1182653&postcount=2

MERGE INTO KBS.NUFUS_MUHTARLIK B
USING (
    SELECT '028-01' CILT, '25' SAYFA, '6' KUTUK, '46603404838' MERNIS_NO
    FROM DUAL
) E
ON (B.MERNIS_NO = E.MERNIS_NO)
WHEN MATCHED THEN
    UPDATE SET B.CILT = E.CILT, B.SAYFA = E.SAYFA, B.KUTUK = E.KUTUK
WHEN NOT MATCHED THEN
    INSERT (  CILT,   SAYFA,   KUTUK,   MERNIS_NO)
    VALUES (E.CILT, E.SAYFA, E.KUTUK, E.MERNIS_NO); 

2
মানে INSERT (B.CILT, B.SAYFA, B.KUTUK, B.MERNIS_NO) VALUES (E.CILT, E.SAYFA, E.KUTUK, E.MERNIS_NO); ?
মাত্তিও

অবশ্যই। ধন্যবাদ। সংশোধন করা হয়েছে।
হবিটাস

ধন্যবাদ আপনি নিজের উত্তরটি সম্পাদনা করেছেন! :) আমার সম্পাদনা দুঃখজনকভাবে stackoverflow.com/review/suggested-edits/7555674
মাত্তিও

9

দুটি সমাধান সম্পর্কিত একটি নোট যা পরামর্শ দেয়:

1) সন্নিবেশ করুন, ব্যতিক্রম হলে আপডেট করুন,

অথবা

2) আপডেট করুন, যদি বর্গ% রোউমাউন্ট = 0 তবে সন্নিবেশ করান

প্রথমে sertোকানো বা আপডেট করতে হবে কিনা তা প্রশ্নও প্রয়োগ নির্ভর। আপনি কি আরও সন্নিবেশ বা আরও আপডেটের প্রত্যাশা করছেন? যার সফল হওয়ার সম্ভাবনা সবচেয়ে বেশি তার প্রথমে চলে যাওয়া উচিত।

আপনি যদি ভুলটি বেছে নেন তবে আপনি একগুচ্ছ অপ্রয়োজনীয় সূচক পড়বেন। একটি বিশাল চুক্তি নয় তবে এখনও বিবেচনা করার মতো কিছু।


স্কয়ার% নোটফাউন্ডটি আমার ব্যক্তিগত পছন্দ
আর্টুরো হার্নান্দেজ

8

আমি বছরের পর বছর ধরে প্রথম কোডের নমুনাটি ব্যবহার করছি। গণনার চেয়ে নোটফাউন্ডে লক্ষ্য করুন।

UPDATE tablename SET val1 = in_val1, val2 = in_val2
    WHERE val3 = in_val3;
IF ( sql%notfound ) THEN
    INSERT INTO tablename
        VALUES (in_val1, in_val2, in_val3);
END IF;

নীচের কোডটি সম্ভবত নতুন এবং উন্নত কোড

MERGE INTO tablename USING dual ON ( val3 = in_val3 )
WHEN MATCHED THEN UPDATE SET val1 = in_val1, val2 = in_val2
WHEN NOT MATCHED THEN INSERT 
    VALUES (in_val1, in_val2, in_val3)

প্রথম উদাহরণে আপডেটটি একটি সূচক সন্ধান করে। এটি করতে হবে, ডান সারিতে আপডেট করার জন্য। ওরাকল একটি অন্তর্নিহিত কার্সার খোলে, এবং আমরা এটি একটি সংশ্লিষ্ট সন্নিবেশটিকে মোড়ানোর জন্য ব্যবহার করি যাতে আমরা জানি যে সারণিটি তখনই ঘটবে যখন কীটির অস্তিত্ব থাকবে না। তবে সন্নিবেশ একটি স্বতন্ত্র কমান্ড এবং এটির জন্য দ্বিতীয় সন্ধান করা উচিত। আমি মার্জ কমান্ডের অভ্যন্তরীণ কার্যকারিতা জানি না তবে যেহেতু কমান্ডটি একক ইউনিট, ওরাকল একটি একক সূচী অনুসন্ধানের সাথে সঠিক সন্নিবেশ বা আপডেট করতে পারত।

আমার মনে হয় আপনার যখন কিছু প্রক্রিয়াজাতকরণ করতে হবে তখন মার্জ করা ভাল means যার অর্থ কয়েকটি সারণী থেকে ডেটা নেওয়া এবং একটি টেবিল আপডেট করা, সম্ভবত সারি সন্নিবেশ করা বা মোছা। তবে একক সারির ক্ষেত্রে, সিনট্যাক্সটি সাধারণ হওয়ার কারণে আপনি প্রথম কেসটি বিবেচনা করতে পারেন।


0

মার্জ সহ এক টেবিলের জন্য অন্য টেবিল প্রবেশের জন্য উদাহরণটি অনুলিপি করুন এবং আটকান:

CREATE GLOBAL TEMPORARY TABLE t1
    (id VARCHAR2(5) ,
     value VARCHAR2(5),
     value2 VARCHAR2(5)
     )
  ON COMMIT DELETE ROWS;

CREATE GLOBAL TEMPORARY TABLE t2
    (id VARCHAR2(5) ,
     value VARCHAR2(5),
     value2 VARCHAR2(5))
  ON COMMIT DELETE ROWS;
ALTER TABLE t2 ADD CONSTRAINT PK_LKP_MIGRATION_INFO PRIMARY KEY (id);

insert into t1 values ('a','1','1');
insert into t1 values ('b','4','5');
insert into t2 values ('b','2','2');
insert into t2 values ('c','3','3');


merge into t2
using t1
on (t1.id = t2.id) 
when matched then 
  update set t2.value = t1.value,
  t2.value2 = t1.value2
when not matched then
  insert (t2.id, t2.value, t2.value2)  
  values(t1.id, t1.value, t1.value2);

select * from t2

ফলাফল:

  1. খ 4 5
  2. গ 3 3
  3. a 1 1

-3

এটা চেষ্টা কর,

insert into b_building_property (
  select
    'AREA_IN_COMMON_USE_DOUBLE','Area in Common Use','DOUBLE', null, 9000, 9
  from dual
)
minus
(
  select * from b_building_property where id = 9
)
;

-6

Http://www.praetoriate.com/oracle_tips_upserts.htm থেকে :

"ওরাকল 9 আই-তে, কোনও ইউপিএসআরটি একটি বিবৃতিতে এই কাজটি সম্পাদন করতে পারে:"

INSERT
FIRST WHEN
   credit_limit >=100000
THEN INTO
   rich_customers
VALUES(cust_id,cust_credit_limit)
   INTO customers
ELSE
   INTO customers SELECT * FROM new_customers;

14
-1 টিপিকাল ডন বার্লসন সিআর @ পি আমি ভয় করি - এটি একটি টেবিল বা অন্য একটি সারণি, এখানে কোনও "উপস্থাপনা" নেই!
টনি অ্যান্ড্রুজ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.