ChatGPT解决这个技术问题 Extra ChatGPT

What's the PostgreSQL datatype equivalent to MySQL AUTO INCREMENT?

I'm switching from MySQL to PostgreSQL and I was wondering how can I have an INT column with AUTO INCREMENT. I saw in the PostgreSQL docs a datatype called SERIAL, but I get syntax errors when using it.

if you'd provide the query and error you're getting - perhaps someone could tell you what is wrong with the query.
My first hit too Mich' and as it's a question that gets enough views to be relevant, why not vote it up. PS it's not trivial if you don't know how to do it.
SERIAL is the preferred choice if your client driver is Npgsql. The provider is internally selecting new values after an INSERT using SELECT currval(pg_get_serial_sequence('table', 'column')). This will fail if the underlying column is not of type serial (numeric type + explicit sequence for instance)
Just for curiousity... Why does someone have to migrate from MySQL which is very good, to PostgreSql?
...which is even better.

y
yakirchi

Yes, SERIAL is the equivalent function.

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 is just a create table time macro around sequences. You can not alter SERIAL onto an existing column.


because unless you have a table "Table" and "table" then just leave it unquoted and canonicalize it to table. The convention is simply never to use quotes in Pg. You can, if you want, use mixed case names for appearance, just don't require it: CREATE TABLE fooBar ( .. ); SELECT * FROM fooBar; will work, as will SELECT * FROM foobar.
plus...the standard for most relational db implementations is to not have quotes. It makes it simpler to swap database implementations if ever necessary.
@EvanCarroll try INSERT INTO user without quotes, please.
Per postgres doc, either consistently quote or unquote: postgresql.org/docs/current/interactive/…
There is nothing wrong with quoting. In fact, it's Postgres that's the weird one here with a caseless convention for schema. Migrating from any other database requires this.
u
user272735

You can use any other integer data type, such as smallint.

Example :

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;

Better to use your own data type, rather than user serial data type.


I'd say this is actually the better answer because it allowed me to modify a table I had just created in PostgreSQL by setting the columns default (after reading up on CREATE SEQUENCE postgresql.org/docs/8.1/interactive/sql-createsequence.html ). HOWEVER, I'm not quite sure why you changed the owner.
@JayC: From documentation: Lastly, the sequence is marked as "owned by" the column, so that it will be dropped if the column or table is dropped.
why doesn't postgres community just reinvent the autoincrement keyword?
There's also smallserial if you just want a smaller data type.
I never understood why some developers reinvent the wheel or complicate things. If Postgres already has an internal mechanism optimized and created specifically for this problem (Serial), why make everything more complicated by creating a sequence?
F
Felipe

If you want to add sequence to id in the table which already exist you can use:

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

What is sequence? Where is AUTO_INCREMENT?
@Green: AUTO_INCREMENT isn't part of the SQL standard, it's specific to MySQL. Sequences are something that do a similar job in PostgreSQL.
if you use 'id SERIAL', it will automatically creates a sequence in PostgreSQL. Name of that sequence will be __seq
Don't you have to use ALTER COLUMN user_id?
I tried this method but I get an error: ERROR: syntax error at or near "DEFAULT" Any suggestions?
a
a_horse_with_no_name

Starting with Postgres 10, identity columns as defined by the SQL standard are also supported:

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

creates an identity column that can't be overridden unless explicitly asked for. The following insert will fail with a column defined as generated always:

insert into foo (id) 
values (1);

This can however be overruled:

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

When using the option generated by default this is essentially the same behaviour as the existing serial implementation:

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

When a value is supplied manually, the underlying sequence needs to be adjusted manually as well - the same as with a serial column.

An identity column is not a primary key by default (just like a serial column). If it should be one, a primary key constraint needs to be defined manually.


generated always as identity is from SQL 2003 standard. You can find it in H2 & Oracle. Thx God I'm in 2021 ))
what's the benefit to using this over SERIAL?
P
Programster

