PostgreSQL Otomatik Oluşturma


578

MySQL'den PostgreSQL'e geçiyorum ve nasıl autoincrement değerleri yapabileceğimi merak ediyordum. PostgreSQL dokümanı bir veri türü "seri" gördüm, ancak (v8.0) sözdizimi hataları alıyorum.


9
sorguyu ve aldığınız hatayı verirseniz - belki birisi size sorgunun neyin yanlış olduğunu söyleyebilir.

2
İlk vuruşum da Mich 've alakalı olmak için yeterli görüş alan bir soru olduğu için neden oy kullanmıyorsunuz? PS, bunu nasıl yapacağınızı bilmiyorsanız önemsiz değil.
baash05

1
İstemci sürücünüz Npgsql ise SERIAL tercih edilen seçimdir. Sağlayıcı, bir INSERT sonrasında SELECT akımını (pg_get_serial_sequence ('tablo', 'sütun')) kullanarak yeni değerler seçiyor. Temel sütun seri tipte değilse (örneğin sayısal tip + açık dizi) başarısız olur
Olivier MATROT

Sadece merak için ... Neden birisi çok iyi MySQL'den PostgreSql'e göç etmek zorunda?
villamejia

17
... daha da iyi.
Rohmer

Yanıtlar:


701

Evet, SERİAL eşdeğer işlevdir.

CREATE TABLE foo (
id SERIAL,
bar varchar);

INSERT INTO foo (bar) values ('blah');
INSERT INTO foo (bar) values ('blah');

SELECT * FROM foo;

1,blah
2,blah

SERİ, sadece diziler etrafında bir tablo zamanı oluştur makrosu. SERİ'yi mevcut bir sütuna değiştiremezsiniz.


19
Tablo adını alıntılamak gerçekten kötü bir uygulamadır
Evan Carroll

71
Tablo adlarını alıntılamak bir alışkanlıktır çünkü karışık vaka adları olan bir DB'yi miras aldım ve tablo adlarını alıntılamak bir kullanım gereksinimidir.
Trey

26
@Evan Carroll - Neden kötü bir alışkanlık (sadece soruyor)?
Christian

27
çünkü bir tablonuz yoksa "Table"ve "table"daha sonra sadece alıntı yapmadan bırakınız ve standartlaştırınız table. Konvansiyon asla Pg. İsterseniz, görünüm için karışık vaka adlarını kullanabilirsiniz, sadece gerekli değildir: CREATE TABLE fooBar ( .. ); SELECT * FROM fooBar;çalışacağı gibi SELECT * FROM foobar.
Evan Carroll

26
Postgres doc başına, tutarlı bir şekilde alıntı yapın veya alıntı yapın: postgresql.org/docs/current/interactive/…
Καrτhικ

226

Başka kullanabilirsiniz tamsayı veri türü gibi smallint.

Misal :

CREATE SEQUENCE user_id_seq;
CREATE TABLE user (
    user_id smallint NOT NULL DEFAULT nextval('user_id_seq')
);
ALTER SEQUENCE user_id_seq OWNED BY user.user_id;

Kullanıcı seri veri türünden ziyade kendi veri türünüzü kullanmak daha iyidir .


11
Bunun aslında daha iyi bir yanıt olduğunu söyleyebilirim çünkü PostgreSQL'de yeni oluşturduğum bir tabloyu varsayılan sütunları ayarlayarak değiştirmeme izin verdi ( CREATE SEQUENCE postgresql.org/docs/8.1/interactive/sql-createsequence.html üzerinde okuduktan sonra ) . ANCAK, sahibini neden değiştirdiğinizden emin değilim.
JayC

12
@JayC: Dokümantasyondan : Son olarak, dizi sütuna "ait" olarak işaretlenir, böylece sütun veya tablo düşürülürse düşürülür.
user272735

8
postgres topluluğu neden autoincrement anahtar kelimesini yeniden keşfetmiyor?
Dr Deo

2
@Dr Deo: seri yerine autoincrement anahtar kelime kullanıyorlar, neden bilmiyorum :)
Ahmad

4
Daha küçük bir veri türü istiyorsanız, küçük seri de var.
beldaz

110

Halihazırda var olan tabloda kimliğe sıra eklemek isterseniz şunları kullanabilirsiniz:

CREATE SEQUENCE user_id_seq;
ALTER TABLE user ALTER user_id SET DEFAULT NEXTVAL('user_id_seq');

Dizi nedir? AUTO_INCREMENT nerede?
Yeşil

23
@Yeşil: AUTO_INCREMENT, SQL standardının bir parçası değildir, MySQL'e özeldir. Diziler PostgreSQL'de benzer bir iş yapan bir şeydir.
beldaz

