Postgres에서 시퀀스를 재설정하고 ID 열을 새 데이터로 채우는 방법은 무엇입니까?


126

백만 개가 넘는 행이있는 테이블이 있습니다. 시퀀스를 재설정하고 새 값 (1, 2, 3, 4 ... 등)으로 id 열을 다시 할당해야합니다. 그렇게하는 쉬운 방법이 있습니까?


6
진짜 질문 : 도대체 왜 그렇게하고 싶습니까? 아마도 ID는 기본 키이므로 기본 키를 변경해도 아무런 이점이 없습니다. 기본 키는 의미가없는 (귀하의 경우 인공) 값입니다. "번호 다시 매기기"는 관계형 데이터베이스에서 합리적인 목적을 제공하지 않습니다.
a_horse_with_no_name

2
처음에는 로컬에서 앱을 실행 한 다음 데이터를 프로덕션에 복사했습니다. 그러나 id1부터 시작하지 않았습니까? 그래서 순서는 다음과 같이 밝혀졌습니다 : 150, 151 ..., 300, 1, 2 ... 그리고 그것은 결국 중복 ID 오류를 일으킬 것입니다. ID. 또한 order by id가 일반적으로 order by보다 낫습니다 created_at. 그리고 여기 저에게 효과적이었습니다 .
x-yuri 2015 년

이 작업의 요점은 순차 키를 계속 증가시키면서 새 데이터를 지속적으로받는 데이터베이스의 기본 키에 bigint 대신 일반 int를 계속 사용할 수 있도록하는 것입니다. 부호있는 정수 제한에 빠르게 도달 할 수 있으며 기존 ID를 유지하는 것이 중요하지 않은 경우이 프로세스를 통해 관리 가능한 ID 번호로 돌아갑니다.
Ben Wilson

이것에 대한 또 다른 용도는 테스트입니다. 각 테스트를 시작하기 전에 테이블을 알려진 상태로 재설정하려고하며 ID를 재설정해야합니다.
Safa Alai

답변:


203

ID의 순서를 유지하지 않으려면 다음을 수행 할 수 있습니다.

ALTER SEQUENCE seq RESTART WITH 1;
UPDATE t SET idcolumn=nextval('seq');

전체 테이블을 다시 만들지 않고 선택한 순서대로 쉽게 수행 할 수있는 방법이 없을 것 같습니다.


4
ALTER SEQUENCE seq RESTART WITH 1;그래?
Lars Haugseth 2013

5
이로 인해 중복 ID가 발생할 수 있습니다. 이를 방지하려면 먼저 모두를 매우 높은 값으로 설정할 수 있습니다. UPDATE t SET idcolumn = 1000000 + nextval ( 'seq'); 그런 다음 위의 스크립트를 실행하십시오.
tahagh

5
SELECT setval('seq', 1, FALSE)똑같이해야합니다 (여기서 세 번째 인수 인 FALSE nextval는 2 대신 1이어야 함을 보여주기 때문에 마술을 합니다)
Vasilen Donchev

@VassilenDontchev, 절대적으로.
Michael Krelin-해커

55

PostgreSQL 8.4 WITH 1이상 에서는 더 이상 지정할 필요가 없습니다. 에 의해 기록 CREATE SEQUENCE되었거나 마지막에 설정된 시작 값이 ALTER SEQUENCE START WITH사용됩니다 (대부분 1이 될 것입니다).

순서 재설정 :

ALTER SEQUENCE seq RESTART;

그런 다음 테이블의 ID 열을 업데이트합니다.

UPDATE foo SET id = DEFAULT;

출처 : PostgreSQL 문서


3
이것은 시퀀스의 시작 값에 대한 가정을 피할 수 있기 때문에 가장 좋은 대답처럼 보입니다.
sheepdog

내 사건에 대한 최고의 답변입니다. 나는이 답변을 결합 이 하나의 I에 의해 '서열'을 변경할 수 있도록 ...는 ALTER SEQUENCE 명령을 설명하고, mytable_id_seq 'MYTABLE은'내 테이블 이름과 '아이디'내 시리얼 컬럼의 이름입니다
하비

42

순서 재설정 :

SELECT setval('sequence_name', 0);

현재 기록 업데이트 :

UPDATE foo SET id = DEFAULT;

3
순서는 0보다 최소 값보다가 (종류에 따라 사용 및 디폴트의 최소 값을 수 serialCREATE SEQUENCE1입니다!)
BRK

18

제공된 두 솔루션 모두 저에게 효과적이지 않았습니다.

> SELECT setval('seq', 0);
ERROR:  setval: value 0 is out of bounds for sequence "seq" (1..9223372036854775807)

