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_sequence
lấy các đối số sau:
arg_table
: tên bảng (ví dụ 'example'
)
arg_column
: tên cột khóa chính (ví dụ 'id'
)
arg_sequence
: tên trình tự (ví dụ 'example_id_seq'
)
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:
- 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)
.
- 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.
- 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.id
giá 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)