Whilst it looks like sequences are the equivalent to MySQL auto_increment, there are some subtle but important differences:

1. Failed Queries Increment The Sequence/Serial

The serial column gets incremented on failed queries. This leads to fragmentation from failed queries, not just row deletions. For example, run the following queries on your PostgreSQL database:

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;

You should get the following output:

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

Notice how uid goes from 1 to 3 instead of 1 to 2.

This still occurs if you were to manually create your own sequence with:

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;

If you wish to test how MySQL is different, run the following on a MySQL database:

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

You should get the following with no fragementation:

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

2. Manually Setting the Serial Column Value Can Cause Future Queries to Fail.

This was pointed out by @trev in a previous answer.

To simulate this manually set the uid to 4 which will "clash" later.

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

Table data:

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

Run another insert:

INSERT INTO table1 (col_b) VALUES(6);

Table data:

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

Now if you run another insert:

INSERT INTO table1 (col_b) VALUES(7);

It will fail with the following error message:

ERROR: duplicate key value violates unique constraint "table1_pkey" DETAIL: Key (uid)=(5) already exists.

In contrast, MySQL will handle this gracefully as shown below:

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

Now insert another row without setting uid

INSERT INTO table1 (col_b) VALUES(3);

The query doesn't fail, uid just jumps to 5:

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

Testing was performed on MySQL 5.6.33, for Linux (x86_64) and PostgreSQL 9.4.9


You're giving a comparison but I don't see any solution here! Is it an answer?
@Anwar it simply extends the various answers that state that the answer is to use a serial/sequence. This provides some important context to take into consideration.
Coming from 10 years with MSSQL and Mysql, Point 2 is just utterly ridiculous. A random, manual insert from a user can entirely break an application
@dsturbid A code bug or data quality problem might sometimes legitimately call for a manual insert in a production situation. That might be enough of a reason for some application developers to avoid using this feature.
"Failed Queries Increment The Sequence/Serial" - my testing with two psql instances shows that this also applies to failed transactions. If you begin two transactions, the first one to INSERT claims the first id. If the second transaction commits but the first rolls back, the first id will be skipped in the table.
Z
Zhao Li

Sorry, to rehash an old question, but this was the first Stack Overflow question/answer that popped up on Google.

This post (which came up first on Google) talks about using the more updated syntax for PostgreSQL 10: https://blog.2ndquadrant.com/postgresql-10-identity-columns/

which happens to be:

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

Hope that helps :)


This is indeed the way to go in PostgreSQL 10 and it is the same syntax as other database software like DB2 or Oracle.
@adriaan Actually the GENERATED … AS IDENTITY commands are standard SQL. First added in SQL:2003, then clarified in SQL:2008. See features # T174 & F386 & T178.
t
trev

You have to be careful not to insert directly into your SERIAL or sequence field, otherwise your write will fail when the sequence reaches the inserted value:

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

P
Prince

In the context of the asked question and in reply to the comment by @sereja1c, creating SERIAL implicitly creates sequences, so for the above example-

CREATE TABLE foo (id SERIAL,bar varchar);

CREATE TABLE would implicitly create sequence foo_id_seq for serial column foo.id. Hence, SERIAL [4 Bytes] is good for its ease of use unless you need a specific datatype for your id.


S
Sergey Vishnevetskiy

Since PostgreSQL 10

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

w
webtechnelson

This way will work for sure, I hope it helps:

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

You can check this the details in the next link: http://www.postgresqltutorial.com/postgresql-serial/


佚名

Create Sequence.

CREATE SEQUENCE user_role_id_seq
  INCREMENT 1
  MINVALUE 1
  MAXVALUE 9223372036854775807
  START 3
  CACHE 1;
ALTER TABLE user_role_id_seq
  OWNER TO postgres;

and alter table

ALTER TABLE user_roles ALTER COLUMN user_role_id SET DEFAULT nextval('user_role_id_seq'::regclass);