Você já se deparou com a necessidade de fazer uma alteração que afeta vários campos de várias tabelas?
Imagine a seguinte situação: você
possui vários campos em diversas tabelas que representam valores
monetários de 10 casas inteiras e 2 decimais, ou seja, tipo
numeric(12,2)
, e por necessidade do cliente o analista informou que
isso precisa ser alterado para 15 casas inteiras e 2 decimais, ou
seja, tipo numeric(17,2)
. E agora?
Bem, nosso amigo elefante, guarda esses dados com bastante carinho e permite que nós, meros mortais, possamos visualizá-los e tomar decisões com eles já que cada banco de dados possui um esquema contendo os dados sobre os seus dados - os metadados.
O nome desse esquema é information_schema
e contém views que nos
permitem, por exemplo, listar os campos de uma tabela com seus
respectivos tipos, essa view é declarada como columns. Então o que tem
nela?
SELECT * FROM information_schema.columns;
… saída muito grande aqui …
Testou? “Coisarada” né? Mas que tal listar as colunas de uma tabela
especifica? Suponha que exista uma tabela tb_pessoa
:
SELECT * FROM information_schema.columns WHERE table_name = 'tb_pessoa';
table_catalog | table_schema | table_name | column_name | ordinal_position | column_default | is_nullable | data_type | character_maximum_length | character_octet_length | numeric_precision | numeric_precision_radix | numeric_scale | datetime_precision | interval_type | interval_precision | character_set_catalog | character_set_schema | character_set_name | collation_catalog | collation_schema | collation_name | domain_catalog | domain_schema | domain_name | udt_catalog | udt_schema | udt_name | scope_catalog | scope_schema | scope_name | maximum_cardinality | dtd_identifier | is_self_referencing |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
esquema | esquema | tb_pessoa | tipo_pessoa | 3 | NO | integer | 32 | 2 | 0 | esquema | pg_catalog | int4 | 3 | NO | |||||||||||||||||||
esquema | esquema | tb_pessoa | nome | 2 | NO | character varying | 150 | 1073741824 | esquema | pg_catalog | varchar | 2 | NO | ||||||||||||||||||||
esquema | esquema | tb_pessoa | nome_personalizado | 9 | YES | character varying | 25 | 1073741824 | esquema | pg_catalog | varchar | 9 | NO | ||||||||||||||||||||
esquema | esquema | tb_pessoa | dt_inclusao | 5 | NO | date | esquema | pg_catalog | date | 5 | NO | ||||||||||||||||||||||
esquema | esquema | tb_pessoa | nro_documento | 1 | NO | numeric | 14 | 10 | 0 | esquema | pg_catalog | numeric | 1 | NO |
Melhorou um pouco né? Certo, tem várias colunas, então que tal agora mostrar só o que interessa? Como por exemplo, o nome ta tabela, o nome da coluna, o tipo da mesma e se ela aceita nulo?
SELECT table_name AS nome_tabela,
column_name AS nome_coluna,
data_type AS tipo,
is_nullable AS aceita_nulo
FROM information_schema.columns
WHERE table_name = 'tb_pessoa';
nome_tabela | nome_coluna | tipo | aceita_nulo |
---|---|---|---|
tb_pessoa | tipo_pessoa | integer | NO |
tb_pessoa | nome | character varying | NO |
tb_pessoa | nome_personalizado | character varying | YES |
tb_pessoa | dt_inclusao | date | NO |
tb_pessoa | nro_documento | numeric | NO |
Melhor ainda né? Se você analisar a descrição da visão columns
…
Vejamos:
Coluna | Tipo | Modificadores |
---|---|---|
table_catalog | information_schema.sql_identifier | |
table_schema | information_schema.sql_identifier | |
table_name | information_schema.sql_identifier | |
column_name | information_schema.sql_identifier | |
ordinal_position | information_schema.cardinal_number | |
column_default | information_schema.character_data | |
is_nullable | information_schema.character_data | |
data_type | information_schema.character_data | |
character_maximum_length | information_schema.cardinal_number | |
character_octet_length | information_schema.cardinal_number | |
numeric_precision | information_schema.cardinal_number | |
numeric_precision_radix | information_schema.cardinal_number | |
numeric_scale | information_schema.cardinal_number | |
datetime_precision | information_schema.cardinal_number | |
interval_type | information_schema.character_data | |
interval_precision | information_schema.character_data | |
character_set_catalog | information_schema.sql_identifier | |
character_set_schema | information_schema.sql_identifier | |
character_set_name | information_schema.sql_identifier | |
collation_catalog | information_schema.sql_identifier | |
collation_schema | information_schema.sql_identifier | |
collation_name | information_schema.sql_identifier | |
domain_catalog | information_schema.sql_identifier | |
domain_schema | information_schema.sql_identifier | |
domain_name | information_schema.sql_identifier | |
udt_catalog | information_schema.sql_identifier | |
udt_schema | information_schema.sql_identifier | |
udt_name | information_schema.sql_identifier | |
scope_catalog | information_schema.sql_identifier | |
scope_schema | information_schema.sql_identifier | |
scope_name | information_schema.sql_identifier | |
maximum_cardinality | information_schema.cardinal_number | |
dtd_identifier | information_schema.sql_identifier | |
is_self_referencing | information_schema.character_data |
… perceberá que pode melhorar a saida acima, considerando o data_type
:
SELECT table_name AS nome_tabela,
column_name AS nome_coluna,
data_type AS tipo,
numeric_precision AS digitos,
numeric_scale AS decimais,
is_nullable AS aceita_nulo
FROM
information_schema.columns
WHERE
data_type = 'numeric';
Agora só falta juntar tudo isso numa panela, cozinhar por alguns
minutos e servir o script que irá satisfazer o nosso problema inicial
(lembra? mudar de numeric(12,2)
para numeric(17,2)
):
SELECT 'ALTER TABLE ' || table_name ||
' ALTER COLUMN ' || column_name ||
' TYPE numeric(17,2);'
FROM information_schema.columns
WHERE data_type = 'numeric' AND
numeric_precision = 12 AND
numeric_scale = 2;
?column?
-----------------------------------------------------------------------------------
ALTER TABLE tb_funcionario ALTER COLUMN remuneracao_basica TYPE numeric(17,2);
ALTER TABLE tb_pessoa_juridica ALTER COLUMN valor_receita TYPE numeric(17,2);
ALTER TABLE tb_fonte_renda_pf ALTER COLUMN valor_renda TYPE numeric(17,2);
ALTER TABLE tb_caixa ALTER COLUMN saldo_dia TYPE numeric(17,2);
--- CORTE ---
Pronto, ai está o nosso script! Você precisa apenas executá-lo agora.
DESAFIO: como a saida do comando SQL é grande, redirecione a saida para um arquivo e execute-o via psql.
Bom, é isso “:D