2011-01-13 23 views
62

Tôi có một bảng có hơn một triệu hàng. Tôi cần phải thiết lập 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 đó không?Làm thế nào để thiết lập lại chuỗi trong postgres và điền vào cột id với dữ liệu mới?

+4

Câu hỏi thực sự: tại sao trên trái đất bạn sẽ 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à giá trị vô nghĩa (trong trường hợp của bạn). "Renumbering" nó không phục vụ bất kỳ mục đích hợp lý nào trong một cơ sở dữ liệu quan hệ. –

+0

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 'id' đã không bắt đầu từ 1. Vì vậy, thứ tự hóa ra như sau: 150, 151 ..., 300, 1, 2 ... Và nó sẽ gây ra lỗi trùng lặp id cuối cùng tôi cho rằng, nếu tôi đã không không đổi tên các id. Ngoài ra, thứ tự bằng 'id' thường tốt hơn lệnh' created_at'. Và đây là [những gì làm việc cho tôi] (http://gbif.blogspot.com/2011/06/ordered-updates-with-postgres.html). –

Trả lời

96

Nếu bạn không muốn giữ lại thứ tự của id, sau đó 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ự của sự lựa chọn của bạn mà không tái tạo lại toàn bộ bảng.

+1

Không nên là 'ALTER SEQUENCE seq RESTART WITH 1;'? –

+0

@LarsHaugseth, tôi nghĩ bạn nói đúng. –

+4

Đ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ả các giá trị rất cao: UPDATE t SET idcolumn = 1000000 + nextval ('seq'); sau đó chạy tập lệnh trên. – tahagh

28

Thiết lập lại trình tự:

SELECT setval('sequence_name', 0); 

Đang cập nhật hồ sơ hiện tại:

UPDATE foo SET id = DEFAULT; 
12

Cả hai giải pháp được 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ố với 2, và ALTER SEQUENCE seq START 1 bắt đầu đánh số với 2 là tốt, vì seq.is_called là đúng (Postgres phiên bản 9.0.4)

Các giải pháp mà làm việc đối với tôi là:

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

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

20

Với PostgreSQL 8.4 hoặc mới hơn, không cần phải chỉ định WITH 1 nữa. Giá trị bắt đầu được ghi lại bởi CREATE SEQUENCE hoặc thiết lập cuối cùng bởi ALTER SEQUENCE START WITH sẽ được sử dụng (hầu hết có thể đây sẽ là 1).

Thiết lập 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: PostgreSQL Docs

0

Nếu bạn đang sử dụng pgAdmin3, mở rộng 'Trình tự, nghe tiếng' click chuột phải vào một chuỗi, chuyển đế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 truy vấn.

+3

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

+3

Đây là cách dễ nhất, rõ ràng là tôi nghĩ anh ấy đang nói pg admin 3 – MvcCmsJon

4

FYI: Nếu bạn cần phải xác định một startvalue mới giữa một loạt các ID (256 - ví dụ 10000000):

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

Để duy trì trật 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; 
1

Chỉ cần đặt lại trình tự 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 các bản sao, sau đó với các id bạn thực sự muốn.

Vui lòng tránh thêm số tiền cố định vào tất cả các id (như được đề xuất trong các nhận xét khác). Điều gì sẽ 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 dãy là cao hơn tất cả các id của các hàng hiện có (bạn chỉ muốn lấp đầy những khoảng trống), tôi sẽ làm điều đó như:

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

Lấy cảm hứng từ câu trả lời khác ở đây, tôi đã tạo ra một SQL chức năng để làm một di chuyển chuỗi. Hàm di chuyển một chuỗi khóa chính đến một chuỗi liên tiếp mới bắt đầu với 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 here cách tôi sử dụng chức năng này khi di chuyển hai cơ sở dữ liệu với cùng một lược đồ nhưng các giá trị khác nhau vào một cơ sở dữ liệu.

Thứ nhất, chức năng (trong đó in SQL tạo ra các lệnh để nó là 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; 

Chức năng migrate_pkey_sequence mất các đối số sau đây:

  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 đây:

  1. Move các giá trị khóa chính cho một phạm vi miễn phí. Tôi giả định rằng nextval('example_id_seq') theo sau max(id) và trình tự bắt đầu với 1. Điều này cũng xử lý trường hợp 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ị khóa được bảo tồn nhưng các lỗ trong phạm vi không được giữ nguyên.
  3. In giá trị tiếp theo sẽ theo sau trong chuỗi. Điều này 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 một cột này.

Để minh hoạ, 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 ta chèn một số giá trị (bắt đầu, ví dụ, ở mức 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 giá trị example.id để 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) 
6

Chỉ cần đơn giản hóa và làm rõ việc sử dụng thích hợp của ALTER SEQUENCECHỌN setval để đặt lại trình tự:

ALTER SEQUENCE sequence_name RESTART WITH 1; 

tương đương với

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

Một trong những điều khoản có thể được sử dụng để thiết lập lại trình tự và bạn có thể nhận được giá trị tiếp theo bằng cách NEXTVAL ('sequence_name') như đã nêu here thêm:

nextval('sequence_name') 
+0

Cảm ơn Ali. Tôi đã chỉ nhận thấy nó rất quan trọng để thiết lập rằng tham số thứ 3 sai với hàm setval – DavidHyogo

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; 

đâu bàn của tôi được đặt tên bảng

+0

Cảm ơn bạ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 hơi quá mơ hồ. –

2

cách tốt nhất để thiết lập lại một chuỗi để bắt đầu b ack 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 sử dụng nó sẽ là:

ALTER SEQUENCE users_id_seq RESTART WITH 1 
Các vấn đề liên quan