PostgreSQL'de son kimliği tabloya nasıl ekleyebilirim?
MS SQL'de SCOPE_IDENTITY () vardır.
Lütfen böyle bir şey kullanmamı tavsiye etmeyin:
select max(id) from table
PostgreSQL'de son kimliği tabloya nasıl ekleyebilirim?
MS SQL'de SCOPE_IDENTITY () vardır.
Lütfen böyle bir şey kullanmamı tavsiye etmeyin:
select max(id) from table
Yanıtlar:
( tl;dr
: seçenek 3'e dön: RETURNING ile ekle)
Postgresql'de tablolar için "id" kavramı bulunmadığını hatırlayın, sadece sekanslar (bunlar tipik ancak zorunlu birincil anahtarlar için SERIAL sözde türüyle varsayılan değerler olarak kullanılmaz ).
Yeni eklenen bir satırın kimliğini almakla ilgileniyorsanız, birkaç yol vardır:
1. Seçenek: CURRVAL(<sequence name>);
.
Örneğin:
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
SELECT currval('persons_id_seq');
Dizinin adı bilinmelidir, gerçekten keyfi; bu örnekte, tablonun sözde türle oluşturulmuş persons
bir id
sütunu olduğunu varsayıyoruz SERIAL
. Buna güvenmekten kaçınmak ve daha temiz hissetmek için bunun yerine şunları kullanabilirsiniz pg_get_serial_sequence
:
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
SELECT currval(pg_get_serial_sequence('persons','id'));
Uyarı: currval()
yalnızca aynı oturumdaINSERT
(yürütülmüş nextval()
) sonra çalışır .
Seçenek 2: LASTVAL();
Bu öncekine benzer, sadece dizi adını belirtmenize gerek yoktur: en son değiştirilen diziyi arar (her zaman oturumunuzun içinde, yukarıdakiyle aynı uyarı).
Her ikisi de CURRVAL
ve LASTVAL
tamamen eşzamanlı güvenlidir. PG'deki dizinin davranışı, farklı oturumun müdahale etmeyeceği şekilde tasarlanmıştır, bu nedenle yarış koşulları riski yoktur (başka bir oturum INSERT ile SELECT'im arasına başka bir satır eklerse, yine de doğru değerimi alırım).
Ancak ince bir potansiyel problemleri var. Veritabanının, tabloya eklenirken, diğer tablolara bazı ek eklemeler yapan bazı TRIGGER (veya KURAL) varsa persons
... LASTVAL
muhtemelen bize yanlış değer verecektir. CURRVAL
Ek persons
tablolar aynı tabloya yapıldıysa bile sorun ortaya çıkabilir (bu çok daha az olağandır, ancak risk hala mevcuttur).
Seçenek 3: INSERT
ileRETURNING
INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John') RETURNING id;
Bu, kimliği almanın en temiz, verimli ve güvenli yoludur. Bir öncekinin riskleri yok.
Dezavantajları? Neredeyse hiçbiri: INSERT ifadenizi arama şeklinizi değiştirmeniz gerekebilir (en kötü durumda, belki de API veya DB katmanınız bir INSERT'in bir değer döndürmesini beklemez); standart SQL değil (kimin umurunda); Postgresql 8.2'den beri mevcut (Aralık 2006 ...)
Sonuç: Yapabiliyorsanız, seçenek 3'e gidin. Başka bir yerde, 1'i tercih edin.
Not: Son eklenen kimliği global olarak almayı düşünüyorsanız (oturumunuz tarafından zorunlu değildir) tüm bu yöntemler işe yaramaz . Bunun için başvurmalısınız SELECT max(id) FROM table
(elbette, bu diğer işlemlerden taahhüt edilmemiş kesici uçları okumaz).
Buna karşılık, ifadeniz tarafından yeni oluşturulan kimliği elde etmek için yukarıdaki 3 seçenekten biri yerine asla kullanmamalısınız , çünkü (performans dışında) bu aynı anda güvenli değildir: sizin ve başka bir oturumunuz arasında başka bir kayıt eklenmiş olabilir.SELECT max(id) FROM table
INSERT
INSERT
SELECT
SELECT max(id)
maalesef satırları silmeye başlar başlamaz işi yapmaz.
1,2,3,4,5
olan satırlarınız varsa ve 4 ve 5 satırlarını silerseniz, son eklenen kimlik hala max()
RETURNING id;
başka bir tabloya eklemek için nasıl kullanılacağına dair bir örnek memnuniyetle karşılanacaktır!
RETURNING id
beslenen bir SQL komut dosyasında nasıl kullanabilirim psql
?
INSERT deyiminin RETURNING yantümcesine bakın . Temel olarak, INSERT bir sorgu olarak iki katına çıkar ve size eklenen değeri geri verir.
insert into names (firstname, lastname) values ('john', 'smith') returning id;
o zaman select id from names where id=$lastid
doğrudan doğrudan koştuğunuz gibi id çıktısı verir. Eğer isterseniz aa değişkeninin içine dönüşünü kaydetmek , daha sonra insert into names (firstname, lastname) values ('john', 'smith') returning id into other_variable;
dönen içeren deyim ise bir fonksiyonu son açıklamada , daha sonra kimliği olma returning
'ed bir bütün olarak işlev tarafından döndürülür.
aşağıdaki gibi INSERT deyiminde RETURNING deyimini kullanabilirsiniz
wgzhao=# create table foo(id int,name text);
CREATE TABLE
wgzhao=# insert into foo values(1,'wgzhao') returning id;
id
----
1
(1 row)
INSERT 0 1
wgzhao=# insert into foo values(3,'wgzhao') returning id;
id
----
3
(1 row)
INSERT 0 1
wgzhao=# create table bar(id serial,name text);
CREATE TABLE
wgzhao=# insert into bar(name) values('wgzhao') returning id;
id
----
1
(1 row)
INSERT 0 1
wgzhao=# insert into bar(name) values('wgzhao') returning id;
id
----
2
(1 row)
INSERT 0
Leonbloy'un cevabı oldukça eksiksiz. Ben sadece bir OPTION 3 tam olarak uymuyor bir PL / pgSQL fonksiyonu içinden son eklenen değeri almak için gereken özel bir durum eklemek istiyorum.
Örneğin, aşağıdaki tablolarımız varsa:
CREATE TABLE person(
id serial,
lastname character varying (50),
firstname character varying (50),
CONSTRAINT person_pk PRIMARY KEY (id)
);
CREATE TABLE client (
id integer,
CONSTRAINT client_pk PRIMARY KEY (id),
CONSTRAINT fk_client_person FOREIGN KEY (id)
REFERENCES person (id) MATCH SIMPLE
);
Bir müşteri kaydı eklememiz gerekirse, bir kişi kaydına başvurmalıyız. Ancak diyelim ki istemciye yeni bir kayıt ekleyen ama aynı zamanda yeni kişi kaydını ekleyen bir PL / pgSQL fonksiyonu tasarlamak istiyoruz. Bunun için leonbloy'un SEÇENEK 3'ün küçük bir varyasyonunu kullanmalıyız:
INSERT INTO person(lastname, firstname)
VALUES (lastn, firstn)
RETURNING id INTO [new_variable];
İki INTO yan tümcesi olduğunu unutmayın. Bu nedenle, PL / pgSQL işlevi şöyle tanımlanır:
CREATE OR REPLACE FUNCTION new_client(lastn character varying, firstn character varying)
RETURNS integer AS
$BODY$
DECLARE
v_id integer;
BEGIN
-- Inserts the new person record and retrieves the last inserted id
INSERT INTO person(lastname, firstname)
VALUES (lastn, firstn)
RETURNING id INTO v_id;
-- Inserts the new client and references the inserted person
INSERT INTO client(id) VALUES (v_id);
-- Return the new id so we can use it in a select clause or return the new id into the user application
RETURN v_id;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
Şimdi yeni verileri aşağıdakileri kullanarak ekleyebiliriz:
SELECT new_client('Smith', 'John');
veya
SELECT * FROM new_client('Smith', 'John');
Ve yeni oluşturulan kimliği alıyoruz.
new_client
integer
----------
1
Aşağıdaki örneğe bakın
CREATE TABLE users (
-- make the "id" column a primary key; this also creates
-- a UNIQUE constraint and a b+-tree index on the column
id SERIAL PRIMARY KEY,
name TEXT,
age INT4
);
INSERT INTO users (name, age) VALUES ('Mozart', 20);
Son eklenen kimliği almak için bunu tablo "kullanıcı" seq sütun adı "id" için kullanın
SELECT currval(pg_get_serial_sequence('users', 'id'));
SELECT CURRVAL(pg_get_serial_sequence('my_tbl_name','id_col_name'))
Tabii ki tablo adını ve sütun adını sağlamanız gerekir.
Bu, geçerli oturum / bağlantı için http://www.postgresql.org/docs/8.3/static/functions-sequence.html
Bunu dene:
select nextval('my_seq_name'); // Returns next value
Bu 1 döndürürse (veya diziniz için başlangıç_sayısı ne olursa olsun), yanlış bayrağı ileterek diziyi orijinal değerine sıfırlayın:
select setval('my_seq_name', 1, false);
Aksi takdirde,
select setval('my_seq_name', nextValue - 1, true);
Bu işlem dizi değerini orijinal durumuna geri yükler ve "setval" aradığınız dizi değeriyle geri döner.
Postgres, aynı sorguda kimliği veya sorgunun geri dönmesini istediğiniz her şeyi döndüren dahili bir mekanizmaya sahiptir. işte bir örnek. Sütun1 ve sütun2 içeren 2 tablonuzun oluşturulduğunu ve sütun1'in her eklemeden sonra döndürülmesini istediğinizi düşünün.
# create table users_table(id serial not null primary key, name character varying);
CREATE TABLE
#insert into users_table(name) VALUES ('Jon Snow') RETURNING id;
id
----
1
(1 row)
# insert into users_table(name) VALUES ('Arya Stark') RETURNING id;
id
----
2
(1 row)
Java ve Postgres ile bu sorunu yaşadım. Yeni bir Connector-J sürümünü güncelleyerek düzelttim.
postgresql-9.2-1002.jdbc4.jar
https://jdbc.postgresql.org/download.html : Sürüm 42.2.12