Terinspirasi oleh jawaban lain di sini, saya membuat fungsi SQL untuk melakukan migrasi urutan. Fungsi ini memindahkan urutan kunci primer ke urutan baru yang berdekatan yang dimulai dengan nilai apa pun (> = 1) baik di dalam maupun di luar rentang urutan yang ada.
Saya menjelaskan di sini bagaimana saya menggunakan fungsi ini dalam migrasi dua database dengan skema yang sama tetapi nilai berbeda ke dalam satu database.
Pertama, fungsinya (yang mencetak perintah SQL yang dihasilkan sehingga jelas apa yang sebenarnya terjadi):
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;
Fungsi tersebut migrate_pkey_sequence
mengambil argumen berikut:
arg_table
: nama tabel (mis. 'example'
)
arg_column
: nama kolom kunci utama (mis 'id'
)
arg_sequence
: nama urutan (misalnya 'example_id_seq'
)
arg_next_value
: nilai berikutnya untuk kolom setelah migrasi
Itu melakukan operasi berikut:
- Pindahkan nilai kunci utama ke rentang bebas. Saya berasumsi bahwa
nextval('example_id_seq')
berikut max(id)
dan urutannya dimulai dengan 1. Ini juga menangani kasus di mana arg_next_value > max(id)
.
- Pindahkan nilai kunci utama ke rentang bersebelahan yang dimulai dengan
arg_next_value
. Urutan nilai kunci dipertahankan tetapi lubang pada kisaran tidak dipertahankan.
- Cetak nilai berikutnya yang akan mengikuti urutan. Ini berguna jika Anda ingin memindahkan kolom dari tabel lain dan menggabungkannya dengan yang satu ini.
Untuk mendemonstrasikan, kami menggunakan urutan dan tabel yang ditentukan sebagai berikut (misalnya menggunakan 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)
);
Kemudian, kami memasukkan beberapa nilai (mulai, misalnya, pada 3):
# ALTER SEQUENCE example_id_seq RESTART WITH 3;
# INSERT INTO example VALUES (DEFAULT), (DEFAULT), (DEFAULT);
-- id: 3, 4, 5
Terakhir, kami memigrasi example.id
nilai untuk memulai dengan 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)
Hasil:
# SELECT * FROM example;
id
----
1
2
3
(3 rows)