পোস্টগ্রিএসকিউএল-এ অন কনফ্লিক্ট দিয়ে কীভাবে রিটার্নিং ব্যবহার করবেন?


149

পোস্টগ্রিজ এসকিউএল 9.5 এ আমার নিম্নলিখিত ইউপিএসআরটি রয়েছে:

INSERT INTO chats ("user", "contact", "name") 
           VALUES ($1, $2, $3), 
                  ($2, $1, NULL) 
ON CONFLICT("user", "contact") DO NOTHING
RETURNING id;

যদি কোনও দ্বন্দ্ব না থাকে তবে এটি এমন কিছু ফিরে আসে:

----------
    | id |
----------
  1 | 50 |
----------
  2 | 51 |
----------

তবে যদি দ্বন্দ্ব থাকে তবে এটি কোনও সারি ফেরায় না:

----------
    | id |
----------

idযদি কোনও বিবাদ না হয় বা idবিবাদী কলামগুলির বিদ্যমান কলামগুলি ফেরত দিতে আমি নতুন কলামগুলি ফিরিয়ে দিতে চাই ।
এই কাজ করা যাবে? তা হলে কীভাবে?


1
ON CONFLICT UPDATEসারিটিতে পরিবর্তন রয়েছে তাই ব্যবহার করুন । তারপরে RETURNINGএটি ক্যাপচার করবে।
গর্ডন লিনফ

1
@ গর্ডনলিনফ আপডেট করার মতো কিছু নেই?
ওক্কু

1
যদি আপডেট করার মতো কিছু না থাকে তবে এর অর্থ হ'ল কোনও বিরোধ নেই তাই এটি কেবল নতুন মান সন্নিবেশ করায় এবং তাদের আইডি ফিরিয়ে দেয়
জিলা

1
আপনি এখানে অন্যান্য উপায় খুঁজে পাবেন । পারফরম্যান্সের দিক দিয়ে যদিও আমি দুজনের মধ্যে পার্থক্য জানতে চাই love
Stanislasdrg পুনরায় ইনস্টল করুন মনিকা

উত্তর:


88

আমার ঠিক একই সমস্যা ছিল এবং আমি আপডেট করার মতো কিছুই না থাকা সত্ত্বেও, 'কিছুই না' এর পরিবর্তে 'ডু আপডেট' ব্যবহার করে এটি সমাধান করেছি। আপনার ক্ষেত্রে এটি এমন কিছু হবে:

INSERT INTO chats ("user", "contact", "name") 
       VALUES ($1, $2, $3), 
              ($2, $1, NULL) 
ON CONFLICT("user", "contact") DO UPDATE SET name=EXCLUDED.name RETURNING id;

এই সন্ধানটি সমস্ত সারি ফিরিয়ে দেবে, তা সবেমাত্র inোকানো হয়েছে বা সেগুলি আগে বিদ্যমান ছিল।


11
এই পদ্ধতির সাথে একটি সমস্যা হ'ল, প্রাথমিক কী এর সিকোয়েন্স নম্বরটি প্রতিটি সংঘাতের উপর বাড়ানো হয় (বোগাস আপডেট), যার মূলত অর্থ এই যে আপনি ক্রমটির বিশাল ফাঁক দিয়ে শেষ করতে পারেন। কোন ধারণা কীভাবে এড়ানো যায়?
মিশা

9
@ মিশা: তাহলে কি? সিকোয়েন্সগুলি কখনই প্রথম স্থানে ফাঁকবিহীন হওয়ার গ্যারান্টিযুক্ত হয় না এবং ফাঁকগুলি কোনও ব্যাপার হয় না (এবং যদি তা করে তবে একটি ক্রমটি করা ভুল জিনিস)
a_horse_with_no_name

24
আমি বেশিরভাগ ক্ষেত্রে এটি ব্যবহার করার পরামর্শ দেব না । আমি একটি উত্তর যুক্ত করেছি কেন।
এরউইন ব্র্যান্ডসেটেটার

