Peningkatan Otomatis PostgreSQL


579

Saya beralih dari MySQL ke PostgreSQL dan bertanya-tanya bagaimana saya bisa melakukan nilai autoincrement. Saya melihat di PostgreSQL mendokumentasikan datatype "serial", tapi saya mendapatkan kesalahan sintaks saat menggunakannya (dalam v8.0).


9
jika Anda memberikan kueri dan kesalahan yang Anda dapatkan - mungkin seseorang dapat memberi tahu Anda apa yang salah dengan kueri.

2
Hit pertama saya juga Mich 'dan karena ini adalah pertanyaan yang mendapat cukup banyak pandangan agar relevan, mengapa tidak memilihnya. PS itu tidak sepele jika Anda tidak tahu bagaimana melakukannya.
baash05

1
SERIAL adalah pilihan yang lebih disukai jika driver klien Anda adalah Npgsql. Penyedia secara internal memilih nilai baru setelah INSERT menggunakan SELECT currval (pg_get_serial_ berikutnyaence ('table', 'kolom')). Ini akan gagal jika kolom yang mendasarinya bukan dari tipe serial (tipe numerik + urutan eksplisit misalnya)
Olivier MATROT

Hanya untuk rasa ingin tahu ... Mengapa seseorang harus bermigrasi dari MySQL yang sangat bagus, ke PostgreSql?
villamejia

17
... yang bahkan lebih baik.
Rohmer

Jawaban:


702

Ya, SERIAL adalah fungsi yang setara.

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

SERIAL hanyalah makro waktu pembuatan tabel di sekitar sekuens. Anda tidak dapat mengubah SERIAL ke kolom yang ada.


19
mengutip nama tabel adalah praktik yang sangat buruk
Evan Carroll

71
Mengutip nama tabel adalah kebiasaan karena saya mewarisi DB yang memiliki nama kasus campuran dan mengutip nama tabel adalah persyaratan penggunaan.
Trey

26
@ Evan Carroll - Mengapa itu kebiasaan buruk (hanya bertanya)?
Christian

27
karena kecuali Anda memiliki meja "Table"dan "table"kemudian hanya meninggalkannya kuotasi dan canonicalize ke table. Konvensi ini tidak pernah menggunakan kutipan dalam hal. Anda dapat, jika ingin, menggunakan nama case campuran untuk penampilan, hanya saja tidak memerlukannya: CREATE TABLE fooBar ( .. ); SELECT * FROM fooBar;akan berfungsi, seperti yang akan terjadi SELECT * FROM foobar.
Evan Carroll

26
Per postgres doc, baik kutipan atau tanda kutip secara konsisten: postgresql.org/docs/current/interactive/…
Καrτhικ

225

Anda dapat menggunakan tipe data integer lainnya , seperti smallint.

Contoh:

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;

Lebih baik menggunakan tipe data Anda sendiri, daripada tipe data serial pengguna .


11
Saya akan mengatakan ini sebenarnya jawaban yang lebih baik karena memungkinkan saya untuk mengubah tabel yang baru saja saya buat di PostgreSQL dengan mengatur kolom default (setelah membaca CREATE SEQUENCE postgresql.org/docs/8.1/interactive/sql-createsequence.html ) . NAMUN, saya tidak yakin mengapa Anda mengubah pemiliknya.
JayC

12
@ JayC: Dari dokumentasi : Terakhir, urutan ditandai sebagai "dimiliki oleh" kolom, sehingga akan dijatuhkan jika kolom atau tabel dijatuhkan.
user272735

9
mengapa komunitas postgres tidak menemukan kembali kata kunci peningkatan otomatis?
Dr Deo

2
@Dr Deo: mereka menggunakan kata kunci serial bukannya autoincrement, saya tidak tahu mengapa :)
Ahmad

4
Ada juga server yang lebih kecil jika Anda hanya menginginkan tipe data yang lebih kecil.
beldaz

110

Jika Anda ingin menambahkan urutan ke id di tabel yang sudah ada, Anda dapat menggunakan:

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

Apa itu urutan? Di mana AUTO_INCREMENT?
Hijau

23
@Green: AUTO_INCREMENT bukan bagian dari standar SQL, ini khusus untuk MySQL. Urutan adalah sesuatu yang melakukan pekerjaan serupa di PostgreSQL.
beldaz

5
jika Anda menggunakan 'id SERIAL', itu akan secara otomatis membuat urutan di PostgreSQL. Nama urutan itu adalah <nama tabel> _ <nama kolom> _seq
Jude Niroshan

Apakah kamu tidak harus menggunakan ALTER COLUMN user_id?
Alec

Saya mencoba metode ini tetapi saya mendapatkan kesalahan: ERROR: syntax error at or near "DEFAULT"Ada saran?
Ely Fialkoff

44

Walaupun sepertinya urutannya setara dengan MySQL auto_increment, ada beberapa perbedaan yang halus tetapi penting:

