নির্মল ON CONFLICT DO UPDATE
আচরণ
ম্যানুয়ালটি এখানে বিবেচনা করুন :
সন্নিবেশের জন্য প্রস্তাবিত প্রতিটি স্বতন্ত্র সারির জন্য, হয় সন্নিবেশ এগিয়ে যায়, বা যদি সালিসি বাধা বা নির্দিষ্ট করে সূচক
conflict_target
লঙ্ঘন করা হয়, বিকল্প conflict_action
নেওয়া হয়।
বোল্ড জোর আমার। সুতরাং আপনাকে ( WHERE
দ ) এর দফায় স্বতন্ত্র সূচীতে অন্তর্ভুক্ত কলামগুলির জন্য পূর্বাভাসগুলি পুনরাবৃত্তি করতে হবে না :UPDATE
conflict_action
INSERT INTO test_upsert AS tu
(name , status, test_field , identifier, count)
VALUES ('shaun', 1 , 'test value', 'ident' , 1)
ON CONFLICT (name, status, test_field) DO UPDATE
SET count = tu.count + 1;
WHERE tu.name = 'shaun' AND tu.status = 1 AND tu.test_field = 'test value'
অনন্য লঙ্ঘন ইতিমধ্যে আপনার যুক্ত WHERE
ক্লজটি যে অপ্রয়োজনীয়ভাবে প্রয়োগ করবে তা তা ইতিমধ্যে প্রতিষ্ঠিত করে।
আংশিক সূচি স্পষ্ট করুন
আপনি নিজের উল্লেখ করার মতো WHERE
একটি আসল আংশিক সূচক তৈরি করার জন্য একটি ধারা যুক্ত করুন (তবে বিপরীত যুক্তির সাথে):
CREATE UNIQUE INDEX test_upsert_partial_idx
ON public.test_upsert (name, status)
WHERE test_field IS NULL; -- not: "is not null"
আপনার ইউপিএসআরটিতে এই আংশিক সূচকটি ব্যবহার করার জন্য আপনার @ ম্যাসেজের মতো প্রদর্শিত একটি মিল দরকার :conflict_target
ON CONFLICT (name, status) WHERE test_field IS NULL
এখন উপরের আংশিক সূচকটি অনুমান করা হয়েছে। তবে ম্যানুয়ালটিতে যেমন উল্লেখ করা হয়েছে :
[...] একটি অন-আংশিক অনন্য সূচক (প্রাকটিক্যাল ব্যতীত একটি অনন্য সূচক) অনুমান করা হবে (এবং এভাবে ব্যবহার করা হবে ON CONFLICT
) যদি অন্য সূত্রগুলি সন্তুষ্ট করে এমন প্রতিটি সূচক উপলব্ধ থাকে।
আপনার যদি অতিরিক্ত (বা শুধুমাত্র) সূচক থাকে তবে এটি (name, status)
(এছাড়াও) ব্যবহৃত হবে। একটি সূচক (name, status, test_field)
স্পষ্টভাবে অনুমান করা হবে না । এটি আপনার সমস্যার ব্যাখ্যা দেয় না, তবে পরীক্ষার সময় বিভ্রান্তি বাড়িয়ে তোলে।
সমাধান
এআইআইআই, উপরের কোনওটিই আপনার সমস্যার সমাধান করে না। আংশিক সূচকের সাথে, কেবলমাত্র ন্যূুল মানগুলির সাথে বিশেষ কিছু পাওয়া যায়। এবং অন্য সদৃশ সারিগুলি eitherোকানো হবে যদি আপনার কাছে অন্য কোনও মিলের অনন্য সূচক / সীমাবদ্ধতা না থাকে, বা যদি আপনি এটি করেন তবে একটি ব্যতিক্রম বাড়ান। আমি মনে করি এটি আপনি চান না তুমি লেখ:
সংমিশ্রিত কীটি 20 টি কলাম দ্বারা গঠিত, যার মধ্যে 10 টি স্থূল হতে পারে।
আপনি একটি সদৃশ ঠিক কি বিবেচনা? পোস্টগ্রিস (এসকিউএল স্ট্যান্ডার্ড অনুযায়ী) দুটি নূন্যমূল্যকে সমান হিসাবে বিবেচনা করে না। ম্যানুয়াল:
সাধারণভাবে, সারণীতে একাধিক সারি থাকলে সীমাবদ্ধতায় অন্তর্ভুক্ত সমস্ত কলামের মান সমান হলে একটি অনন্য বাধা লঙ্ঘন করা হয়। যাইহোক, দুটি নাল মান এই তুলনায় কখনও সমান বিবেচিত হয় না। এর অর্থ এমনকি অনন্য প্রতিবন্ধকতার উপস্থিতিতেও অনুলিপিযুক্ত সারিগুলি সংরক্ষণ করা সম্ভব যা অন্তত একটি সীমাবদ্ধ কলামগুলিতে নাল মান রাখে। এই আচরণটি এসকিউএল স্ট্যান্ডার্ডের সাথে সঙ্গতিপূর্ণ তবে আমরা শুনেছি যে অন্যান্য এসকিউএল ডাটাবেসগুলি এই নিয়মটি অনুসরণ না করে। তাই পোর্টেবল হওয়ার উদ্দেশ্যে তৈরি অ্যাপ্লিকেশনগুলি বিকাশ করার সময় সাবধান হন।
সম্পর্কিত:
আমি ধরে নিলামNULL
আপনি সমস্ত 10 টি কলামের মানগুলি সমান হিসাবে বিবেচনাকরতে চান। এখানে প্রদর্শিত যেমন একটি অতিরিক্ত আংশিক সূচী সহ একটি একক nallable কলাম কভার করা মার্জিত এবং ব্যবহারিক:
তবে আরও নালামযোগ্য কলামগুলির জন্য এটি দ্রুত হাতছাড়া হয়ে যায়। নালামযোগ্য কলামগুলির প্রতিটি স্বতন্ত্র সমন্বয়ের জন্য আপনার আংশিক সূচক প্রয়োজন index মাত্র 2 তাদের জন্য 3 আংশিক ইনডেক্স যে এর জন্য (a)
, (b)
এবং (a,b)
। সংখ্যাটি তত দ্রুত বাড়ছে 2^n - 1
। আপনার 10 টি নালামযোগ্য কলামগুলির জন্য, NULL মানগুলির সমস্ত সম্ভাব্য সংমিশ্রণগুলি কভার করতে আপনার ইতিমধ্যে 1023 আংশিক সূচক প্রয়োজন। যাও না।
সহজ সমাধান: নুল মানগুলি প্রতিস্থাপন করুন এবং জড়িত কলামগুলি সংজ্ঞায়িত করুন NOT NULL
এবং সমস্ত কিছু একটি UNIQUE
সীমাবদ্ধতার সাথে ঠিক কাজ করবে ।
যদি এটি কোনও বিকল্প না হয় তবে আমি সূচকে COALESCE
NULL প্রতিস্থাপনের জন্য একটি এক্সপ্রেশন সূচকটি প্রস্তাব করি :
CREATE UNIQUE INDEX test_upsert_solution_idx
ON test_upsert (name, status, COALESCE(test_field, ''));
খালি স্ট্রিং ( ''
) অক্ষর প্রকারের জন্য একটি সুস্পষ্ট প্রার্থী, তবে আপনি এমন কোনও আইনি মান ব্যবহার করতে পারেন যা কখনও প্রদর্শিত হয় না বা আপনার "অনন্য" সংজ্ঞা অনুসারে NULL দিয়ে ভাঁজ করা যায় ।
তারপরে এই বিবৃতিটি ব্যবহার করুন:
INSERT INTO test_upsert as tu(name,status,test_field,identifier, count)
VALUES ('shaun', 1, null , 'ident', 11) -- works with
, ('bob' , 2, 'test value', 'ident', 22) -- and without NULL
ON CONFLICT (name, status, COALESCE(test_field, '')) DO UPDATE -- match expr. index
SET count = COALESCE(tu.count + EXCLUDED.count, EXCLUDED.count, tu.count);
@ টাইপারউবের মত আমিও ধরে নিলাম আপনি আসলে count
বিদ্যমান গণনায় যোগ করতে চান । যেহেতু কলামটি নুল হতে পারে, তাই এনওএল যুক্ত করে কলামটি ন্যূনাল সেট করা হবে। আপনি যদি সংজ্ঞা দেন তবে আপনি count NOT NULL
সরল করতে পারবেন।
অন্য ধারণাটি হ'ল সমস্ত অনন্য লঙ্ঘন coverেকে দেওয়ার জন্য বিবৃতি থেকে দ্বন্দ্ব_দলটি বাদ দিন । তারপরে আপনি "অনন্য" হওয়ার কথা বলে এর আরও পরিশীলিত সংজ্ঞার জন্য আপনি বিভিন্ন অনন্য সূচী সংজ্ঞায়িত করতে পারেন। কিন্তু যে সঙ্গে উড়ে না । ম্যানুয়ালটি আরও একবার:ON CONFLICT DO UPDATE
কারণ ON CONFLICT DO NOTHING
, এটি একটি সংঘাত_মার্কেট নির্দিষ্ট করার জন্য isচ্ছিক; বাদ দেওয়া হলে, সমস্ত ব্যবহারযোগ্য বাধার (এবং অনন্য সূচক) এর সাথে দ্বন্দ্বগুলি পরিচালনা করা হয়। জন্য ON CONFLICT DO UPDATE
, একটি দ্বন্দ্ব_দ্বারা প্রদান করা আবশ্যক ।
count = CASE WHEN EXCLUDED.count IS NULL THEN tu.count ELSE COALESCE(tu.count, 0) + COALESCE(EXCLUDED.count, 0) END
সরলীকৃত করা যেতে পারেcount = COALESCE(tu.count+EXCLUDED.count, EXCLUDED.count, tu.count)