4
এই উত্তরটি DO NOTHINGমূল প্রশ্নের দিকটি অর্জন করে না বলে মনে হয় - আমার কাছে মনে হয় এটি সমস্ত সারিটির জন্য অ-বিরোধী ক্ষেত্রটি (এখানে "নাম") আপডেট করে।
পিটারজেসিএলও

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

202

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

অন্যান্য সমস্ত ক্ষেত্রে, প্রয়োজন ছাড়া অভিন্ন সারি আপডেট করবেন না । এমনকি যদি আপনি পৃষ্ঠে কোনও পার্থক্য না দেখেন তবে বিভিন্ন পার্শ্ব প্রতিক্রিয়া রয়েছে :

  • এটি সম্ভবত ট্রিগারগুলিকে গুলি চালাতে পারে যা গুলি করা উচিত নয়।

  • এটি "নির্দোষ" সারিগুলি লিখতে লক করে, সম্ভবত সমবর্তী লেনদেনের জন্য ব্যয় বহন করে।

  • এটি সারিটি নতুন বলে মনে হতে পারে যদিও এটি পুরানো (লেনদেনের টাইমস্ট্যাম্প)।

  • সর্বাধিক গুরুত্বপূর্ণ , পোস্টগ্রিসএসকিউএল এর এমভিসিসি মডেলের সাথে প্রত্যেকের জন্য একটি নতুন সারি সংস্করণ লেখা হয় UPDATE, সারিটির ডেটা পরিবর্তিত হয় কিনা তা বিবেচনা করেই। এটি ইউপিএসইআরটি নিজেই, টেবিল ব্লাট, সূচক ফোটা, টেবিলে পরবর্তী ক্রিয়াকলাপের জন্য পারফরম্যান্স পেনাল্টি, VACUUMব্যয়ের ব্যয় করে। কয়েকটি অনুলিপিগুলির জন্য একটি সামান্য প্রভাব, তবে বেশিরভাগ ধরণের জন্য massive

এছাড়াও , কখনও কখনও এটি ব্যবহারিক বা এমনকি ব্যবহার করা সম্ভব হয় না ON CONFLICT DO UPDATEম্যানুয়াল:

জন্য ON CONFLICT DO UPDATE, একটি সরবরাহ করা conflict_targetআবশ্যক।

একাধিক সূচক / সীমাবদ্ধতা জড়িত থাকলে একটি একক "দ্বন্দ্ব লক্ষ্য" সম্ভব নয়।

খালি আপডেট এবং পার্শ্ব প্রতিক্রিয়া ছাড়াই আপনি প্রায় (প্রায়) একইটি অর্জন করতে পারেন। উত্থিত হতে পারে এমন সমস্ত সম্ভাব্য দ্বন্দ্বগুলি ON CONFLICT DO NOTHINGধরার জন্য নীচের কয়েকটি সমাধান ("কোনও বিরোধের লক্ষ্য নয়") নিয়েও কাজ করে - যা কাঙ্ক্ষিত বা নাও হতে পারে।

একযোগে লেখার বোঝা ছাড়াই

WITH input_rows(usr, contact, name) AS (
   VALUES
      (text 'foo1', text 'bar1', text 'bob1')  -- type casts in first row
    , ('foo2', 'bar2', 'bob2')
    -- more?
   )
, ins AS (
   INSERT INTO chats (usr, contact, name) 
   SELECT * FROM input_rows
   ON CONFLICT (usr, contact) DO NOTHING
   RETURNING id  --, usr, contact              -- return more columns?
   )
SELECT 'i' AS source                           -- 'i' for 'inserted'
     , id  --, usr, contact                    -- return more columns?
FROM   ins
UNION  ALL
SELECT 's' AS source                           -- 's' for 'selected'
     , c.id  --, usr, contact                  -- return more columns?
FROM   input_rows
JOIN   chats c USING (usr, contact);           -- columns of unique index

sourceকলাম প্রদর্শন করতে কিভাবে এই কাজ করে একটি ঐচ্ছিক ছাড়াও। উভয়ের ক্ষেত্রে পার্থক্য বলতে খালি আপনার প্রয়োজন হতে পারে (খালি লেখার ক্ষেত্রে আরও একটি সুবিধা)।