5
'id SERIAL' kullanırsanız, PostgreSQL'de otomatik olarak bir sıra oluşturur. Bu dizinin adı <tablo adı> _ <sütun adı> _seq
Jude Niroshan

Kullanmanıza gerek yok ALTER COLUMN user_idmu?
Alec

Bu yöntemi denedim ama bir hata alıyorum: ERROR: syntax error at or near "DEFAULT"Herhangi bir öneriniz var mı?
Ely Fialkoff

44

Diziler MySQL auto_increment'e eşdeğer gibi görünse de, bazı ince ama önemli farklılıklar vardır:

1. Başarısız Sorgular Sıra / Seri Artışı

Seri sütun başarısız sorgularda artar. Bu, yalnızca satır silme işlemlerinin değil, başarısız sorguların parçalanmasına yol açar. Örneğin, PostgreSQL veritabanınızda aşağıdaki sorguları çalıştırın:

CREATE TABLE table1 (
  uid serial NOT NULL PRIMARY KEY,
  col_b integer NOT NULL,
  CHECK (col_b>=0)
);

INSERT INTO table1 (col_b) VALUES(1);
INSERT INTO table1 (col_b) VALUES(-1);
INSERT INTO table1 (col_b) VALUES(2);

SELECT * FROM table1;

Aşağıdaki çıktıyı almalısınız:

 uid | col_b 
-----+-------
   1 |     1
   3 |     2
(2 rows)

Uid'in 1 ila 2 yerine 1'den 3'e nasıl gittiğine dikkat edin.

Bu, aşağıdakilerle manuel olarak kendi dizinizi oluşturursanız gerçekleşir:

CREATE SEQUENCE table1_seq;
CREATE TABLE table1 (
    col_a smallint NOT NULL DEFAULT nextval('table1_seq'),
    col_b integer NOT NULL,
    CHECK (col_b>=0)
);
ALTER SEQUENCE table1_seq OWNED BY table1.col_a;

MySQL'in nasıl farklı olduğunu test etmek isterseniz, MySQL veritabanında aşağıdakileri çalıştırın:

CREATE TABLE table1 (
  uid int unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
  col_b int unsigned NOT NULL
);

INSERT INTO table1 (col_b) VALUES(1);
INSERT INTO table1 (col_b) VALUES(-1);
INSERT INTO table1 (col_b) VALUES(2);

Parçalanma olmadan aşağıdakileri almalısınız :

+-----+-------+
| uid | col_b |
+-----+-------+
|   1 |     1 |
|   2 |     2 |
+-----+-------+
2 rows in set (0.00 sec)

2. Seri Sütun Değerinin Manuel Olarak Ayarlanması Gelecekteki Sorguların Başarısız olmasına Neden Olabilir.

Bu önceki cevapta @trev tarafından belirtilmişti.

Bunu simüle etmek için uid değerini daha sonra "çakışma" yapacak olan 4'e ayarlayın.

INSERT INTO table1 (uid, col_b) VALUES(5, 5);

Tablo verileri:

 uid | col_b 
-----+-------
   1 |     1
   3 |     2
   5 |     5
(3 rows)

Başka bir kesici uç çalıştırın:

INSERT INTO table1 (col_b) VALUES(6);

Tablo verileri:

 uid | col_b 
-----+-------
   1 |     1
   3 |     2
   5 |     5
   4 |     6

Şimdi başka bir kesici uç çalıştırırsanız:

INSERT INTO table1 (col_b) VALUES(7);

Aşağıdaki hata iletisiyle başarısız olur:

HATA: yinelenen anahtar değeri benzersiz kısıtlamayı ihlal ediyor "table1_pkey" DETAY: Anahtar (uid) = (5) zaten var.

Bunun aksine, MySQL bunu aşağıda gösterildiği gibi incelikle işleyecektir:

INSERT INTO table1 (uid, col_b) VALUES(4, 4);

Şimdi uid ayarlamadan başka bir satır ekleyin

INSERT INTO table1 (col_b) VALUES(3);

Sorgu başarısız olmaz, uid sadece 5'e atlar:

+-----+-------+
| uid | col_b |
+-----+-------+
|   1 |     1 |
|   2 |     2 |
|   4 |     4 |
|   5 |     3 |
+-----+-------+

Test, Linux (x86_64) ve PostgreSQL 9.4.9 için MySQL 5.6.33 üzerinde gerçekleştirildi


10
Bir karşılaştırma yapıyorsunuz ama burada çözüm göremiyorum! Bu bir cevap mı?
Anwar

