Antes de irmos pra prática, bora responder: o que é esse tal de SQL dinâmico? Imagina que você precisa criar uma tabela com um nome único, que chega como parâmetro. Ou rodar uma query numa tabela cujo nome só é conhecido na hora que o programa tá rodando. Aqui, SQL estático não resolve — é aí que entra a execução dinâmica.
O PL/pgSQL tem o comando EXECUTE, que executa uma query SQL passada como string. Isso te dá a chance de montar e rodar código SQL "on the fly", criando queries que mudam de acordo com os parâmetros.
Por que SQL dinâmico pode ser útil?
- Flexibilidade: Dá pra montar queries dinamicamente dependendo dos dados de entrada. Tipo, fazer operações em tabelas ou colunas cujos nomes você não sabe antes.
- Automação: Criar tabelas ou índices com nomes únicos.
- Universalidade: Trabalhar com diferentes estruturas de dados sem precisar reescrever o procedimento.
Exemplo da vida real: imagina que você tá criando um sistema de analytics, e pra cada cliente novo precisa criar uma tabela separada pra guardar os dados dele. Dá pra automatizar tudo isso usando EXECUTE.
Sintaxe do EXECUTE
Usar SQL dinâmico com EXECUTE é assim:
EXECUTE 'string-SQL';
Exemplo de query simples:
DO $$
BEGIN
EXECUTE 'CREATE TABLE test_table (id SERIAL PRIMARY KEY, name TEXT)';
END $$;
Esse bloco de código vai criar a tabela test_table. Moleza, mas bora ver uns cenários mais avançados.
Exemplos de uso do EXECUTE
1. Criando tabela com nome dinâmico
Suponha que você precise criar tabelas com nomes baseados na data atual. Olha só como faz:
DO $$
DECLARE
table_name TEXT;
BEGIN
-- Gerando o nome da tabela
table_name := 'report_' || to_char(CURRENT_DATE, 'YYYYMMDD');
-- Criando a tabela com nome dinâmico
EXECUTE 'CREATE TABLE ' || table_name || ' (id SERIAL PRIMARY KEY, data TEXT)';
-- Mostrando mensagem pra conferir
RAISE NOTICE 'Tabela % criada com sucesso', table_name;
END $$;
Aqui o nome dinâmico é gerado a partir da data de hoje, e a string SQL final vai pro EXECUTE.
2. Rodando query com parâmetros dinâmicos
Digamos que você precisa buscar dados de uma tabela cujo nome chega como parâmetro. Bora criar uma função pra isso:
CREATE OR REPLACE FUNCTION get_data_from_table(table_name TEXT)
RETURNS TABLE(id INTEGER, name TEXT) AS $$
BEGIN
RETURN QUERY EXECUTE
'SELECT id, name FROM ' || table_name || ' WHERE id < 10';
END $$ LANGUAGE plpgsql;
Chamando a função:
SELECT * FROM get_data_from_table('employees');
Esse jeito é ótimo pra criar utilitários universais, tipo sistemas de relatórios dinâmicos.
Problemas e limitações do SQL dinâmico
Executar SQL dinamicamente te dá muita liberdade, mas, como na vida, liberdade vem com responsabilidade. Olha onde pode dar ruim:
SQL injection: se você passa parâmetros de texto na query sem tratar, pode dar brecha pra alguém rodar código SQL malicioso.
Exemplo de código vulnerável:
EXECUTE 'SELECT * FROM users WHERE name = ''' || user_input || '''';Se
user_inputfor'; DROP TABLE users; --, a query vai destruir a tabelausers.Dificuldade de debug: código dinâmico é mais difícil de analisar e debugar, porque a query só é montada e executada na hora.
- Perda de performance: queries dinâmicas não aproveitam o cache de planos de execução do PostgreSQL, o que pode deixar tudo mais lento.
Como se proteger de SQL injection
Pra evitar ataques de SQL injection, use parametrização nas queries dinâmicas em vez de só concatenar strings. No PL/pgSQL, você faz isso com quote_literal() pra parâmetros de texto e quote_ident() pra identificadores (tipo nomes de tabelas ou colunas).
Exemplo de código seguro:
DO $$
DECLARE
table_name TEXT;
user_input TEXT := 'John';
BEGIN
table_name := 'employees';
EXECUTE 'SELECT * FROM ' || quote_ident(table_name) ||
' WHERE name = ' || quote_literal(user_input);
END $$;
Implementação: atualização dinâmica de tabelas
Olha um exemplo de procedimento que atualiza valores numa tabela cujo nome chega como parâmetro:
CREATE OR REPLACE FUNCTION update_table_data(table_name TEXT, id_value INT, new_data TEXT)
RETURNS VOID AS $$
BEGIN
EXECUTE 'UPDATE ' || quote_ident(table_name) ||
' SET data = ' || quote_literal(new_data) ||
' WHERE id = ' || id_value;
END $$ LANGUAGE plpgsql;
Chamando a função:
SELECT update_table_data('test_table', 1, 'Valor Atualizado');
Exemplo: criando relatório pra cliente
Imagina que você controla pedidos por cliente e quer automatizar a criação de tabelas de relatório pra cada cliente.
CREATE OR REPLACE FUNCTION create_client_report(client_id INT)
RETURNS VOID AS $$
DECLARE
table_name TEXT;
BEGIN
-- Montando o nome da tabela de relatório
table_name := 'client_report_' || client_id;
-- Criando a tabela de relatório
EXECUTE 'CREATE TABLE ' || quote_ident(table_name) || ' (order_id INT, amount NUMERIC)';
-- Preenchendo a tabela com dados
EXECUTE 'INSERT INTO ' || quote_ident(table_name) ||
' SELECT order_id, amount FROM orders WHERE client_id = ' || client_id;
RAISE NOTICE 'Relatório para cliente % criado: tabela %', client_id, table_name;
END $$ LANGUAGE plpgsql;
SQL dinâmico com EXECUTE é uma ferramenta poderosa que abre possibilidades incríveis pra automação e flexibilidade no PL/pgSQL. Use com cuidado, sempre lembrando dos riscos de SQL injection. Se quiser que suas queries sejam seguras e confiáveis, use quote_ident() e quote_literal().
Na próxima aula, a gente vai se aprofundar na criação de procedimentos complexos, incluindo validação de dados, atualização de registros e logging de operações. Se prepara porque trabalhar com queries dinâmicas vai ser a base pra resolver essas paradas!
GO TO FULL VERSION