setval('seq', 1)2 번호 매기기를 시작하고, ALTER SEQUENCE seq START 1seq.is_called 사실이기 때문에,뿐만 아니라 2 번호 매기기를 시작 (포스트 그레스 버전 9.0.4)

나를 위해 일한 솔루션은 다음과 같습니다.

> ALTER SEQUENCE seq RESTART WITH 1;
> UPDATE foo SET id = DEFAULT;

1
여기에도 같은 문제가 있습니다. 솔루션은 PostgreSQL 8.3.10에서도 작동합니다.
PeqNP

17

시퀀스 재설정을 위해 ALTER SEQUENCESELECT setval 의 적절한 사용을 단순화하고 명확하게하기 위해 :

ALTER SEQUENCE sequence_name RESTART WITH 1;

다음과 같다

SELECT setval('sequence_name', 1, FALSE);

명령문 중 하나를 사용하여 시퀀스를 재설정 할 수 있으며 여기에 설명 된대로 nextval ( 'sequence_name')으로 다음 값을 얻을 수 있습니다.

nextval('sequence_name')

고마워 알리. 난 그냥이 setval에 기능을 false로 그 세번째 매개 변수를 설정하는 것이 중요입니다 나타났습니다
DavidHyogo

14

시퀀스를 재설정하여 번호 1로 다시 시작하는 가장 좋은 방법은 다음을 실행하는 것입니다.

ALTER SEQUENCE <tablename>_<id>_seq RESTART WITH 1

예를 들어 사용자 테이블의 경우 다음과 같습니다.

ALTER SEQUENCE users_id_seq RESTART WITH 1

6

행 순서를 유지하려면 다음을 수행하십시오.

UPDATE thetable SET rowid=col_serial FROM 
(SELECT rowid, row_number() OVER ( ORDER BY lngid) AS col_serial FROM thetable ORDER BY lngid) AS t1 
WHERE thetable.rowid=t1.rowid;

4

참고 : ID 범위 (예 : 256-10000000) 사이에 새 시작 값을 지정해야하는 경우 :

SELECT setval('"Sequence_Name"', 
       (SELECT coalesce(MAX("ID"),255) 
           FROM "Table_Name" 
           WHERE "ID" < 10000000 and "ID" >= 256)+1
       ); 

2

시퀀스를 재설정하고 모든 행을 업데이트하면 중복 ID 오류가 발생할 수 있습니다. 대부분의 경우 모든 행을 두 번 업데이트해야합니다. 먼저 중복을 피하기 위해 더 높은 ID를 사용하고 실제로 원하는 ID를 사용하십시오.

모든 ID에 고정 금액을 추가하지 마십시오 (다른 의견에서 권장 됨). 이 고정 된 양보다 많은 행이 있으면 어떻게됩니까? 시퀀스의 다음 값이 기존 행의 모든 ​​ID보다 높다고 가정하면 (단지 간격을 채우고 싶음) 다음과 같이 처리합니다.

UPDATE table SET id = DEFAULT;
ALTER SEQUENCE seq RESTART;
UPDATE table SET id = DEFAULT;


0

여기의 다른 답변에서 영감을 받아 시퀀스 마이그레이션을 수행하는 SQL 함수를 만들었습니다. 이 함수는 기본 키 시퀀스를 기존 시퀀스 범위 내부 또는 외부의 값 (> = 1)으로 시작하는 새 연속 시퀀스로 이동합니다.

여기서는 스키마가 같지만 값이 다른 두 데이터베이스를 하나의 데이터베이스로 마이그레이션 할 때이 함수를 사용하는 방법을 설명 합니다.

첫째, 함수 (생성 된 SQL 명령을 인쇄하여 실제로 무슨 일이 일어나고 있는지 명확하게 나타냄) :

CREATE OR REPLACE FUNCTION migrate_pkey_sequence
  ( arg_table      text
  , arg_column     text
  , arg_sequence   text
  , arg_next_value bigint  -- Must be >= 1
  )
RETURNS int AS $$
DECLARE
  result int;
  curr_value bigint = arg_next_value - 1;
  update_column1 text := format
    ( 'UPDATE %I SET %I = nextval(%L) + %s'
    , arg_table
    , arg_column
    , arg_sequence
    , curr_value
    );
  alter_sequence text := format
    ( 'ALTER SEQUENCE %I RESTART WITH %s'
    , arg_sequence
    , arg_next_value
    );
  update_column2 text := format
    ( 'UPDATE %I SET %I = DEFAULT'
    , arg_table
    , arg_column
    );
  select_max_column text := format
    ( 'SELECT coalesce(max(%I), %s) + 1 AS nextval FROM %I'
    , arg_column
    , curr_value
    , arg_table
    );
