100万行を超えるテーブルがあります。シーケンスをリセットし、新しい値(1、2、3、4 ...など)でid列を再割り当てする必要があります。それを行う簡単な方法はありますか?
IDの順序を保持したくない場合は、次のことができます。
ALTER SEQUENCE seq RESTART WITH 1;
UPDATE t SET idcolumn=nextval('seq');
テーブル全体を再作成せずに、選択した順序でそれを行う簡単な方法があるとは思いません。
シーケンスをリセットします。
SELECT setval('sequence_name', 0);
現在のレコードの更新:
UPDATE foo SET id = DEFAULT;
PostgreSQL 8.4以降では、WITH 1
を指定する必要がなくなりました。 CREATE SEQUENCE
によって記録された開始値またはALTER SEQUENCE START WITH
によって最後に設定された開始値が使用されます(ほとんどの場合、これは1になります)。
シーケンスをリセットします。
ALTER SEQUENCE seq RESTART;
次に、テーブルのID列を更新します。
UPDATE foo SET id = DEFAULT;
ソース: PostgreSQL Docs
提供されたソリューションはどちらも私にとってはうまくいきませんでした。
> 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 1
は2から番号付けを開始します。これは、seq.is_calledが真であるためです(Postgresバージョン9.0.4)
私のために働いた解決策は次のとおりです。
> ALTER SEQUENCE seq RESTART WITH 1;
> UPDATE foo SET id = DEFAULT;
ALTER SEQUENCEおよびSELECT setvalの適切な使用法を単純化および明確化するためだけにシーケンスをリセットするため:
ALTER SEQUENCE sequence_name RESTART WITH 1;
に等しい
SELECT setval('sequence_name', 1, FALSE);
いずれかのステートメントを使用してシーケンスをリセットでき、次のようにnextval( 'sequence_name')で次の値を取得できます here また:
nextval('sequence_name')
シーケンスをリセットして番号1から開始する最良の方法は、次を実行することです。
ALTER SEQUENCE <tablename>_<id>_seq RESTART WITH 1
したがって、たとえばユーザーテーブルの場合は次のようになります。
ALTER SEQUENCE users_id_seq RESTART WITH 1
参考:IDの範囲(たとえば256〜10000000)の間に新しい開始値を指定する必要がある場合:
SELECT setval('"Sequence_Name"',
(SELECT coalesce(MAX("ID"),255)
FROM "Table_Name"
WHERE "ID" < 10000000 and "ID" >= 256)+1
);
行の順序を保持するには:
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;
シーケンスをリセットしてすべての行を更新するだけで、IDの重複エラーが発生する場合があります。多くの場合、すべての行を2回更新する必要があります。最初に重複を避けるために高いIDを使用し、次に実際に必要なIDを使用します。
(他のコメントで推奨されているように)すべてのIDに固定金額を追加することは避けてください。この固定量よりも多くの行がある場合はどうなりますか?シーケンスの次の値が既存の行のすべてのID(ギャップを埋めるだけ)よりも高いと仮定すると、次のようになります。
UPDATE table SET id = DEFAULT;
ALTER SEQUENCE seq RESTART;
UPDATE table SET id = DEFAULT;
私の場合、次の方法でこれを達成しました。
ALTER SEQUENCE table_tabl_id_seq RESTART WITH 6;
私のテーブルの名前はtableです
自動インクリメント列でもPKではありません(この例ではseq-別名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();
ここの他の回答に触発されて、シーケンス移行を行うためのSQL関数を作成しました。この関数は、主キーシーケンスを、既存のシーケンス範囲の内側または外側のいずれかの値(> = 1)で始まる新しい連続したシーケンスに移動します。
こちら 同じスキーマで異なる値を持つ2つのデータベースを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
は次の引数を取ります。
arg_table
:テーブル名(例:'example'
)arg_column
:主キー列名(例:'id'
)arg_sequence
:シーケンス名(例:'example_id_seq'
)arg_next_value
:移行後の列の次の値次の操作を実行します。
nextval('example_id_seq')
がmax(id)
に続き、シーケンスが1で始まると仮定します。これは、arg_next_value > max(id)
の場合も処理します。arg_next_value
で始まる連続した範囲に主キー値を移動します。キー値の順序は保持されますが、範囲内の穴は保持されません。実証するために、次のように定義されたシーケンスとテーブルを使用します(例: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)