চূড়ান্ত JOIN chatsকাজ করে কারণ সংযুক্ত ডেটা-সংশোধনকারী সিটিই থেকে সদ্য সন্নিবেশ করা সারিগুলি অন্তর্নিহিত সারণীতে এখনও দৃশ্যমান নয়। (একই এসকিউএল স্টেটমেন্টের সমস্ত অংশ অন্তর্নিহিত সারণীর একই স্ন্যাপশট দেখতে পাবে))

যেহেতু VALUESএক্সপ্রেশনটি মুক্ত-স্থিত (সরাসরি কোনও সংযুক্ত নয় INSERT) পোস্টগ্রাগেস লক্ষ্য কলামগুলি থেকে ডেটা ধরণের সংগ্রহ করতে পারে না এবং আপনাকে স্পষ্টত ধরণের ক্যাসেট যুক্ত করতে হতে পারে। ম্যানুয়াল:

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

নিজেই ক্যোয়ারী (পার্শ্ব প্রতিক্রিয়াগুলি গণনা করছে না) সিটিইর ওভারহেডের কারণে এবং অতিরিক্ত (যা নিখুঁত সূচকটি সংজ্ঞা অনুসারে রয়েছে সেহেতু সস্তা হওয়া উচিত) - এর ফলে কয়েকটি দ্বিপের জন্য কিছুটা ব্যয়বহুল হতে পারে SELECT- এর সাথে একটি অনন্য বাধা কার্যকর করা হয়েছে একটি সূচক)।

অনেক অনুলিপি জন্য দ্রুত হতে পারে (অনেক) । অতিরিক্ত লেখার কার্যকর ব্যয় অনেকগুলি বিষয়ের উপর নির্ভর করে।

তবে কোনও ক্ষেত্রে পার্শ্ব প্রতিক্রিয়া এবং লুকানো ব্যয় কম রয়েছে । এটি সম্ভবত সামগ্রিকভাবে সস্তা।

সংযুক্তি ক্রমগুলি এখনও উন্নত, যেহেতু দ্বন্দ্বগুলির পরীক্ষার আগে ডিফল্ট মান পূরণ করা হয় ।

সিটিই সম্পর্কে:

একযোগে লেখার বোঝা সহ

ডিফল্ট READ COMMITTEDলেনদেনের বিচ্ছিন্নতা ধরে নেওয়া । সম্পর্কিত:

বর্ণের অবস্থার বিরুদ্ধে রক্ষা করার সর্বোত্তম কৌশল নির্ভর করে সঠিক প্রয়োজনীয়তা, সারণীতে এবং ইউপিএসআরটিগুলিতে সারিগুলির সংখ্যা এবং আকার, একত্রে লেনদেনের সংখ্যা, দ্বন্দ্বের সম্ভাবনা, উপলভ্য সংস্থান এবং অন্যান্য কারণগুলির উপর ...

সংহত ইস্যু 1

যদি আপনার একযোগে লেনদেন কোনও সারিটিতে লিখিত থাকে যা আপনার লেনদেন এখন ইউপিএসআরটি-তে চেষ্টা করে, আপনার লেনদেনের অপরটির সমাপ্তির জন্য অপেক্ষা করতে হবে।

যদি অন্য লেনদেনটি ROLLBACK(বা কোনও ত্রুটি, অর্থাৎ স্বয়ংক্রিয় ROLLBACK) দিয়ে শেষ হয় তবে আপনার লেনদেন স্বাভাবিকভাবে এগিয়ে যেতে পারে। সামান্য সম্ভাব্য পার্শ্ব প্রতিক্রিয়া: অনুক্রমিক সংখ্যার ফাঁক। তবে কোনও সারি নেই।

