postgresのシーケンスをリセットしてid列に新しいデータを入力する方法は?


126

100万行を超えるテーブルがあります。シーケンスをリセットし、id列を新しい値(1、2、3、4など)で再割り当てする必要があります。それを行う簡単な方法はありますか?


6
本当の質問:なぜ地球上でそれをしたいのですか?おそらくIDが主キーであるため、主キーを変更しても何のメリットもありません。主キーは無意味な(あなたの場合は人工的な)値です。「番号を付け直す」ことは、リレーショナルデータベースでの賢明な目的には役立ちません。
a_horse_with_no_name 2011年

2
最初はローカルでアプリを実行していたので、データを本番環境にコピーしました。しかしid、1から始まっていません。したがって、順序は次のようになりました:150、151 ...、300、1、2 ...そして、番号を付け直さなかった場合、最終的に重複IDエラーが発生すると思いますID。さらに、id通常、order by はorder by よりも優れていcreated_atます。そして、これが私のために働いたものです
x-yuri 2015年

これを行うポイントは、シーケンシャルキーをインクリメントし続けますが、常に新しいデータを受信するデータベースの主キーに対して、bigintの代わりに通常のintを引き続き使用できるようにするためです。すぐに符号付き整数の制限にぶつかります。現存するIDを保持することが重要でない場合は、このプロセスによって管理可能なID番号に戻ります。
ベンウィルソン

これのもう1つの用途はテストです。各テストを開始する前にテーブルを既知の状態にリセットし、IDをリセットする必要があります。
サファアライ

回答:


203

IDの順序を保持したくない場合は、

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

テーブル全体を再作成せずに、選択した順序でこれを行う簡単な方法はないと思います。


4
そうじゃないのALTER SEQUENCE seq RESTART WITH 1;
Lars Haugseth、2013

5
これにより、IDが重複する可能性があります。これを防ぐには、最初にすべてを非常に高い値に設定します。UPDATE t SET idcolumn = 1000000 + nextval( 'seq'); 次に、上記のスクリプトを実行します。
tahagh 2013年

5
SELECT setval('seq', 1, FALSE)同じことをするnextval必要があります(ここでは、3番目の引数FALSEがマジックを実行します。これは、2ではなく1 でなければならないことを示しています)
Vasilen Donchev

@VassilenDontchev、絶対に。
マイケルクレリン-ハッカー、2015年

55

PostgreSQL 8.4以降では、WITH 1もう指定する必要はありません。によって記録された、CREATE SEQUENCEまたは最後に設定された開始値ALTER SEQUENCE START WITHが使用されます(ほとんどの場合、これは1になります)。

シーケンスをリセットします。

ALTER SEQUENCE seq RESTART;

次に、テーブルのID列を更新します。

UPDATE foo SET id = DEFAULT;

出典:PostgreSQL Docs


3
これは、シーケンスの開始値に関する仮定を行わないため、最良の答えのようです。
シープドッグ

私の場合もベストアンサー。私はこの答えを組み合わせて、この1私がで「配列」を変えて... ALTER SEQUENCEコマンドを説明し、 mytable_id_seq「mytableは」の私のテーブル名と「ID」である私のシリアル列の名前です
ハビ

42

シーケンスをリセットします。

SELECT setval('sequence_name', 0);

現在のレコードの更新:

UPDATE foo SET id = DEFAULT;

3
シーケンスは、0よりも最小値も大きく持っている(そしてタイプで使用されるデフォルトの最小値を可能性serialCREATE SEQUENCE1です!)
BRK

18

提供された両方のソリューションは私にとってはうまくいきませんでした。

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

setval('seq', 1)ALTER SEQUENCE seq START 1seq.is_calledがtrue(Postgresバージョン9.0.4)であるため、番号付けを2で開始し、番号付けも2で開始します。

私のために働いた解決策は:

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

1
ここでも同じ問題。あなたのソリューションはPostgreSQL 8.3.10でも動作します。
PeqNP

17

シーケンスをリセットするためのALTER SEQUENCESELECT setvalの適切な使用法を単純化して明確にするためだけに:

ALTER SEQUENCE sequence_name RESTART WITH 1;

に相当

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

一連の文をリセットするために使用することができると述べたように、あなたはNEXTVAL(「SEQUENCE_NAME」)で次の値を取得することができますどちらかここにも。

nextval('sequence_name')

ありがとうアリ。setval関数で3番目のパラメーターをfalseに設定することが重要であることに気づきました
DavidHyogo

14

シーケンスをリセットして番号1から開始する最良の方法は、以下を実行することです。

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

したがって、たとえば、usersテーブルの場合は次のようになります。

ALTER SEQUENCE users_id_seq RESTART WITH 1

6

行の順序を保持するには:

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

参考:IDの範囲(たとえば、256-10000000)の間に新しい開始値を指定する必要がある場合:

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

2

シーケンスをリセットしてすべての行を更新するだけでは、重複IDエラーが発生する可能性があります。多くの場合、すべての行を2回更新する必要があります。重複を避けるために最初に高いIDを使用し、次に実際に必要なIDを使用します。

他のコメントで推奨されているように、すべてのIDに固定金額を追加することは避けてください。この固定量よりも多くの行がある場合はどうなりますか?シーケンスの次の値が既存の行のすべてのIDよりも大きいと仮定すると(ギャップを埋めるだけです)、次のようにします。

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


0

ここでの他の回答に触発されて、シーケンス移行を実行する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は次の引数を取ります。

  1. arg_table:テーブル名(例'example'
  2. arg_column:主キー列名(例 'id'
  3. arg_sequence:シーケンス名(例'example_id_seq'
  4. arg_next_value:移行後の列の次の値

次の操作を実行します。

  1. 主キー値を自由範囲に移動します。私はそれがnextval('example_id_seq')次のようでmax(id)あり、シーケンスが1で始まると仮定し ます。これはarg_next_value > max(id)。の場合も処理します。
  2. 主キー値をで始まる連続した範囲に移動し arg_next_valueます。キー値の順序は保持されますが、範囲内の穴は保持されません。
  3. シーケンスに続く次の値を出力します。これは、別のテーブルの列を移行して、このテーブルとマージする場合に役立ちます。

例として、次のように定義されたシーケンスとテーブルを使用します(例:を使用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)

0

自動インクリメント列もPKではありません(この例ではseq-akaシーケンスと呼ばれています)。これはトリガーで実現できます。

DROP TABLE IF 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

pgAdmin3を使用している場合は、[シーケンス]を展開し、シーケンスを右クリックして[プロパティ]に移動し、[定義]タブで[現在の値]を任意の値に変更します。クエリは必要ありません。


3
少なくとも使用しているツールを私たちに伝えなければ、あなたの答えは価値がありません。
11101101b 14

3
これが最も簡単な方法です。明らかに彼はpg admin 3
MvcCmsJon
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.