PostgreSQL 자동 증분


578

MySQL에서 PostgreSQL로 전환하고 자동 증가 값을 수행하는 방법이 궁금합니다. PostgreSQL 문서에서 데이터 유형 "직렬"을 보았지만 v8.0에서 사용할 때 구문 오류가 발생합니다.


9
쿼리와 오류를 제공하면 쿼리에 어떤 문제가 있는지 누군가가 알 수 있습니다.

2
내 첫 번째 명중도 Mich '와 관련이있을 정도로 충분한 견해를 얻는 질문이므로 투표하지 않는 것이 좋습니다. 추신 : 당신이 그것을하는 방법을 모른다면 사소하지 않습니다.
baash05

1
클라이언트 드라이버가 Npgsql 인 경우 SERIAL이 선호됩니다. 공급자는 SELECT currval (pg_get_serial_sequence ( 'table', 'column'))을 사용하여 INSERT 후 내부적으로 새 값을 선택합니다. 기본 열이 serial 유형이 아닌 경우 (예 : 숫자 유형 + 명시 적 시퀀스)
Olivier MATROT

그냥 궁금해서 ... 누군가 MySQL에서 PostgreSql으로 마이그레이션해야하는 이유는 무엇입니까?
villamejia

17
... 더 낫다.
Rohmer

답변:


701

예, SERIAL은 동등한 기능입니다.

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은 시퀀스를 중심으로 테이블 시간을 생성하는 매크로입니다. 기존 컬럼에서 SERIAL을 변경할 수 없습니다.


19
테이블 이름을 인용하는 것은 정말 나쁜 습관입니다
Evan Carroll

71
테이블 이름을 인용하는 것은 습관이 섞인 DB를 상속하고 테이블 이름을 인용하는 것이 필요하기 때문에 습관입니다.
Trey

26
@Evan Carroll-왜 나쁜 습관입니까?
Christian

27
테이블을하지 않는 한 때문에 "Table"하고 "table"그럼 그냥 인용 부호가 그것을두고으로 정규화 table. 컨벤션은 단순히 Pg에서 따옴표를 사용하지 않습니다. 원하는 경우 대소 문자를 혼합 된 이름으로 사용할 수 있지만 필요하지 않습니다 . CREATE TABLE fooBar ( .. ); SELECT * FROM fooBar;작동 SELECT * FROM foobar합니다.
Evan Carroll

26
postgres 문서에 따라 꾸준히 인용하거나 인용을 해제하십시오 : postgresql.org/docs/current/interactive/…
Καrτhικ

226

와 같은 다른 정수 데이터 유형을 사용할 수 있습니다 smallint.

예 :

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;

사용자 직렬 데이터 유형 보다는 고유 한 데이터 유형을 사용하는 것이 좋습니다 .


11
PostgreSQL에서 방금 만든 열을 기본값으로 설정하여 postgreSQL에서 방금 만든 테이블을 수정할 수 있기 때문에 이것이 실제로 더 나은 대답이라고합니다 ( CREATE SEQUENCE postgresql.org/docs/8.1/interactive/sql-createsequence.html에서 읽은 후 ) . 그러나 왜 당신이 소유자를 변경했는지 잘 모르겠습니다.
JayC

12
@JayC : 문서에서 : 마지막으로, 열은 "소유자"로 표시되므로 열 또는 테이블을 삭제하면 삭제됩니다.
user272735

8
왜 postgres 커뮤니티가 자동 증가 키워드를 재발 명하지 않습니까?
Dr Deo

2
@ Dr Deo : 그들은 자동 증가 키워드 대신 직렬을 사용합니다. 이유를 모르겠습니다 :)
Ahmad

4
더 작은 데이터 유형을 원하면 더 작은 직렬도 있습니다.
beldaz

110

이미 존재하는 테이블에서 id에 시퀀스를 추가하려면 다음을 사용할 수 있습니다.

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

시퀀스 란 무엇입니까? AUTO_INCREMENT는 어디에 있습니까?
Green

23
@Green : AUTO_INCREMENT는 SQL 표준의 일부가 아니며 MySQL에만 해당됩니다. 시퀀스는 PostgreSQL에서 비슷한 작업을 수행합니다.
beldaz

5
'id SERIAL'을 사용하면 PostgreSQL에 자동으로 시퀀스가 ​​생성됩니다. 그 시퀀스의 이름이 될 것입니다 <테이블 이름> _ <열 이름> _seq
유 Niroshan

사용할 필요가 ALTER COLUMN user_id없습니까?
Alec

이 방법을 시도했지만 오류가 발생했습니다. ERROR: syntax error at or near "DEFAULT"제안 사항이 있습니까?
Ely Fialkoff

44

시퀀스가 MySQL auto_increment 같은 것처럼 보이지만 미묘하지만 중요한 차이점이 있습니다.

1. 쿼리 실패 시퀀스 / 시리얼 증가