1. Permintaan Gagal Peningkatan Urutan / Serial

Kolom serial akan bertambah pada kueri yang gagal. Ini mengarah ke fragmentasi dari kueri yang gagal, bukan hanya penghapusan baris. Sebagai contoh, jalankan query berikut pada database PostgreSQL Anda:

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;

Anda harus mendapatkan output berikut:

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

Perhatikan bagaimana Anda beralih dari 1 ke 3 bukannya 1 ke 2.

Ini masih terjadi jika Anda secara manual membuat urutan Anda sendiri dengan:

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;

Jika Anda ingin menguji perbedaan MySQL, jalankan yang berikut di database MySQL:

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);

Anda harus mendapatkan yang berikut tanpa frmentasi :

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

2. Mengatur Nilai Kolom Serial Secara Manual Dapat Menyebabkan Gagal Permintaan Masa Depan.

Ini ditunjukkan oleh @trev dalam jawaban sebelumnya.

Untuk mensimulasikan ini secara manual atur uid ke 4 yang akan "clash" nanti.

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

Data tabel:

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

Jalankan sisipan lain:

INSERT INTO table1 (col_b) VALUES(6);

Data tabel:

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

Sekarang jika Anda menjalankan sisipan lain:

INSERT INTO table1 (col_b) VALUES(7);

Ini akan gagal dengan pesan kesalahan berikut:

GALAT: nilai kunci duplikat melanggar batasan unik "table1_pkey" DETAIL: Kunci (uid) = (5) sudah ada.

Sebaliknya, MySQL akan menangani ini dengan anggun seperti yang ditunjukkan di bawah ini:

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

Sekarang masukkan baris lain tanpa pengaturan uid

INSERT INTO table1 (col_b) VALUES(3);

Permintaan tidak gagal, Anda hanya perlu melompat ke 5:

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

Pengujian dilakukan pada MySQL 5.6.33, untuk Linux (x86_64) dan PostgreSQL 9.4.9


10
Anda memberikan perbandingan tetapi saya tidak melihat solusi apa pun di sini! Apakah ini sebuah jawaban?
Anwar

4
@ Anwar itu hanya memperluas berbagai jawaban yang menyatakan bahwa jawabannya adalah menggunakan serial / urutan. Ini memberikan beberapa konteks penting untuk dipertimbangkan.
Programster

38

Dimulai dengan Postgres 10, kolom identitas seperti yang didefinisikan oleh standar SQL juga didukung:

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

membuat kolom identitas yang tidak bisa diganti kecuali diminta secara eksplisit. Sisipan berikut akan gagal dengan kolom yang didefinisikan sebagai generated always:

insert into foo (id) 
values (1);

Namun ini dapat ditolak:

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

Saat menggunakan opsi generated by defaultini pada dasarnya perilaku yang sama dengan serialimplementasi yang ada :

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

Ketika nilai diberikan secara manual, urutan yang mendasarinya perlu disesuaikan secara manual juga - sama seperti dengan serialkolom.


Kolom identitas bukan kunci utama secara default (seperti serialkolom). Jika harus satu, batasan kunci primer perlu didefinisikan secara manual.


26

Maaf, untuk mengulangi pertanyaan lama, tapi ini adalah pertanyaan / jawaban Stack Overflow pertama yang muncul di Google.

Posting ini (yang muncul pertama kali di Google) berbicara tentang penggunaan sintaks yang lebih diperbarui untuk PostgreSQL 10: https://blog.2ndquadrant.com/postgresql-10-identity-columns/

yang kebetulan adalah:

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

Semoga itu bisa membantu :)


1
Ini memang cara untuk masuk dalam PostgreSQL 10 dan itu adalah sintaksis yang sama dengan perangkat lunak database lain seperti DB2 atau Oracle.
adriaan

1
@adriaan Sebenarnya GENERATED … AS IDENTITYperintahnya adalah SQL standar. Pertama ditambahkan dalam SQL: 2003 , kemudian diklarifikasi dalam SQL: 2008 . Lihat fitur # T174 & F386 & T178.
Basil Bourque

16

Anda harus berhati-hati untuk tidak memasukkan langsung ke bidang SERIAL atau urutan Anda, jika tidak, penulisan Anda akan gagal ketika urutan mencapai nilai yang dimasukkan:

-- 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

Dalam konteks pertanyaan yang diajukan dan sebagai balasan atas komentar oleh @ sereja1c, membuat SERIALsecara implisit menciptakan urutan, jadi untuk contoh di atas-

CREATE TABLE foo (id SERIAL,bar varchar);

CREATE TABLEsecara implisit akan membuat urutan foo_id_sequntuk kolom serial foo.id. Karenanya, SERIAL[4 Bytes] bagus untuk kemudahan penggunaan kecuali Anda membutuhkan tipe data khusus untuk id Anda.



3

Sejak PostgreSQL 10

CREATE TABLE test_new (
    id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    payload text
);
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.