Làm cách nào để đặt lại chuỗi trong postgres và điền cột id với dữ liệu mới?


126

Tôi có một bảng với hơn triệu hàng. Tôi cần đặt lại chuỗi và gán lại cột id với các giá trị mới (1, 2, 3, 4 ... vv ...). Có cách nào dễ dàng để làm điều đó?


6
Câu hỏi thực sự: tại sao bạn muốn làm điều đó? Có lẽ ID là khóa chính, vì vậy không có lợi ích gì trong việc thay đổi khóa chính. Khóa chính là một giá trị vô nghĩa (trong trường hợp của bạn). "Làm mới" nó không phục vụ bất kỳ mục đích hợp lý nào trong cơ sở dữ liệu quan hệ.
a_horse_with_no_name

2
Ban đầu tôi có ứng dụng chạy cục bộ, sau đó tôi sao chép dữ liệu vào sản xuất. Nhưng idkhông có bắt đầu từ 1. Vì vậy, thứ tự được bật ra như sau: 150, 151 ..., 300, 1, 2 ... Và cuối cùng tôi sẽ gây ra lỗi id trùng lặp, nếu tôi không đánh số lại các id. Ngoài ra, thứ tự idthường tốt hơn so với thứ tự của created_at. Và đây là những gì làm việc cho tôi .
x-yuri

Mục đích của việc này là để bạn có thể tiếp tục sử dụng một int thông thường thay vì bigint cho khóa chính trong cơ sở dữ liệu tiếp tục tăng khóa tuần tự nhưng liên tục nhận dữ liệu mới. Bạn sẽ nhanh chóng chạy vào giới hạn số nguyên đã ký và nếu việc giữ lại id còn tồn tại không quan trọng, quy trình này sẽ đưa bạn trở lại số id có thể quản lý được.
Ben Wilson

Một cách sử dụng khác cho việc này là thử nghiệm. Bạn muốn đặt lại bảng về trạng thái đã biết trước khi bắt đầu mỗi bài kiểm tra và yêu cầu id phải được đặt lại.
Safa Alai

Câu trả lời:


203

Nếu bạn không muốn giữ lại thứ tự của id, thì bạn có thể

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

Tôi nghi ngờ có một cách dễ dàng để làm điều đó theo thứ tự bạn chọn mà không cần tạo lại toàn bộ bảng.


4
Có nên như ALTER SEQUENCE seq RESTART WITH 1;vậy không?
Lars Haugseth

5
Điều này có thể gây ra các id trùng lặp. Để ngăn chặn điều này, trước tiên bạn có thể đặt tất cả thành các giá trị rất cao: UPDATE t SET idcolumn = 1000000 + nextval ('seq'); sau đó chạy đoạn script trên.
tahagh

5
SELECT setval('seq', 1, FALSE)nên làm như vậy (ở đây, đối số thứ ba, FALSE, thực hiện phép thuật, vì nó cho thấy nextvalphải là 1 thay vì 2)
Vasilen Donchev

@VassilenDontchev, hoàn toàn.
Michael Krelin - hacker

55

Với PostgreSQL 8.4 trở lên, không cần chỉ định WITH 1nữa. Giá trị bắt đầu được ghi lại bởi CREATE SEQUENCEhoặc được đặt trước bởi ALTER SEQUENCE START WITHsẽ được sử dụng (rất có thể đây sẽ là 1).

Đặt lại trình tự:

ALTER SEQUENCE seq RESTART;

Sau đó cập nhật cột ID của bảng:

UPDATE foo SET id = DEFAULT;

Nguồn: Tài liệu PostgreSQL


3
Đây có vẻ như là câu trả lời tốt nhất vì nó tránh đưa ra các giả định về giá trị bắt đầu của chuỗi.
chó chăn cừu

Câu trả lời tốt nhất cho trường hợp của tôi quá. Tôi kết hợp câu trả lời này với câu trả lời này , nó giải thích lệnh ALTER SEQUENCE ... vì vậy tôi đã thay đổi 'seq' bởi mytable_id_seq trong đó 'mytable' là tên bảng của tôi và 'id' là tên của cột nối tiếp của tôi
Javi

42

Đặt lại trình tự:

SELECT setval('sequence_name', 0);

Cập nhật hồ sơ hiện tại:

UPDATE foo SET id = DEFAULT;

3
Trình tự có thể có giá trị tối thiểu lớn hơn 0. (Và giá trị tối thiểu mặc định được sử dụng theo loại serialCREATE SEQUENCElà 1!)
brk

18

Cả hai giải pháp cung cấp không làm việc cho tôi;

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

setval('seq', 1)bắt đầu đánh số bằng 2 và cũng ALTER SEQUENCE seq START 1bắt đầu đánh số bằng 2, vì seq.is_called là đúng (phiên bản Postgres 9.0.4)

Giải pháp hiệu quả với tôi là:

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

1
Cùng một vấn đề ở đây. Giải pháp của bạn cũng hoạt động cho PostgreSQL 8.3.10.
PeqNP

17

Chỉ để đơn giản hóa và làm rõ cách sử dụng đúng của ALTER SEQUENCESELECT setval để đặt lại chuỗi:

ALTER SEQUENCE sequence_name RESTART WITH 1;

tương đương với

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

Một trong hai câu lệnh có thể được sử dụng để đặt lại chuỗi và bạn có thể nhận giá trị tiếp theo theo nextval ('Sequ_name') như đã nêu ở đây :

nextval('sequence_name')

Cảm ơn Ali. Tôi vừa nhận thấy điều quan trọng là đặt tham số thứ 3 thành sai với hàm
setval

13

Cách tốt nhất để thiết lập lại một chuỗi để bắt đầu trở lại với số 1 là thực hiện như sau:

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

Vì vậy, ví dụ cho bảng người dùng, nó sẽ là:

ALTER SEQUENCE users_id_seq RESTART WITH 1

6

Để giữ thứ tự của các hàng:

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

FYI: Nếu bạn cần chỉ định một giá trị bắt đầu mới giữa một phạm vi ID (chẳng hạn 256 - 10000000):

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

2

Chỉ cần đặt lại chuỗi và cập nhật tất cả các hàng có thể gây ra lỗi id trùng lặp. Trong nhiều trường hợp, bạn phải cập nhật tất cả các hàng hai lần. Đầu tiên với id cao hơn để tránh trùng lặp, sau đó với id bạn thực sự muốn.

Vui lòng tránh để thêm một số tiền cố định cho tất cả các id (như được đề xuất trong các nhận xét khác). Điều gì xảy ra nếu bạn có nhiều hàng hơn số tiền cố định này? Giả sử giá trị tiếp theo của chuỗi cao hơn tất cả id của các hàng hiện có (bạn chỉ muốn lấp đầy các khoảng trống), tôi sẽ làm như sau:

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

1

Trong trường hợp của tôi, tôi đã đạt được điều này với:

ALTER SEQUENCE table_tabl_id_seq RESTART WITH 6;

Bảng của tôi được đặt tên bảng


Cảm ơn đã bao gồm một ví dụ cụ thể với tên bảng của bạn. Các câu trả lời khác là một chút quá mơ hồ.
Brylie Christopher Oxley

0

Lấy cảm hứng từ các câu trả lời khác ở đây, tôi đã tạo một hàm SQL để thực hiện di chuyển chuỗi. Hàm di chuyển một chuỗi khóa chính sang một chuỗi liền kề mới bắt đầu bằng bất kỳ giá trị nào (> = 1) ở bên trong hoặc bên ngoài phạm vi chuỗi hiện có.

Tôi giải thích ở đây cách tôi sử dụng hàm này trong việc di chuyển hai cơ sở dữ liệu có cùng lược đồ nhưng giá trị khác nhau vào một cơ sở dữ liệu.

Đầu tiên, hàm (in các lệnh SQL được tạo để rõ ràng những gì đang thực sự xảy ra):

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;

Hàm migrate_pkey_sequencelấy các đối số sau:

  1. arg_table: tên bảng (ví dụ 'example')
  2. arg_column: tên cột khóa chính (ví dụ 'id')
  3. arg_sequence: tên trình tự (ví dụ 'example_id_seq')
  4. arg_next_value: giá trị tiếp theo cho cột sau khi di chuyển

Nó thực hiện các hoạt động sau:

  1. Di chuyển các giá trị khóa chính đến một phạm vi miễn phí. Tôi giả sử như nextval('example_id_seq')sau max(id)và trình tự bắt đầu bằng 1. Điều này cũng xử lý trường hợp trong đó arg_next_value > max(id).
  2. Di chuyển các giá trị khóa chính sang phạm vi tiếp giáp bắt đầu bằng arg_next_value. Thứ tự của các giá trị chính được bảo tồn nhưng các lỗ trong phạm vi không được bảo tồn.
  3. In giá trị tiếp theo sẽ theo sau trong chuỗi. Điều này rất hữu ích nếu bạn muốn di chuyển các cột của bảng khác và hợp nhất với bảng này.

Để chứng minh, chúng tôi sử dụng một chuỗi và bảng được định nghĩa như sau (ví dụ: sử dụng 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)
  );

Sau đó, chúng tôi chèn một số giá trị (ví dụ: bắt đầu ở 3):

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

Cuối cùng, chúng tôi di chuyển các example.idgiá trị để bắt đầu bằng 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)

Kết quả:

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

0

Ngay cả cột tăng tự động không phải là PK (trong ví dụ này, nó được gọi là chuỗi seq - aka), bạn có thể đạt được điều đó với một trình kích hoạt:

BẢNG DROP NẾU EXISTS 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

Nếu bạn đang sử dụng pgAdmin3, hãy mở rộng 'Chuỗi,' nhấp chuột phải vào chuỗi, đi đến 'Thuộc tính' và trong tab 'Định nghĩa' thay đổi 'Giá trị hiện tại' thành bất kỳ giá trị nào bạn muốn. Không cần một truy vấn.


3
Câu trả lời của bạn không có giá trị nếu bạn ít nhất không cho chúng tôi biết bạn đang sử dụng công cụ nào.
11101101b

3
Đây là cách dễ nhất, rõ ràng tôi nghĩ anh ấy đang nói pg admin 3
MvcCmsJon
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.