যদি অন্য লেনদেনটি স্বাভাবিকভাবে শেষ হয় (অন্তর্নিহিত বা স্পষ্টভাবে COMMIT), আপনি INSERTএকটি বিরোধ সনাক্ত করতে পারবেন ( UNIQUEসূচক / সীমাবদ্ধতা নিখুঁত) এবং DO NOTHINGসুতরাং সারিটিও ফিরে পাবেন না। (এছাড়াও নীচে সামঞ্জস্য ইস্যুতে প্রদর্শিত সারিটি 2 টি লক করতে পারে না , কারণ এটি দৃশ্যমান নয় )) SELECTকোয়েরির শুরু থেকে একই স্ন্যাপশটটি দেখায় এবং এখনও অদৃশ্য সারিটিও ফিরে আসতে পারে না।

ফলাফলের সেট থেকে এই জাতীয় কোনও সারি নিখোঁজ রয়েছে (যদিও তারা অন্তর্নিহিত টেবিলে বিদ্যমান রয়েছে)!

এটি যেমন ঠিক আছে তেমনও হতে পারে । বিশেষত যদি আপনি উদাহরণের মতো সারিগুলি না ফিরিয়ে থাকেন এবং সারিটি রয়েছে তা জেনে সন্তুষ্ট হন। যদি এটি যথেষ্ট ভাল না হয় তবে এর চারপাশে বিভিন্ন উপায় রয়েছে।

আপনি আউটপুটটির সারি গণনাটি পরীক্ষা করতে পারেন এবং বিবৃতিটি যদি ইনপুটটির সারি গণনার সাথে মেলে না তবে এটি পুনরাবৃত্তি করতে পারেন। বিরল ক্ষেত্রে যথেষ্ট হতে পারে। বিষয়টি হ'ল একটি নতুন ক্যোয়ারি শুরু করা (একই লেনদেনে হতে পারে), যা পরে সদ্য প্রতিশ্রুতিবদ্ধ সারিগুলি দেখতে পাবে।

অথবা ফলাফলের সারি অনুপস্থিত জন্য চেক মধ্যে একই প্রশ্নের সাথে এবং ওভাররাইট পাশব বল কৌতুক প্রদর্শিত যাদের Alextoni এর উত্তর

WITH input_rows(usr, contact, name) AS ( ... )  -- see above
, ins AS (
   INSERT INTO chats AS c (usr, contact, name) 
   SELECT * FROM input_rows
   ON     CONFLICT (usr, contact) DO NOTHING
   RETURNING id, usr, contact                   -- we need unique columns for later join
   )
, sel AS (
   SELECT 'i'::"char" AS source                 -- 'i' for 'inserted'
        , id, usr, contact
   FROM   ins
   UNION  ALL
   SELECT 's'::"char" AS source                 -- 's' for 'selected'
        , c.id, usr, contact
   FROM   input_rows
   JOIN   chats c USING (usr, contact)
   )
, ups AS (                                      -- RARE corner case
   INSERT INTO chats AS c (usr, contact, name)  -- another UPSERT, not just UPDATE
   SELECT i.*
   FROM   input_rows i
   LEFT   JOIN sel   s USING (usr, contact)     -- columns of unique index
   WHERE  s.usr IS NULL                         -- missing!
   ON     CONFLICT (usr, contact) DO UPDATE     -- we've asked nicely the 1st time ...
   SET    name = c.name                         -- ... this time we overwrite with old value
   -- SET name = EXCLUDED.name                  -- alternatively overwrite with *new* value
   RETURNING 'u'::"char" AS source              -- 'u' for updated
           , id  --, usr, contact               -- return more columns?
   )
SELECT source, id FROM sel
UNION  ALL
TABLE  ups;

এটি উপরের প্রশ্নের মতো, তবে আমরা সম্পূর্ণ ফলাফলের সেটটি upsফেরত দেওয়ার আগে, আমরা সিটিইর সাথে আরও একটি পদক্ষেপ যুক্ত করি । সেই শেষ সিটিই বেশিরভাগ সময় কিছুই করবে না। যদি ফিরে আসা ফলাফল থেকে সারিগুলি নিখোঁজ হয় তবে আমরা নিষ্ঠুর শক্তি ব্যবহার করি।

