sql >> データベース >  >> RDS >> PostgreSQL

すべてのテーブルのIDを圧縮または番号変更し、シーケンスをmax(id)にリセットしますか?

    質問は古いですが、ここで提案されていることを適用しようとした後、dba.SEの絶望的なユーザーから新しい質問がありました。 詳細と説明がありますで答えを見つけてください :

    現在受け入れられている回答 ほとんどの場合失敗します

    • 通常、PRIMARY KEYがあります またはUNIQUE idの制約 NOT DEFERRABLEである列 デフォルトでは。 (OPはreferences and constraintsに言及しています 。)このような制約は各行の後にチェックされるため、固有の違反が発生する可能性があります。 試行エラー。詳細:

    • 通常、元の行の順序を保持する必要があります ギャップを埋めながら。ただし、行が更新される順序は任意です。 、任意の数になります。示されている例では、物理ストレージが目的の順序(ほんの少し前に目的の順序で行が挿入されている)と一致しているため、元のシーケンスが保持されているようです。これは、実際のアプリケーションではほとんど発生せず、完全に信頼性がありません。

    問題は最初に思われるよりも複雑です。 1つ PK / UNIQUE制約(および関連するFK制約)を一時的に削除する余裕がある場合の解決策(とりわけ):

    BEGIN;
    
    LOCK tbl;
    
    -- remove all FK constraints to the column
    
    ALTER TABLE tbl DROP CONSTRAINT tbl_pkey;  -- remove PK
    
    -- for the simple case without FK references - or see below:    
    UPDATE tbl t  -- intermediate unique violations are ignored now
    SET    id = t1.new_id
    FROM  (SELECT id, row_number() OVER (ORDER BY id) AS new_id FROM tbl) t1
    WHERE  t.id = t1.id;
    
    -- Update referencing value in FK columns at the same time (if any)
    
    SELECT setval('tbl_id_seq', max(id)) FROM tbl;  -- reset sequence
    
    ALTER TABLE tbl ADD CONSTRAINT tbl_pkey PRIMARY KEY(id); -- add PK back
    
    -- add all FK constraints to the column back
    
    COMMIT;
    

    これも すべての行のPK(およびFK)制約をチェックすることは、制約を削除して再度追加するよりもはるかにコストがかかるため、大きなテーブルの場合は高速になります。

    tbl.idを参照する他のテーブルにFK列がある場合 、データ変更CTE> それらすべてを更新します。

    テーブルの例fk_tbl およびFK列fk_id

    WITH u1 AS (
       UPDATE tbl t
       SET    id = t1.new_id
       FROM  (SELECT id, row_number() OVER (ORDER BY id) AS new_id FROM tbl) t1
       WHERE  t.id = t1.id
       RETURNING t.id, t1.new_id  -- return old and new ID
       )
    UPDATE fk_tbl f
    SET    fk_id = u1.new_id      -- set to new ID
    FROM   u1
    WHERE  f.fk_id = u1.id;       -- match on old ID
    

    詳細については、dba.SEの参照回答 をご覧ください。 。



    1. SELECT LAST_INSERT_ID()は、プリペアドステートメントを使用した後に0を返します

    2. x要素のグループをバッチで返す場合はMySQLSelectQuery

    3. Golangを使用してMySQLテーブルをJSONにダンプする

    4. HTML入力フォームボックスが最初のスペースの後にPHP値を入力しない