Çakışan satırın kimliğini nasıl yükseltebilirim?


18

tag2 sütunlu bir tablo var : id(uuid) ve name(metin). Şimdi tabloya yeni bir etiket eklemek istiyorum, ancak etiket zaten varsa, sadece idvarolan kaydı almak istiyorum .

Ben sadece kullanabilirsiniz varsayılır ON CONFLICT DO NOTHINGbirlikte RETURNING "id":

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

Ancak, "foo" adındaki etiket zaten varsa, bu boş bir sonuç kümesi döndürür.

Sonra noop DO UPDATEyan tümcesi kullanmak için sorguyu değiştirdim :

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

Bu, amaçlandığı gibi çalışır, ancak biraz kafa karıştırıcıdır, çünkü adı zaten mevcut değere ayarlıyorum.

Bu sorunu çözmenin yolu mu yoksa eksik olduğum daha basit bir yaklaşım var mı?


denedin returning excluded.idmi
a_horse_with_no_name

@a_horse_with_no_name Bu sadece beni ERROR: missing FROM-clause entry for table "excluded"kullanırken verir DO NOTHING.
Der Hochstapler

Yanıtlar:


8

Eklenecek değerlerin tümü yeniyse veya zaten tabloda veya bir karışımdaysa, bu, (test ettiğim kadarıyla) 3 durumda da çalışır:

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 ;

Muhtemelen yeni ON CONFLICTsözdizimini kullanmadan bunu yapmanın başka yolları da vardır .


4

Bunun nasıl performans göstereceği konusunda bir fikriniz yok ama denemek için başka bir seçenek olarak, burada aynı eski okul yolunu yapıyor (olmadan 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)
;

Yani, yalnızca tagtabloda bulunmayan [benzersiz] adları girin ve kimlikleri döndürün; bunu tagnihai çıktı için var olan adların kimlikleriyle birleştirin . Ayrıca ypercubeᵀᴹ tarafından önerildiğiname gibi çıktıya da atayabilirsiniz , böylece hangi kimliğin hangi adla eşleştiğini bilirsiniz.


1
Evet. SELECT .. FROM ins UNION ALL SELECT ... FROM val JOIN tag ... ;
Kodumun
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.