INSERT… RETURNING'in dönüş değerini başka bir INSERT'te kullanabilir miyim?


87

Böyle bir şey mümkün mü?

INSERT INTO Table2 (val)
VALUES ((INSERT INTO Table1 (name) VALUES ('a_title') RETURNING id));

birinci tabloya bir başvuru ile ikinci bir tabloya bir satır eklemek için dönüş değerini değer olarak kullanmak gibi?

Yanıtlar:


106

Postgres 9.1'den başlayarak bunu yapabilirsiniz:

with rows as (
INSERT INTO Table1 (name) VALUES ('a_title') RETURNING id
)
INSERT INTO Table2 (val)
SELECT id
FROM rows

Bu arada, sadece id ile ilgileniyorsanız, bunu bir tetikleyici ile yapabilirsiniz:

create function t1_ins_into_t2()
  returns trigger
as $$
begin
  insert into table2 (val) values (new.id);
  return new;
end;
$$ language plpgsql;

create trigger t1_ins_into_t2
  after insert on table1
for each row
execute procedure t1_ins_into_t2();

1
Dönen kimliğin yanına değerler nasıl eklenir? örneğin: INSERT INTO TABLE2 (val1, val2, val3) (1, 2, satırlardan ID SEÇ)
Mahmoud Hanafy

@MahmoudHanafy: değiştirirken rowsile (some_query returning ...)günümüzde kudreti çalışması (denemedim).
Denis de Bernardy

2
@MahmoudHanafy: Dönen kimliğin yanına değerler eklemek için aşağıdaki gibi bir şey yapabilirsiniz: INSERT INTO TABLE2 (val1, val2, val3) SELECT id, 1, 2 FROM rows
Bhindi

oy verildi! Bu atomik anlam, eğer birinci ekleme başarılı olursa ve ikincisi olmazsa o zaman ne olur?
PirateApp

2
@PirateApp Yeni test edildi! v12.4. İlk INSERT, ikincisi başarısız olursa gerçekten geri alınır, ancak ilk
INSERT'in


13

Denis de Bernardy'nin verdiği cevap doğrultusunda ..

İd'nin daha sonra da döndürülmesini istiyorsanız ve Tablo2'ye daha fazla şey eklemek istiyorsanız:

with rows as (
INSERT INTO Table1 (name) VALUES ('a_title') RETURNING id
)
INSERT INTO Table2 (val, val2, val3)
SELECT id, 'val2value', 'val3value'
FROM rows
RETURNING val

10
DO $$
DECLARE tableId integer;
BEGIN
  INSERT INTO Table1 (name) VALUES ('a_title') RETURNING id INTO tableId;
  INSERT INTO Table2 (val) VALUES (tableId);
END $$;

Psql (10.3, sunucu 9.6.8) ile test edildi


8

Şu lastval()işlevi kullanabilirsiniz :

nextvalHerhangi bir dizi için en son elde edilen dönüş değeri

Yani bunun gibi bir şey:

INSERT INTO Table1 (name) VALUES ('a_title');
INSERT INTO Table2 (val)  VALUES (lastval());

nextval()INSERT'leriniz arasında kimse başka herhangi bir sekansı (mevcut oturumda) aramadığı sürece bu iyi çalışacaktır.

As Denis aşağıda belirtildiği ve ben kullanarak yaklaşık yukarıda uyardı lastval()başka dizi ile erişebilecekleri ise sorun içine alabilirsiniz nextval()senin ınsert'ler arasında. Bu , bir dizide Table1manuel olarak çağrılan bir INSERT tetikleyicisi varsa nextval()veya daha büyük olasılıkla, bir SERIALveyaBIGSERIAL birincil anahtarı olan bir tablo üzerinde bir INSERT yaptıysa olabilir . Eğer gerçekten paranoyak olmak istiyorsanız (iyi bir şey, onlar o zaman kullanabilirsiniz, gerçekten sonuçta seni almak için vardır) currval()ancak ilgili dizisinin ismini öğrenmek gerekir:

INSERT INTO Table1 (name) VALUES ('a_title');
INSERT INTO Table2 (val)  VALUES (currval('Table1_id_seq'::regclass));

Otomatik olarak oluşturulan sıra genellikle tablo adı t_c_seqnerede tve csütun adı olarak adlandırılır, ancak her zaman girip şunu psqlsöyleyerek öğrenebilirsiniz :

=> \d table_name;

ve sonra söz konusu sütun için varsayılan değere bakın, örneğin:

id | integer | not null default nextval('people_id_seq'::regclass)

Bilginize: lastval()aşağı yukarı MySQL'in PostgreSQL sürümüdür LAST_INSERT_ID. Bunu sadece söylüyorum çünkü pek çok insan MySQL'e PostgreSQL'den daha aşinadır, bu yüzden lastval()tanıdık bir şeyle bağlantı kurmak bazı şeyleri açıklığa kavuşturabilir.


2
Tablo1'deki bir tetikleyicinin sonraki eklemeler yapması durumunda currval () daha iyi kullanılır.
Denis de Bernardy

@Denis: Doğru, ama o zaman dizinin adına ihtiyacın var. Sadece tüm temelleri kapsayacak şekilde bu etkiye küçük bir güncelleme ekleyeceğim.
mu çok kısa

LASTVAL () ve CURRVAL (), diğer bağlantılar için değil, mevcut veritabanı bağlantısı için çalışır. Diğer kullanıcılar sıralamayı aynı anda güncelleyebilir, bu, sonuçlarınızı değiştirmez. Başkaları için endişelenmeyin, LASTVAL ve / CURRVAL için sonuçlarınızı asla değiştirmezler. TRANSACTION olmadan bir bağlantı havuzu kullanırken LASTVAL ve CURRVAL hiç kullanılamaz, işte o zaman işler ters gider: Veritabanı bağlantısını kontrol etmezsiniz.
Frank Heikens

1
@Frank: Evet, hepsi oturuma özgüdür ancak sorun lastvalşu ki , Table1'deki bir AFTER INSERT tetikleyicisinden arkanızda sıraya dayalı bir INSERT olabilir. Bu, mevcut seansta olacak ve muhtemelen lastval()beklemediğinizde değişecektir .
mu çok kısa

1

table_ex

id varsayılan nextval ('table_id_seq' :: regclass),

camp1 varchar

camp2 varchar

INSERT INTO table_ex(camp1,camp2) VALUES ('xxx','123') RETURNING id 
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.