আরও ওভারহেড, এখনও। প্রাক-বিদ্যমান সারিগুলির সাথে যত বেশি দ্বন্দ্ব, তত সহজেই এটি সহজ পদ্ধতির তুলনায় কার্যকর হবে।

একটি পার্শ্ব প্রতিক্রিয়া: ২ য় ইউপিএসআরটি সারি সারি লিখে দেয়, সুতরাং একই সারিতে তিন বা ততোধিক লেনদেন ওভারল্যাপ করে লিখলে এটি ডেডলকের সম্ভাবনা পুনরায় পরিচয় করিয়ে দেয় (নীচে দেখুন) । যদি সমস্যা হয় তবে আপনার আলাদা সমাধান দরকার - যেমন উপরে বর্ণিত পুরো বক্তব্যটি পুনরাবৃত্তি করা।

সংক্ষিপ্ত বিবরণ 2

যদি সমবর্তী লেনদেনগুলি প্রভাবিত সারিগুলির জড়িত কলামগুলিতে লিখতে পারে এবং আপনাকে নিশ্চিত করতে হবে যে সারিগুলি আপনি খুঁজে পেয়েছেন একই লেনদেনের পরবর্তী পর্যায়ে এখনও রয়েছে, আপনি বিদ্যমান সারিগুলি সস্তাভাবে সিটিইতে লক করতে পারেন ins(যা অন্যথায় আনলক হয়ে যাবে) সঙ্গে:

...
ON CONFLICT (usr, contact) DO UPDATE
SET name = name WHERE FALSE  -- never executed, but still locks the row
...

এবং পাশাপাশি একটি লকিং ক্লজ যুক্ত করুনSELECTFOR UPDATE

এটি প্রতিযোগিতামূলক লেখার ক্রিয়াকলাপ লেনদেনের সমাপ্তি অবধি অপেক্ষা করে, যখন সমস্ত লক প্রকাশিত হয়। সুতরাং সংক্ষিপ্ত হতে।

আরও বিশদ এবং ব্যাখ্যা:

ডেডলক?

বিরুদ্ধে রক্ষার জন্য ডেডলক সারি সন্নিবেশ করার মাধ্যেমে সামঞ্জস্যপূর্ণ অর্ডার । দেখা:

ডেটা টাইপ এবং কাস্ট

ডেটা ধরণের টেমপ্লেট হিসাবে বিদ্যমান টেবিল ...

ফ্রি-স্ট্যান্ডিং VALUESএক্সপ্রেশনটিতে ডেটার প্রথম সারির জন্য সুস্পষ্ট প্রকারের কাস্টগুলি অসুবিধা হতে পারে। এর চারপাশে উপায় আছে। সারি টেম্পলেট হিসাবে আপনি যে কোনও বিদ্যমান সম্পর্ক (টেবিল, দেখুন, ...) ব্যবহার করতে পারেন। লক্ষ্য সারণি ব্যবহারের ক্ষেত্রে সুস্পষ্ট পছন্দ। ইনপুট তথ্য স্বয়ংক্রিয়ভাবে উপযুক্ত ধরনের করতে বাধ্য করা হয়, মত VALUESএকটি ধারা INSERT:

WITH input_rows AS (
  (SELECT usr, contact, name FROM chats LIMIT 0)  -- only copies column names and types
   UNION ALL
   VALUES
      ('foo1', 'bar1', 'bob1')  -- no type casts here
    , ('foo2', 'bar2', 'bob2')
   )
   ...

এটি কিছু ডেটা ধরণের জন্য কাজ করে না। দেখা:

... এবং নাম

এটি সমস্ত ডেটা ধরণের জন্যও কাজ করে ।

সারণীর সমস্ত (শীর্ষস্থানীয়) কলামগুলিতে প্রবেশ করার সময়, আপনি কলামের নাম বাদ দিতে পারেন। chatsউদাহরণে ধরে নেওয়া সারণীটি কেবল ইউপিএসআরটিতে ব্যবহৃত 3 টি কলামগুলি নিয়ে গঠিত:

WITH input_rows AS (
   SELECT * FROM (
      VALUES
      ((NULL::chats).*)         -- copies whole row definition
      ('foo1', 'bar1', 'bob1')  -- no type casts needed
    , ('foo2', 'bar2', 'bob2')
      ) sub
   OFFSET 1
   )
   ...

একপাশে: ব্যবহার করবেন না সংরক্ষিত শব্দ মত "user"শনাক্তকারী হিসেবে। এটি একটি বোঝা ফুটগান। আইনী, লোয়ার-কেস, অব্যর্থ সনাক্তকারী সনাক্ত করুন। আমি এটি দিয়ে প্রতিস্থাপন usr


2
আপনি বোঝাচ্ছেন যে এই পদ্ধতিটি সিরিয়ালগুলিতে ফাঁক তৈরি করবে না, তবে সেগুলি
হ'ল: অন্তর্ভুক্ত ... কনফ্লিক্টে

1
এটি এতটা গুরুত্বপূর্ণ তা নয়, তবে সিরিয়ালগুলি কেন বাড়ানো হয়? এবং এড়ানো কোন উপায় আছে?
স্পষ্টভাবে

1
@ অবতীর্ণ: যেমনটি আমি উপরে যুক্ত করেছি: সংঘাতের জন্য পরীক্ষার আগে কলামের ডিফল্ট মানগুলি পূরণ করা হয় এবং সমবর্তী লেখাগুলির সাথে দ্বন্দ্ব এড়াতে কখনই সিকোয়েন্সগুলি আবার ঘুরিয়ে দেওয়া হয় না।
এরউইন ব্র্যান্ডস্টেটার

7
অবিশ্বাস্য। মনোযোগের মতো কাজ করে এবং এটি একবার মনোযোগ দিয়ে দেখলে বোঝা সহজ Works আমি এখনও ইচ্ছুক ON CONFLICT SELECT...যেখানে যদিও :) একটা জিনিস
Roshambo

3
অবিশ্বাস্য। পোস্টগ্রিজের নির্মাতারা মনে হয় ব্যবহারকারীদের উপর নির্যাতন করছেন। স্রেফ কেবল রিটার্ন ক্লজটি সর্বদা মানগুলি ফিরিয়ে দেয় না কেন , সেখানে সন্নিবেশক রয়েছে কিনা তা নির্বিশেষে?
আনাতোলি আলেকসিভ

16

আপলোড করুন, INSERTক্যোয়ারির একটি এক্সটেনশন হওয়া সীমাবদ্ধতার বিরোধের ক্ষেত্রে দুটি পৃথক আচরণের সাথে সংজ্ঞায়িত করা যেতে পারে: DO NOTHINGবা DO UPDATE

INSERT INTO upsert_table VALUES (2, 6, 'upserted')
   ON CONFLICT DO NOTHING RETURNING *;

 id | sub_id | status
----+--------+--------
 (0 rows)

পাশাপাশি নোট করুন যা RETURNINGকিছুই দেয় না, কারণ কোনও টিপলস .োকানো হয়নি । এখন এর সাথে DO UPDATE, দ্বিধাদ্বন্দ্বের সাথে টিপলটিতে অপারেশন করা সম্ভব। প্রথম দ্রষ্টব্য যে একটি সীমাবদ্ধতা সংজ্ঞায়িত করা গুরুত্বপূর্ণ যা সংঘাত রয়েছে তা নির্ধারণ করতে ব্যবহৃত হবে।

INSERT INTO upsert_table VALUES (2, 2, 'inserted')
   ON CONFLICT ON CONSTRAINT upsert_table_sub_id_key
   DO UPDATE SET status = 'upserted' RETURNING *;

 id | sub_id |  status
----+--------+----------
  2 |      2 | upserted
(1 row)

2
আক্রান্ত সারির আইডিটি সর্বদা পাওয়ার জন্য দুর্দান্ত উপায় এবং এটি কোনও সন্নিবেশকৃত বা আপসেট ছিল কিনা তা জেনে রাখুন। ঠিক যেটা আমার দরকার ছিল.
মবি হাঁস