BEGIN
  -- Print the SQL command before executing it.
  RAISE INFO '%', update_column1;
  EXECUTE update_column1;
  RAISE INFO '%', alter_sequence;
  EXECUTE alter_sequence;
  RAISE INFO '%', update_column2;
  EXECUTE update_column2;
  EXECUTE select_max_column INTO result;
  RETURN result;
END $$ LANGUAGE plpgsql;

이 함수 migrate_pkey_sequence는 다음 인수를 사용합니다.

  1. arg_table: 테이블 이름 (예를 들어 'example')
  2. arg_column: 기본 키 열 이름 (예를 들어 'id')
  3. arg_sequence: 시퀀스 이름 (예를 들어 'example_id_seq')
  4. arg_next_value: 마이그레이션 후 열의 다음 값

다음 작업을 수행합니다.

  1. 기본 키 값을 자유 범위로 이동합니다. 나는 nextval('example_id_seq')다음과 같다고 가정한다 max(id) 과 하고 시퀀스가 ​​1로 시작 . 이것은 또한 arg_next_value > max(id).
  2. 다음으로 시작하는 연속 범위로 기본 키 값을 이동합니다. arg_next_value . 키 값의 순서는 유지되지만 범위의 구멍은 유지되지 않습니다.
  3. 순서에 따라 다음 값을 인쇄하십시오. 이것은 다른 테이블의 열을 마이그레이션하고이 테이블과 병합하려는 경우 유용합니다.

설명하기 위해 다음과 같이 정의 된 시퀀스 및 테이블을 사용합니다 (예 : 사용 psql).

# CREATE SEQUENCE example_id_seq
  START WITH 1
  INCREMENT BY 1
  NO MINVALUE
  NO MAXVALUE
  CACHE 1;
# CREATE TABLE example
  ( id bigint NOT NULL DEFAULT nextval('example_id_seq'::regclass)
  );

그런 다음 몇 가지 값을 삽입합니다 (예 : 3에서 시작).

# ALTER SEQUENCE example_id_seq RESTART WITH 3;
# INSERT INTO example VALUES (DEFAULT), (DEFAULT), (DEFAULT);
-- id: 3, 4, 5

마지막으로 example.id값을 1로 시작하도록 마이그레이션합니다 .

# SELECT migrate_pkey_sequence('example', 'id', 'example_id_seq', 1);
INFO:  00000: UPDATE example SET id = nextval('example_id_seq') + 0
INFO:  00000: ALTER SEQUENCE example_id_seq RESTART WITH 1
INFO:  00000: UPDATE example SET id = DEFAULT
 migrate_pkey_sequence
-----------------------
                     4
(1 row)

결과:

# SELECT * FROM example;
 id
----
  1
  2
  3
(3 rows)

0

자동 증가 열조차도 PK가 아닙니다 (이 예에서는 seq-aka sequence라고 함). 트리거를 사용하여 달성 할 수 있습니다.

테이블이있는 경우 삭제 devops_guide CASCADE;

SELECT 'create the "devops_guide" table'
;
   CREATE TABLE devops_guide (
      guid           UUID NOT NULL DEFAULT gen_random_uuid()
    , level          integer NULL
    , seq            integer NOT NULL DEFAULT 1
    , name           varchar (200) NOT NULL DEFAULT 'name ...'
    , description    text NULL
    , CONSTRAINT pk_devops_guide_guid PRIMARY KEY (guid)
    ) WITH (
      OIDS=FALSE
    );

-- START trg_devops_guide_set_all_seq
CREATE OR REPLACE FUNCTION fnc_devops_guide_set_all_seq()
    RETURNS TRIGGER
    AS $$
       BEGIN
         UPDATE devops_guide SET seq=col_serial FROM
         (SELECT guid, row_number() OVER ( ORDER BY seq) AS col_serial FROM devops_guide ORDER BY seq) AS tmp_devops_guide
         WHERE devops_guide.guid=tmp_devops_guide.guid;

         RETURN NEW;
       END;
    $$ LANGUAGE plpgsql;

 CREATE TRIGGER trg_devops_guide_set_all_seq
  AFTER UPDATE OR DELETE ON devops_guide
  FOR EACH ROW
  WHEN (pg_trigger_depth() < 1)
  EXECUTE PROCEDURE fnc_devops_guide_set_all_seq();

-1

pgAdmin3을 사용하는 경우 '시퀀스'를 확장하고 시퀀스를 마우스 오른쪽 버튼으로 클릭 한 다음 '속성'으로 이동 한 다음 '정의'탭에서 '현재 값'을 원하는 값으로 변경합니다. 쿼리가 필요하지 않습니다.


3
사용중인 도구를 적어도 알려주지 않으면 귀하의 답변은 가치가 없습니다.
11101101b

3
이것이 가장 쉬운 방법입니다. 분명히 그가 pg admin 3
MvcCmsJon
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.