Son eklenen kimliği almak için PostgreSQL'deki currval () yöntemini nasıl kullanırım?


64

Bir masam var:

CREATE TABLE names (id serial, name varchar(20))

Eklemeden kullanmadan "son eklenen kimliği" bu tablodan istiyorum RETURNING id. Bir işlevi var gibi görünüyor CURRVAL(), ama nasıl kullanılacağını anlamıyorum.

Denedim:

SELECT CURRVAL() AS id FROM names_id_seq
SELECT CURRVAL('names_id_seq')
SELECT CURRVAL('names_id_seq'::regclass)

ama hiçbiri çalışmıyor. currval()En son eklenen kimliği almak için nasıl kullanabilirim ?


2
Bu problemin / çözümün okuyucuları, RETURNING cümlesinin ek sorgunun ek yükü olmadan ve WRONG VALUE’nin geri dönme olasılığı olmadan geri dönme olasılığı olmadan tanımlayıcıyı sağladığından, currval () kullanımının genellikle tavsiye edilmediğini bilmelidir. bazı kullanım durumları.)
değiştirici,

1
@ chander: Bu iddia için herhangi bir referansınız var mı? Kullanımı currval() kesinlikle kesinlikle önerilmez.
a_horse_with_no_name

Akıntı kullanımının cesaretini kırıp kırmadığı konusunda belki de bir meseledir, ancak bazı durumlarda kullanıcılar beklediğiniz gibi olmayan bir değer verebileceğinin farkında olmalıdır (bu nedenle İADE EDİLMESİ desteklendiğinde daha iyi bir seçimdir). a_seq dizisini kullanan tablo A ve ayrıca PK sütunu için a_seq (nextval'i çağırmak ('a_seq') da kullanan B tablosu vardır.) Ayrıca, tablo A'ya INSERT'den B tablosuna ekleyen bir tetikleyiciniz (a_trg) olduğunu varsayalım. bu durumda (tablo A ekleme sonra) currval () işlevi, tablo B, tablo A'da değil, geçme için oluşturulan sayı döndürür
avize

Yanıtlar:


51

serialPostgreSQL olarak bir sütun oluşturursanız, bunun için otomatik olarak bir sıralama oluşturur.

Dizinin adı otomatik olarak oluşturulur ve her zaman tablename_columnname_seq, sizin durumunuzda dizinin adı olur names_id_seq.

Tabloya ekledikten sonra, currval()bu sıra adı ile arayabilirsiniz :

postgres=> CREATE TABLE names in schema_name (id serial, name varchar(20));
CREATE TABLE
postgres=> insert into names (name) values ('Arthur Dent');
INSERT 0 1
postgres=> select currval('names_id_seq');
 currval
---------
       1
(1 row)
postgres=>

Sıra adını sabit kodlamak yerine, pg_get_serial_sequence()bunun yerine da kullanabilirsiniz :

select currval(pg_get_serial_sequence('names', 'id'));

Bu şekilde Postgres'in kullandığı adlandırma stratejisine güvenmenize gerek yok.

Veya sıra adını hiç kullanmak istemiyorsanız, lastval()


currval()Çok kullanıcılı bir kurulumda kullanmak iyi değil sanırım . Örneğin bir web sunucusunda.
Jonas

9
Hayır, yanılıyorsun. currval()geçerli bağlantınıza "yerel". Bu yüzden çok kullanıcılı bir ortamda kullanmakta hiçbir sorun yoktur. Dizinin bütün amacı bu.
a_horse_with_no_name

1
Bu, insertinizin aynı tabloda daha fazla kesici uç kullandığı (oldukça nadir) durumunda kırılabilir, değil mi?
Leonbloy

1
@ a_horse_with_no_name: Masada tanımlanan birden fazla kesici uç üzerinde (fark etmesi kolay) değil (belki de bilinmeyen) tetikleyiciler üzerinde düşünüyordum. Yukarıdakileri örnek olarak deneyin: gist.github.com/anonymous/9784814
leonbloy

1
Her zaman tablo ve sütun adı değil. Zaten bu isimde bir dizi varsa, sonunda bir sayıyı birleştirerek veya artırarak yeni bir dizi oluşturacaktır ve limiti aşıyorsa (62 karakter gibi gözüküyorsa) ismi kısaltması gerekebilir.
PhilHibbs

47

Bu doğrudan yığın taşmasından kaynaklanıyor

@ A_horse_with_no_name ve @Jack Douglas tarafından belirtildiği gibi currval, yalnızca geçerli oturumla çalışır. Dolayısıyla, sonucun başka bir oturumun taahhüt edilmemiş bir işleminden etkilenebileceği gerçeğinden memnunsanız ve hala oturumlar arasında çalışacak bir şey istiyorsanız, bunu kullanabilirsiniz:

SELECT last_value FROM your_sequence_name;

Daha fazla bilgi için SO bağlantısını kullanın.

Gönderen Postgres belgelerine rağmen, açıkça belirtilmektedir

Geçerli oturumda nextval henüz çağrılmadıysa, lastval çağırmak bir hatadır.

Bu yüzden seanslar arasındaki bir dizi için currval veya last_value işlevini doğru bir şekilde kullanmak için kesinlikle konuşmayı düşünüyorum, böyle bir şey yapmanız gerekir mi?

SELECT setval('serial_id_seq',nextval('serial_id_seq')-1);

Tabii ki, geçerli oturumda seri alanını kullanmanın bir eki veya başka bir yolu olmayacağını varsayarsak.


3
Bunun ne zaman faydalı olacağını bir türlü düşünemiyorum.
ypercubeᵀᴹ

Şu anki seansta nextval çağrılmadıysa, bunun geçerli olmasının bir yolu olup olmadığını merak ediyorum. Bir önerin var mı?
Slak

Bunu yapmak zorunda kaldım, oluşturulan fikstür verilerini elde etmek için birincil anahtarlar yazarken, normalde artan bir şekilde üretilecek olan PK değerlerinin müşteri testini kolaylaştırmak için vaktinden önce belirlenmesini istedim. Bunu yaparken ekleri desteklemek için normalde bir nextval()sizden gelen varsayılan değere göre yönetilen bir sütunda daha sonra diziyi elle kodlanmış ID'lerle eklediğiniz fikstür kayıt sayısına uyacak şekilde ayarlamanız gerekir. Ayrıca currval () / lastval () problemi için ön-hazırlık öncesi mevcut olmamanın çözülmesinin yolu da doğrudan sıraya koymaktır SELECT.
Peter M. Elias

@ ypercubeᵀᴹ Aksine, seçilen "doğru" cevabı kullanmak için iyi bir sebep olmadığını düşünebilirim. Bu cevap, tabloya kayıt eklenmesini gerektirmez. Bu, soruyu da cevaplıyor. Yine, bu cevabı seçilen cevap üzerinde kullanmamak için iyi bir sebep olmadığını düşünebilirim.
Henley Chiu

1
Bu cevap, tablonun hiç değiştirilmesini gerektirmez. Kontrol edilen yapar. İdeal olarak, HERHANGİ BİR değişiklik yapmadan sadece son kimliği bilmek istersiniz. Ya bu bir üretim DB ise? Mümkün perküsyon olmadan sadece rastgele bir satır ekleyemezsiniz. Bu nedenle bu cevap doğru olduğu kadar güvenlidir.
Henley Chiu

14

Daha önce bu oturumda bu sıra için aramanız gerekirnextvalcurrval :

create sequence serial;
select nextval('serial');
 nextval
---------
       1
(1 row)

select currval('serial');
 currval
---------
       1
(1 row)

bu nedenle insert, aynı oturumda yapılmadıkça 'son eklenen kimliği' diziden bulamazsınız (bir işlem geri alınabilir, ancak sıra değişmeyecektir).

a_horse'nin yanıtında da belirtildiği gibi, create tablebir tür sütunu serialotomatik olarak bir dizi oluşturacak ve bunu sütunun varsayılan değerini üretmek için kullanacaktır, bu nedenle insertnormal olarak nextvaldolaylı olarak erişilir:

create table my_table(id serial);
NOTICE:  CREATE TABLE will create implicit sequence "my_table_id_seq" for 
         serial column "my_table.id"

\d my_table
                          Table "stack.my_table"
 Column |  Type   |                       Modifiers
--------+---------+-------------------------------------------------------
 id     | integer | not null default nextval('my_table_id_seq'::regclass)

insert into my_table default values;
select currval('my_table_id_seq');
 currval
---------
       1
(1 row)

3

Dolayısıyla, bu çeşitli yöntemlerle ilgili bazı sorunlar var:

Currval, yalnızca geçerli oturumda üretilen son değeri alır; bu, değer üreten başka bir şeyiniz yoksa, ancak bir tetikleyiciyi çağırabileceğiniz ve / veya mevcut işlemde bir kereden fazla gelişmiş olması durumunda mükemmeldir. doğru değeri döndürmeyeceğim. Bu, oradaki insanların% 99'u için bir sorun değil - ama bu kişinin göz önünde bulundurması gereken bir şey.

Bir ekleme işleminden sonra atanan benzersiz tanımlayıcıyı elde etmenin en iyi yolu RETURNING yan tümcesini kullanmaktır. Aşağıdaki örnek, diziye bağlı olan sütunun "id" olarak adlandırıldığını varsayar:

insert into table A (cola,colb,colc) values ('val1','val2','val3') returning id;

RETURNING yan tümcesinin kullanışlılığının, yalnızca diziyi almanın ötesine geçtiğini unutmayın, çünkü:

  • "Final insert" için kullanılan dönüş değerleri (örneğin, BEFORE tetikleyicisi eklendikten sonra verileri değiştirmiş olabilir.)
  • Silinen değerleri döndür:

    tablodan silme, id> 100 döndürüyor *

  • Bir UPDATE tarihinden sonra değiştirilen satırları döndür:

    güncelleme tablosu X = 'y' kümesi blah = 'blech' döndürüyor *

  • Bir güncelleme için silme sonucunu kullanın:

    A ile (geri dönen id olarak A tablosundan * silin) ​​B güncelleme = set = true (burada ID'yi seçin);


Tabii ki, OP açıkça bir RETURNINGcümle kullanmak istemediklerini söyledi - ancak, başkalarını daha net kullanmanın faydalarını açıklamanın yanlış bir tarafı yok.
RDFozz

Gerçekten sadece çeşitli diğer yöntemlerin tuzaklarına dikkat çekmeye çalışıyordum (eğer dikkatli olunmadıkça, beklenen değerden farklı bir değer getirebilirdi) - ve en iyi uygulamayı netleştirdim.
değiştirici,

1

SQLALchemy kullanmama rağmen bir sorgu yürütmek zorunda kaldım çünkü currval kullanmakta başarılı olamadım.

nextId = db.session.execute("select last_value from <table>_seq").fetchone()[0] + 1

Bu bir python şişesi + postgresql projesiydi.



1

GRANTŞemada kullanmanız gerekir , bunun gibi:

GRANT USAGE ON SCHEMA schema_name to user;

ve

GRANT ALL PRIVILEGES ON schema_name.sequence_name TO user;

1
Dba.se'ye hoş geldiniz! İlk mesajınıza şerefe! Orijinal Gönderi özellikle izinlerle ilgili gözükmüyor. Belki de cevabınızı currval(), bu konuya biraz daha alakalı hale getirmek için çağırırken, izin arızalarının etrafına bazı özellikleri eklemek için genişletmeyi düşünebilirsiniz.
Peter Vandivier

0

PostgreSQL 11.2'de diziye göründüğü gibi bir tablo gibi bakabilirsiniz:

Örnek: 'names_id_seq' adında bir diziniz varsa

select * from names_id_seq;
 last_value | log_cnt | is_called
------------+---------+-----------
          4 |      32 | t
(1 row)

Bu size en son eklenen kimliği vermelidir (bu durumda 4). Bu, geçerli değerin (veya sonraki kimlik için kullanılması gereken değerin) 5 olması gerektiği anlamına gelir.


-2

PostgreSQL'in farklı sürümleri, geçerli veya bir sonraki sıra kimliğini elde etmek için farklı işlevlere sahip olabilir.

Öncelikle, Postgres'inizin versiyonunu bilmek zorundasınız. Select version () kullanarak; sürümünü almak için.

PostgreSQL 8.2.15'te, geçerli sıra kimliğini kullanarak elde edersiniz select last_value from schemaName.sequence_name.

Yukarıdaki ifade işe yaramazsa, kullanabilirsiniz select currval('schemaName.sequence_name');


2
Farklı sürümler için farklı yaptığınız için herhangi bir kanıt?
dezso
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.