Postgres 9.0 데이터베이스에 현재 1부터 시작하는 고유 한 순차 정수가 포함되어 있지만 'serial'키워드를 사용하여 생성되지 않은 정수 ID 필드 (기본 키)가있는 작은 테이블 (~ 30 행)이 있습니다.
지금부터이 테이블에 삽입 할 때이 필드가 유형으로 'serial'을 사용하여 생성 된 것처럼 작동하도록이 테이블을 어떻게 변경할 수 있습니까?
Postgres 9.0 데이터베이스에 현재 1부터 시작하는 고유 한 순차 정수가 포함되어 있지만 'serial'키워드를 사용하여 생성되지 않은 정수 ID 필드 (기본 키)가있는 작은 테이블 (~ 30 행)이 있습니다.
지금부터이 테이블에 삽입 할 때이 필드가 유형으로 'serial'을 사용하여 생성 된 것처럼 작동하도록이 테이블을 어떻게 변경할 수 있습니까?
답변:
다음 명령 (특히 주석이 달린 블록)을보십시오.
DROP TABLE foo;
DROP TABLE bar;
CREATE TABLE foo (a int, b text);
CREATE TABLE bar (a serial, b text);
INSERT INTO foo (a, b) SELECT i, 'foo ' || i::text FROM generate_series(1, 5) i;
INSERT INTO bar (b) SELECT 'bar ' || i::text FROM generate_series(1, 5) i;
-- blocks of commands to turn foo into bar
CREATE SEQUENCE foo_a_seq;
ALTER TABLE foo ALTER COLUMN a SET DEFAULT nextval('foo_a_seq');
ALTER TABLE foo ALTER COLUMN a SET NOT NULL;
ALTER SEQUENCE foo_a_seq OWNED BY foo.a; -- 8.2 or later
SELECT MAX(a) FROM foo;
SELECT setval('foo_a_seq', 5); -- replace 5 by SELECT MAX result
INSERT INTO foo (b) VALUES('teste');
INSERT INTO bar (b) VALUES('teste');
SELECT * FROM foo;
SELECT * FROM bar;
ALTER TABLE foo ADD PRIMARY KEY (a)
.
ALTER TABLE foo OWNER TO current_user;
먼저 수행해야합니다 .
MAX(a)+1
setval에서 설정해야하지 않습니까? SELECT MAX(a)+1 FROM foo; SELECT setval('foo_a_seq', 6);
다음은 값을 읽고 직접 입력하는 데 사람이 필요하지 않은 버전입니다.
CREATE SEQUENCE foo_a_seq OWNED BY foo.a;
SELECT setval('foo_a_seq', coalesce(max(a), 0) + 1, false) FROM foo;
ALTER TABLE foo ALTER COLUMN a SET DEFAULT nextval('foo_a_seq');
또 다른 옵션은 Function
이 답변의 끝에 재사용 가능한 공유 를 사용하는 것입니다.
예를 들어 라이브 DB를 패치하는 동안 비 대화 형 스크립트로Sequence
생성 해야하는 사람들을 위해 다른 두 답변에 추가하는 것입니다 .
즉, SELECT
값을 수동으로 입력 하고 싶지 않을 때 다음 CREATE
문에 직접 입력합니다 .
요컨대 다음을 할 수 없습니다 .
CREATE SEQUENCE foo_a_seq
START WITH ( SELECT max(a) + 1 FROM foo );
...의 START [WITH]
절이 하위 쿼리가 아닌 값 을 CREATE SEQUENCE
기대하기 때문 입니다.
주 : (모든 비 CRUD에 적용 엄지 손가락의 규칙으로서, 예 : 이외의
INSERT
,SELECT
,UPDATE
,DELETE
의 문) pgSQL의 AFAIK.
그러나 setval()
그렇습니다! 따라서 다음은 절대적으로 좋습니다.
SELECT setval('foo_a_seq', max(a)) FROM foo;
데이터가없고 그것에 대해 알지 못하는 경우 (원하는)을 사용 coalesce()
하여 기본값을 설정하십시오.
SELECT setval('foo_a_seq', coalesce(max(a), 0)) FROM foo;
-- ^ ^ ^
-- defaults to: 0
그러나 현재 시퀀스 값을로 설정하는 0
것은 불법이 아니라면 어색합니다.
3 개 매개 변수 형식을 사용하는 setval
것이 더 적절합니다.
-- vvv
SELECT setval('foo_a_seq', coalesce(max(a), 0) + 1, false) FROM foo;
-- ^ ^
-- is_called
setval
to 의 선택적 세 번째 매개 변수를 설정하면 값을 반환하기 전에 false
다음 매개 변수가 nextval
시퀀스를 진행 하지 못하므로 다음 을 수행합니다.
다음
nextval
은 지정된 값을 정확하게 반환하고 시퀀스 진행은 다음과 함께 시작됩니다nextval
.
관련되지 않은 메모에서를 사용하여 Sequence
직접 소유하는 열을 지정할 수도 있으며 CREATE
나중에 변경할 필요가 없습니다.
CREATE SEQUENCE foo_a_seq OWNED BY foo.a;
요약해서 말하자면:
CREATE SEQUENCE foo_a_seq OWNED BY foo.a;
SELECT setval('foo_a_seq', coalesce(max(a), 0) + 1, false) FROM foo;
ALTER TABLE foo ALTER COLUMN a SET DEFAULT nextval('foo_a_seq');
Function
또는 여러 열에 대해이 작업을 계획하는 경우 실제 Function
.
CREATE OR REPLACE FUNCTION make_into_serial(table_name TEXT, column_name TEXT) RETURNS INTEGER AS $$
DECLARE
start_with INTEGER;
sequence_name TEXT;
BEGIN
sequence_name := table_name || '_' || column_name || '_seq';
EXECUTE 'SELECT coalesce(max(' || column_name || '), 0) + 1 FROM ' || table_name
INTO start_with;
EXECUTE 'CREATE SEQUENCE ' || sequence_name ||
' START WITH ' || start_with ||
' OWNED BY ' || table_name || '.' || column_name;
EXECUTE 'ALTER TABLE ' || table_name || ' ALTER COLUMN ' || column_name ||
' SET DEFAULT nextVal(''' || sequence_name || ''')';
RETURN start_with;
END;
$$ LANGUAGE plpgsql VOLATILE;
다음과 같이 사용하십시오.
INSERT INTO foo (data) VALUES ('asdf');
-- ERROR: null value in column "a" violates not-null constraint
SELECT make_into_serial('foo', 'a');
INSERT INTO foo (data) VALUES ('asdf');
-- OK: 1 row(s) affected
coalesce(max(a), 0))
대부분의 경우 Ids가 1부터 시작하므로 대부분의 경우 작동하지 않습니다. 더 정확한 방법은 다음과 같습니다coalesce(max(a), 1))
currval
는 절대해서는 안됩니다 0
. 세 매개 변수 형식을 사용하는 setval
것이 더 적절할 것 setval(..., coalesce(max(a), 0) + 1, false)
입니다.. 그에 따라 답변이 업데이트되었습니다!
SERIAL
가상 유형은 이제 레거시 이며 Postgres 10 이상 에서 SQL : 2003에 정의 된 새로운GENERATED … AS IDENTITY
기능으로 대체되었습니다 . 설명을 참조하십시오 .