अपटाउन में परस्पर विरोधी पंक्ति की आईडी कैसे प्राप्त करें?


18

मेरे पास tag2 कॉलम के साथ एक तालिका है : id(uuid) और name(पाठ)। मैं अब तालिका में एक नया टैग सम्मिलित करना चाहता हूं, लेकिन यदि टैग पहले से मौजूद है, तो मैं केवल idमौजूदा रिकॉर्ड प्राप्त करना चाहता हूं ।

मैंने मान लिया कि मैं इसके ON CONFLICT DO NOTHINGसाथ संयोजन में उपयोग कर सकता हूं RETURNING "id":

INSERT INTO
    "tag" ("name")
VALUES( 'foo' )
ON CONFLICT DO NOTHING
RETURNING "id";

लेकिन यह एक खाली परिणाम सेट देता है, यदि "फू" नाम वाला टैग पहले से मौजूद है।

मैंने तब नॉच DO UPDATEक्लॉज़ का उपयोग करने के लिए क्वेरी को बदल दिया :

INSERT INTO
    "tag" ("name")
VALUES( 'foo' )
ON CONFLICT ("name") DO UPDATE SET "name" = 'foo'
RETURNING "id";

यह इरादा के अनुसार काम करता है, लेकिन यह कुछ हद तक भ्रामक है, क्योंकि मैं सिर्फ पहले से मौजूद मूल्य के लिए नाम सेट कर रहा हूं।

क्या यह इस समस्या के बारे में जाने का तरीका है या क्या मुझे याद आ रहा है?


क्या आपने कोशिश की returning excluded.id?
a_horse_with_no_name

@a_horse_with_no_name यह सिर्फ मुझे ERROR: missing FROM-clause entry for table "excluded"उपयोग करते समय देता है DO NOTHING
डेर होकस्टापलर

1
यह भी देखें stackoverflow.com/a/42217872/1411457
harmic

जवाबों:


8

यह काम करेगा (जहाँ तक मैंने परीक्षण किया है) सभी 3 मामलों में, यदि सम्मिलित किए जाने वाले मान सभी नए हैं या पहले से ही तालिका या मिश्रण में हैं:

WITH
  val (name) AS
    ( VALUES                          -- rows to be inserted
        ('foo'),
        ('bar'),
        ('zzz')
    ),
  ins AS
    ( INSERT INTO
        tag (name)
      SELECT name FROM val
      ON CONFLICT (name) DO NOTHING
      RETURNING id, name              -- only the inserted ones
    )
SELECT COALESCE(ins.id, tag.id) AS id, 
       val.name
FROM val
  LEFT JOIN ins ON ins.name = val.name
  LEFT JOIN tag ON tag.name = val.name ;

ऐसा करने के लिए शायद कुछ अन्य तरीके हैं, शायद नए ON CONFLICTसिंटैक्स का उपयोग किए बिना ।


4

कोई विचार नहीं है कि यह कैसे प्रदर्शन करेगा, लेकिन कोशिश करने के लिए एक और विकल्प के रूप में, यहाँ एक ही पुराने तरीके से (बिना ON CONFLICT) स्कूल कर रहा है :

WITH items (name) AS (VALUES ('foo'), ('bar'), ('zzz')),
     added        AS
      (
        INSERT INTO tag (name)

        SELECT name FROM items
        EXCEPT
        SELECT name FROM tag

        RETURNING id
      )
SELECT id FROM added

UNION ALL

SELECT id FROM tag
WHERE name IN (SELECT name FROM items)
;

यही है, केवल [अनन्य] नाम tagतालिका में नहीं मिले और आईडी लौटाएं; tagअंतिम आउटपुट के लिए, उन नामों की आईडी के साथ, जो मौजूद हैं , को मिलाएं। आप nameआउटपुट में भी फेंक सकते हैं , जैसा कि ypercube so द्वारा सुझाया गया है , ताकि आप जान सकें कि कौन सा आईडी किस नाम से मेल खाता है।


1
हाँ। मेरे कोड का अंतिम चयन के रूप में भी लिखा जा सकता हैSELECT .. FROM ins UNION ALL SELECT ... FROM val JOIN tag ... ;
ypercube
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.