Postgresql 10 – Como re-sequenciar uma coluna de chave primária em uma tabela que depende de outras tabelas

Postgresql 10 – Como re-sequenciar uma coluna de chave primária em uma tabela que depende de outras tabelas

Eu tenho uma tabela chamada cliente que depende da entrada de outras tabelas. com as seguintes especificações:

crewdb=#\d+ client;
                                                    Table "public.client"
       Column        |  Type   | Collation | Nullable |           Default            | Storage  | Stats target | Description
---------------------+---------+-----------+----------+------------------------------+----------+--------------+-------------
 clientid            | integer |           | not null | generated always as identity | plain    |              |
 account_name        | text    |           | not null |                              | extended |              |
 last_name           | text    |           |          |                              | extended |              |
 first_name          | text    |           |          |                              | extended |              |
 address             | text    |           | not null |                              | extended |              |
 suburbid            | integer |           |          |                              | plain    |              |
 cityid              | integer |           |          |                              | plain    |              |
 post_code           | integer |           | not null |                              | plain    |              |
 business_phone      | text    |           |          |                              | extended |              |
 home_phone          | text    |           |          |                              | extended |              |
 mobile_phone        | text    |           |          |                              | extended |              |
 alternative_phone   | text    |           |          |                              | extended |              |
 email               | text    |           |          |                              | extended |              |
 quote_detailsid     | integer |           |          |                              | plain    |              |
 invoice_typeid      | integer |           |          |                              | plain    |              |
 payment_typeid      | integer |           |          |                              | plain    |              |
 job_typeid          | integer |           |          |                              | plain    |              |
 communicationid     | integer |           |          |                              | plain    |              |
 accessid            | integer |           |          |                              | plain    |              |
 difficulty_levelid  | integer |           |          |                              | plain    |              |
 current_lawn_price  | numeric |           |          |                              | main     |              |
 square_meters       | numeric |           |          |                              | main     |              |
 note                | text    |           |          |                              | extended |              |
 client_statusid     | integer |           |          |                              | plain    |              |
 reason_for_statusid | integer |           |          |                              | plain    |              |
Indexes:
    "client_pkey" PRIMARY KEY, btree (clientid)
    "account_name_check" UNIQUE CONSTRAINT, btree (account_name)
Foreign-key constraints:
    "client_accessid_fkey" FOREIGN KEY (accessid) REFERENCES access(accessid)
    "client_cityid_fkey" FOREIGN KEY (cityid) REFERENCES city(cityid)
    "client_client_statusid_fkey" FOREIGN KEY (client_statusid) REFERENCES client_status(client_statusid)
    "client_communicationid_fkey" FOREIGN KEY (communicationid) REFERENCES communication(communicationid)
    "client_difficulty_levelid_fkey" FOREIGN KEY (difficulty_levelid) REFERENCES difficulty_level(difficulty_levelid)
    "client_invoice_typeid_fkey" FOREIGN KEY (invoice_typeid) REFERENCES invoice_type(invoice_typeid)
    "client_job_typeid_fkey" FOREIGN KEY (job_typeid) REFERENCES job_type(job_typeid)
    "client_payment_typeid_fkey" FOREIGN KEY (payment_typeid) REFERENCES payment_type(payment_typeid)
    "client_quote_detailsid_fkey" FOREIGN KEY (quote_detailsid) REFERENCES quote_details(quote_detailsid)
    "client_reason_for_statusid_fkey" FOREIGN KEY (reason_for_statusid) REFERENCES reason_for_status(reason_for_statusid)
    "client_suburbid_fkey" FOREIGN KEY (suburbid) REFERENCES suburb(suburbid)
Referenced by:
    TABLE "work" CONSTRAINT "work_clientid_fkey" FOREIGN KEY (clientid) REFERENCES client(clientid)

A coluna clientid (chave primária) está fora de ordem, pois os registros do cliente foram excluídos da seguinte forma:

crewdb=# select clientid from client order by clientid asc limit 22;
 clientid
----------
        2
        3
        4
        5
        6
        7
        8
        9
       10
       11
       12
       13
       14
       15
       17
       19
       21
       22
       23
       24
       26
       30
(22 rows)

por exemplo, as linhas 1 e 25 foram excluídas. Existe uma maneira de reiniciar o índice de 1 incremento por 1 levando em consideração os relacionamentos com outras tabelas e fazendo tudo isso de maneira segura?

Responder1

Isenção de responsabilidade: Em princípio, gosto da ideia de ter ids bonitos e limpos. No entanto, renumerá-los não oferece nenhuma vantagem se for bem-sucedido, mas quebrará o banco de dados se falhar.

Primeiro, é melhor garantir que você é oúnico usuário conectado ao banco de dados. Usaremos transações de qualquer maneira, mas isso ajudará o banco de dados a fazer seu trabalho com mais rapidez.

Antes de renumerar a clienttabela, você precisa alterar as FOREIGN KEYrestrições que fazem referência à tabela:

Referenced by: TABLE "work" CONSTRAINT "work_clientid_fkey" FOREIGN KEY (clientid) REFERENCES client(clientid)

e adicione a CASCADEação a ON UPDATE(cf.Referência CRIAR TABELA):

BEGIN;
ALTER TABLE work DROP CONSTRAINT work_clientid_fkey;
ALTER TABLE work ADD CONSTRAINT work_clientid_fkey
    FOREIGN KEY (clientid) REFERENCES client ON UPDATE CASCADE;
COMMIT;

Isso atualizará automaticamente a work.clientidcoluna quando ela client.clientidfor alterada. Quando isso for feito podemos usar uma SELECTinstrução para gerar os novos ids e usar o resultado para emitir uma UPDATEinstrução, comoexplicado nesta resposta. Você pode fazer isso com:

BEGIN;
CREATE SEQUENCE temp_client_id;
-- The real work begins
UPDATE client
SET clientid = ids.new_id
FROM (SELECT clientid AS old_id, nextval('temp_client_id') AS new_id
      FROM client ORDER BY clientid) AS ids
WHERE clientid = ids.old_id;
-- Clean up
DROP SEQUENCE temp_client_id;
COMMIT;

Depois de tudo isso feito você pode querer atualizar o valor da sequência que você está usando para gerar ids para a clienttabela (vamos chamá-la de client_id_seq):

SELECT setval('client_id_seq', MAX(clientid)) FROM client;

informação relacionada