4
@Ancak, cevabın bir seri / dizi kullanmak olduğunu belirten çeşitli cevapları genişletir. Bu, dikkate alınması gereken bazı önemli bağlamlar sağlar.
Programcı

38

Postgres 10'dan başlayarak, SQL standardı tarafından tanımlanan kimlik sütunları da desteklenir:

create table foo 
(
  id integer generated always as identity
);

açıkça istenmedikçe geçersiz kılınamayan bir kimlik sütunu oluşturur. Aşağıdaki ekleme, şu şekilde tanımlanan bir sütunla başarısız olacaktır generated always:

insert into foo (id) 
values (1);

Ancak bu geçersiz kılınabilir:

insert into foo (id) overriding system value 
values (1);

Seçeneği kullanırken, generated by defaultbu aslında mevcut serialuygulama ile aynı davranıştır :

create table foo 
(
  id integer generated by default as identity
);

Bir değer manuel olarak sağlandığında, temel sıralamanın serialsütunla olduğu gibi manuel olarak da ayarlanması gerekir .


Kimlik sütunu varsayılan olarak birincil bir anahtar değildir (tıpkı bir serialsütun gibi ). Bir tane olması gerekiyorsa, birincil anahtar kısıtlamasının manuel olarak tanımlanması gerekir.


26

Maalesef eski bir soruyu yeniden düzenlemek için, ancak bu Google'da açılan ilk Yığın Taşması sorusu / cevabı idi.

Bu yazı (Google'da ilk kez geldi) PostgreSQL 10 için daha güncel sözdizimini kullanma hakkında konuşuyor: https://blog.2ndquadrant.com/postgresql-10-identity-columns/

hangi olur:

CREATE TABLE test_new (
    id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
);

Umarım yardımcı olur :)


1
Bu gerçekten PostgreSQL 10'a geçmenin yolu ve DB2 veya Oracle gibi diğer veritabanı yazılımlarıyla aynı sözdizimidir.
adriaan

1
@adriaan Aslında GENERATED … AS IDENTITYkomutlar standart SQL'dir . İlk önce SQL: 2003'te eklendi , sonra SQL: 2008'de netleştirildi . Bkz. # T174 ve F386 ve T178 özellikleri.
Basil Bourque

16

Doğrudan SERİ veya dizi alanınıza eklememeye dikkat etmelisiniz, aksi takdirde dizi girilen değere ulaştığında yazma işleminiz başarısız olur:

-- Table: "test"

-- DROP TABLE test;

CREATE TABLE test
(
  "ID" SERIAL,
  "Rank" integer NOT NULL,
  "GermanHeadword" "text" [] NOT NULL,
  "PartOfSpeech" "text" NOT NULL,
  "ExampleSentence" "text" NOT NULL,
  "EnglishGloss" "text"[] NOT NULL,
  CONSTRAINT "PKey" PRIMARY KEY ("ID", "Rank")
)
WITH (
  OIDS=FALSE
);
-- ALTER TABLE test OWNER TO postgres;
 INSERT INTO test("Rank", "GermanHeadword", "PartOfSpeech", "ExampleSentence", "EnglishGloss")
           VALUES (1, '{"der", "die", "das", "den", "dem", "des"}', 'art', 'Der Mann küsst die Frau und das Kind schaut zu', '{"the", "of the" }');


 INSERT INTO test("ID", "Rank", "GermanHeadword", "PartOfSpeech", "ExampleSentence", "EnglishGloss")
           VALUES (2, 1, '{"der", "die", "das"}', 'pron', 'Das ist mein Fahrrad', '{"that", "those"}');

 INSERT INTO test("Rank", "GermanHeadword", "PartOfSpeech", "ExampleSentence", "EnglishGloss")
           VALUES (1, '{"der", "die", "das"}', 'pron', 'Die Frau, die nebenen wohnt, heißt Renate', '{"that", "who"}');

SELECT * from test; 

15

Sorulan soru bağlamında ve @ sereja1c tarafından yapılan yoruma yanıt olarak, SERIALörtük olarak diziler oluşturur, bu nedenle yukarıdaki örnek için-

CREATE TABLE foo (id SERIAL,bar varchar);

CREATE TABLEdolaylı foo_id_seqolarak seri sütun için sıra oluşturur foo.id. Bu nedenle, SERIAL[4 Bayt] kimliğiniz için belirli bir veri tipine ihtiyacınız olmadığı sürece kullanım kolaylığı açısından iyidir.



3

PostgreSQL 10'dan beri

CREATE TABLE test_new (
    id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    payload text
);
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.