web-dev-qa-db-fra.com

PostgreSQL Autoincrement

Je suis en train de passer de MySQL à PostgreSQL et je me demandais comment faire pour auto-incrémenter des valeurs. J'ai vu dans la documentation de PostgreSQL un type de données "serial", mais j'obtiens des erreurs de syntaxe lors de son utilisation (version 8.0).

544
Ian

Oui, SERIAL est la fonction équivalente.

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 est juste une macro de création de table de temps autour de séquences. Vous ne pouvez pas modifier SERIAL sur une colonne existante.

669
Trey

Vous pouvez utiliser n’importe quel autre type type de données entier , tel que smallint.

Exemple :

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;

Mieux vaut utiliser votre propre type de données plutôt que l'utilisateur type de données série .

217
Ahmad

Si vous voulez ajouter une séquence à id dans la table qui existe déjà, vous pouvez utiliser:

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

Bien qu'il semble que les séquences soient l'équivalent de MySQL avec auto_increment, il existe quelques différences subtiles mais importantes:

1. Les requêtes en échec incrémentent la séquence/série

La colonne série est incrémentée en cas d'échec des requêtes. Cela entraîne une fragmentation des requêtes ayant échoué, pas seulement des suppressions de lignes. Par exemple, exécutez les requêtes suivantes sur votre base de données PostgreSQL:

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;

Vous devriez obtenir le résultat suivant:

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

Remarquez comment uid va de 1 à 3 au lieu de 1 à 2.

Cela se produit encore si vous créez manuellement votre propre séquence avec:

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;

Si vous souhaitez tester en quoi MySQL est différent, exécutez ce qui suit sur une base de données 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);

Vous devriez obtenir ce qui suit avec no fragementation:

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

2. La définition manuelle de la valeur de la colonne de série peut entraîner l'échec des requêtes futures.

Cela a été souligné par @trev dans une réponse précédente.

Pour simuler cette opération, définissez manuellement l'ID sur 4, qui se "heurtera" plus tard.

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

Données de la table:

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

Exécuter une autre insertion:

INSERT INTO table1 (col_b) VALUES(6);

Données de la table:

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

Maintenant, si vous exécutez un autre insert:

INSERT INTO table1 (col_b) VALUES(7);

Il échouera avec le message d'erreur suivant:

ERREUR: la valeur de la clé dupliquée viole la contrainte unique "table1_pkey" DETAIL: la clé (uid) = (5) existe déjà.

En revanche, MySQL gérera cela gracieusement comme indiqué ci-dessous:

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

Maintenant, insérez une autre ligne sans définir uid

INSERT INTO table1 (col_b) VALUES(3);

La requête n'échoue pas, uid passe à 5:

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

Les tests ont été effectués sur MySQL 5.6.33, pour Linux (x86_64) et PostgreSQL 9.4.9.

39
Programster

À partir de Postgres 10, les colonnes d’identité définies par le standard SQL sont également prises en charge:

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

crée une colonne d'identité qui ne peut être remplacée que si elle est explicitement demandée. L'insertion suivante échouera avec une colonne définie comme generated always:

insert into foo (id) 
values (1);

Ceci peut cependant être annulé:

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

Lorsque vous utilisez l'option generated by default, le comportement est identique à celui de l'implémentation existante serial:

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

Lorsqu'une valeur est fournie manuellement, la séquence sous-jacente doit également être ajustée manuellement, comme pour une colonne serial.


Une colonne d'identité n'est pas une clé primaire par défaut (comme une colonne serial). Si tel est le cas, une contrainte de clé primaire doit être définie manuellement.

35

Désolé de reformuler une vieille question, mais c’est la première question/réponse de Stack Overflow qui est apparue sur Google.

Ce billet (qui a été publié en premier sur Google) explique comment utiliser la syntaxe la plus récente pour PostgreSQL 10: https://blog.2ndquadrant.com/postgresql-10-identity-columns/

qui se trouve être:

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

J'espère que ça t'as aidé :)

21
A L

Vous devez faire attention à ne pas insérer directement dans votre champ SERIAL ou de séquence, sinon votre écriture échouera lorsque la séquence atteindra la valeur insérée:

-- 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; 
16
trev

Dans le contexte de la question posée et en réponse au commentaire de @ sereja1c, créer SERIAL crée implicitement des séquences, donc pour l'exemple ci-dessus:

CREATE TABLE foo (id SERIAL,bar varchar);

CREATE TABLE créerait implicitement la séquence foo_id_seq pour la colonne en série foo.id. Par conséquent, SERIAL [4 Octets] convient à sa facilité d'utilisation, sauf si vous avez besoin d'un type de données spécifique pour votre identifiant.

15
Prince

Cela fonctionnera à coup sûr, j'espère que cela aidera:

CREATE TABLE fruits(
   id SERIAL PRIMARY KEY,
   name VARCHAR NOT NULL
);

INSERT INTO fruits(id,name) VALUES(DEFAULT,'Apple');

or

INSERT INTO fruits VALUES(DEFAULT,'Apple');

Vous pouvez vérifier ces détails dans le lien suivant: http://www.postgresqltutorial.com/postgresql-serial/

2
webtechnelson

Depuis PostgreSQL 10

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