এটি এখনও "ডো আপডেট" ব্যবহার করছে যা অসুবিধাগুলি ইতিমধ্যে আলোচনা করা হয়েছে।
বিল ওয়ার্থিংটন

4

একটি আইটেম সন্নিবেশ জন্য, আইডি ফেরত যখন আমি সম্ভবত একটি coalesce ব্যবহার করতে হবে:

WITH new_chats AS (
    INSERT INTO chats ("user", "contact", "name")
    VALUES ($1, $2, $3)
    ON CONFLICT("user", "contact") DO NOTHING
    RETURNING id
) SELECT COALESCE(
    (SELECT id FROM new_chats),
    (SELECT id FROM chats WHERE user = $1 AND contact = $2)
);

2
WITH e AS(
    INSERT INTO chats ("user", "contact", "name") 
           VALUES ($1, $2, $3), 
                  ($2, $1, NULL) 
    ON CONFLICT("user", "contact") DO NOTHING
    RETURNING id
)
SELECT * FROM e
UNION
    SELECT id FROM chats WHERE user=$1, contact=$2;

ব্যবহারের প্রধান উদ্দেশ্য ON CONFLICT DO NOTHINGহ'ল ছোঁড়া ত্রুটি এড়ানো, তবে এটির কোনও সারি ফেরতের কারণ হবে না। সুতরাং SELECTবিদ্যমান আইডি পেতে আমাদের আরও একটি দরকার ।

এই এসকিউএল-এ, যদি এটি দ্বন্দ্বগুলিতে ব্যর্থ হয় তবে এটি কিছুই ফিরিয়ে দেবে না, তবে দ্বিতীয়টি SELECTবিদ্যমান সারিটি পাবে; যদি এটি সফলভাবে সন্নিবেশ করে, তবে দুটি একই রেকর্ড থাকবে, তারপরে আমাদের UNIONফলাফলটি মার্জ করতে হবে।


এই সমাধানটি ভালভাবে কাজ করে এবং ডিবিতে একটি অপ্রয়োজনীয় লিখন (আপডেট) করা এড়ানো যায় !! নিস!
সাইমন সি

0

আমি এরউইন ব্র্যান্ডস্টেটারের আশ্চর্যজনক উত্তরটি পরিবর্তন করেছি, যা ক্রমটি বাড়িয়ে তুলবে না এবং কোনও সারিও লিখবে না। আমি পোস্টগ্রেএসকিউএল-তে তুলনামূলকভাবে নতুন, সুতরাং আপনি যদি এই পদ্ধতিতে কোনও ত্রুটি দেখতে পান তবে নির্দ্বিধায় আমাকে জানান:

WITH input_rows(usr, contact, name) AS (
   VALUES
      (text 'foo1', text 'bar1', text 'bob1')  -- type casts in first row
    , ('foo2', 'bar2', 'bob2')
    -- more?
   )
, new_rows AS (
   SELECT 
     c.usr
     , c.contact
     , c.name
     , r.id IS NOT NULL as row_exists
   FROM input_rows AS r
   LEFT JOIN chats AS c ON r.usr=c.usr AND r.contact=c.contact
   )
INSERT INTO chats (usr, contact, name)
SELECT usr, contact, name
FROM new_rows
WHERE NOT row_exists
RETURNING id, usr, contact, name

এটি ধরে নিয়েছে যে chatsকলামগুলিতে সারণীর একটি অনন্য বাধা রয়েছে (usr, contact)

আপডেট: স্পার্টার (নীচে) থেকে প্রস্তাবিত সংশোধনগুলি যুক্ত করেছে । ধন্যবাদ!


1
পরিবর্তে CASE WHEN r.id IS NULL THEN FALSE ELSE TRUE END AS row_existsশুধু লিখুন r.id IS NOT NULL as row_exists। পরিবর্তে WHERE row_exists=FALSEশুধু লিখুন WHERE NOT row_exists
দফায় দফায়
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.