실패한 쿼리에서 직렬 열이 증가합니다. 이로 인해 행 삭제뿐만 아니라 실패한 쿼리에서 조각화가 발생합니다. 예를 들어 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;

다음과 같은 결과가 나타납니다.

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

uid가 1에서 2가 아닌 1에서 3으로 어떻게되는지 확인하십시오.

다음을 사용하여 직접 시퀀스를 수동으로 생성 한 경우에도 여전히 발생합니다.

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의 차이점을 테스트하려면 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);

조각화없이 다음을 얻어야합니다 .

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

2. 직렬 열 값을 수동으로 설정하면 향후 쿼리가 실패 할 수 있습니다.

이것은 이전 답변에서 @trev에 의해 지적되었습니다.

이를 수동으로 시뮬레이션하려면 uid를 4로 설정하면 나중에 "충돌"됩니다.

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

테이블 데이터 :

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

다른 인서트를 실행하십시오.

INSERT INTO table1 (col_b) VALUES(6);

테이블 데이터 :

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

이제 다른 인서트를 실행하면 :

INSERT INTO table1 (col_b) VALUES(7);

다음과 같은 오류 메시지와 함께 실패합니다.

오류 : 중복 키 값이 고유 제한 조건 "table1_pkey"을 위반합니다. 세부 사항 : 키 (uid) = (5)이 (가) 이미 존재합니다.

대조적으로, MySQL은 아래와 같이 이것을 정상적으로 처리합니다.

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

이제 uid를 설정하지 않고 다른 행을 삽입하십시오.

INSERT INTO table1 (col_b) VALUES(3);

쿼리가 실패하지 않고 uid는 5로 이동합니다.

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

테스트는 Linux (x86_64) 및 PostgreSQL 9.4.9 용 MySQL 5.6.33에서 수행되었습니다.


10
당신은 비교를하고 있지만 여기에 해결책이 없습니다! 답입니까?
Anwar

4
@Anwar은 단순히 일련의 / 시퀀스를 사용한다는 답변을 나타내는 다양한 답변을 확장합니다. 이것은 고려해야 할 몇 가지 중요한 컨텍스트를 제공합니다.
Programster

38

Postgres 10부터는 SQL 표준에 정의 된 자격 증명 열도 지원됩니다.

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

명시 적으로 요청하지 않으면 재정의 할 수없는 ID 열을 만듭니다. 다음과 같이 정의 된 열이 있으면 다음 삽입에 실패합니다 generated always.

insert into foo (id) 
values (1);

그러나 이것은 무시 될 수 있습니다 :

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

옵션을 사용할 때 generated by default이것은 본질적으로 기존 serial구현 과 동일한 동작입니다 .

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

값을 수동으로 제공하는 경우 기본 순서도 serial열과 마찬가지로 수동으로 조정해야 합니다.


ID 열은 기본적으로 기본 키가 아닙니다 ( serial열과 마찬가지로 ). 하나 여야하는 경우 기본 키 제약 조건을 수동으로 정의해야합니다.


26

죄송합니다. 이전 질문을 다시 해시지만 Google에서 처음으로 발생한 스택 오버플로 질문 / 답변입니다.

이 게시물 (Google에서 처음으로 올라온)은 PostgreSQL 10에 대해 더 업데이트 된 구문 사용에 대해 설명합니다. https://blog.2ndquadrant.com/postgresql-10-identity-columns/

어떤 일이 발생합니까?

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

희망이 있습니다 :)


1
이것은 실제로 PostgreSQL 10에 들어가는 방법이며 DB2 또는 Oracle과 같은 다른 데이터베이스 소프트웨어와 동일한 구문입니다.
adriaan

1
@adriaan 실제로 GENERATED … AS IDENTITY명령은 표준 SQL입니다. SQL : 2003 에서 처음 추가 된 후 SQL : 2008 에서 명확 해졌습니다 . 기능 # T174 & F386 & T178을 참조하십시오.
Basil Bourque

16

SERIAL 또는 시퀀스 필드에 직접 삽입하지 않도록주의해야합니다. 그렇지 않으면 시퀀스가 ​​삽입 된 값에 도달하면 쓰기가 실패합니다.

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

@ sereja1c에 의한 질문과 문맥에 따라 SERIAL암시 적으로 시퀀스를 생성하므로 위의 예에서

CREATE TABLE foo (id SERIAL,bar varchar);

CREATE TABLEfoo_id_seq직렬 열에 대한 시퀀스 를 암시 적으로 만듭니다 foo.id. 따라서 SERIAL[4 바이트]는 ID에 특정 데이터 유형이 필요하지 않으면 사용하기 편리합니다.


3

이 방법은 확실히 작동합니다. 도움이되기를 바랍니다.

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

다음 링크에서 세부 사항을 확인할 수 있습니다. http://www.postgresqltutorial.com/postgresql-serial/


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.