Pular para conteúdo

POSTGRESQL EXECUTEQUERY - Executar Consulta SQL

O que é este Node?

O POSTGRESQL EXECUTEQUERY é o node responsável por executar consultas SQL personalizadas no banco de dados PostgreSQL, permitindo SELECT, CREATE TABLE, ALTER TABLE e outras operações SQL.

Por que este Node existe?

Aplicações precisam interagir com bancos de dados relacionais. O POSTGRESQL EXECUTEQUERY existe para:

  1. Flexibilidade total: Executar qualquer query SQL personalizada
  2. Queries complexas: Realizar JOINs, subconsultas, CTEs e agregações
  3. DDL operations: Criar/modificar estruturas de tabelas e índices
  4. Transações: Executar múltiplas operações em uma transação
  5. Funções e procedures: Chamar stored procedures e funções do PostgreSQL
  6. Analytics: Realizar análises complexas com SQL puro

Como funciona internamente?

Quando o POSTGRESQL EXECUTEQUERY é executado, o sistema:

  1. Valida configuração: Verifica se config com credenciais foi fornecida
  2. Cria pool de conexões: Estabelece conexão com PostgreSQL usando pg driver
  3. Substitui variáveis: Troca {{variavel}} por valores do contexto
  4. Executa query: Envia SQL para PostgreSQL e aguarda resultado
  5. Retorna resultado: Retorna rows (linhas), rowCount e command executado
  6. Fecha conexão: Encerra pool após execução
  7. Se erro: Lança exceção com detalhes do erro SQL

Código interno (postgresql.executor.ts:94-102):

private async executeQuery(pool: Pool, query: string, context: ExecutionContext): Promise<any> {
  const replacedQuery = this.replaceVariables(query, context.variables);
  const result = await pool.query(replacedQuery);
  return {
    rows: result.rows,
    rowCount: result.rowCount,
    command: result.command,
  };
}

Quando você DEVE usar este Node?

Use POSTGRESQL EXECUTEQUERY quando precisar de consultas SQL personalizadas:

Casos de uso

  1. SELECT com JOINs: "Buscar pedidos com dados de cliente e produtos"
  2. Agregações complexas: "Relatório de vendas por região com totais"
  3. Subconsultas: "Clientes que compraram acima da média"
  4. CTEs (Common Table Expressions): "Queries hierárquicas recursivas"
  5. Criar estruturas: "CREATE TABLE para nova funcionalidade"
  6. Análises avançadas: "Window functions, GROUPING SETS, ROLLUP"

Quando NÃO usar POSTGRESQL EXECUTEQUERY

  • Insert simples: Use POSTGRESQL INSERT (mais seguro e estruturado)
  • Update simples: Use POSTGRESQL UPDATE (previne SQL injection)
  • Delete simples: Use POSTGRESQL DELETE (mais seguro)
  • Upsert: Use POSTGRESQL INSERTORUPDATE (otimizado)

Parâmetros Detalhados

config (object, obrigatório)

O que é: Configuração de conexão com PostgreSQL.

Estrutura:

{
  "host": "localhost",
  "port": 5432,
  "database": "nome_database",
  "user": "usuario",
  "password": "senha",
  "ssl": false
}

Segurança: NUNCA exponha credenciais em código! Use variáveis de ambiente.

query (string, obrigatório)

O que é: Consulta SQL a ser executada.

Formato: SQL válido do PostgreSQL

Suporte a variáveis: Use {{variavel}} para substituir valores do contexto

Flow completo para testar:

{
  "name": "Teste PostgreSQL - Execute Query",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Cidade",
        "parameters": {
          "message": "Buscar clientes de qual cidade?",
          "variable": "cidade"
        }
      }
    },
    {
      "id": "postgres_1",
      "type": "postgresql",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Buscar Clientes",
        "parameters": {
          "operation": "executeQuery",
          "config": {
            "host": "localhost",
            "port": 5432,
            "database": "crm",
            "user": "app_user",
            "password": "secure_password",
            "ssl": false
          },
          "query": "SELECT id, nome, email, telefone FROM clientes WHERE cidade = '{{cidade}}' ORDER BY nome LIMIT 10",
          "responseVariable": "clientes"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Resultado",
        "parameters": {
          "message": "Encontrados {{clientes.rowCount}} clientes em {{cidade}}:\n\n{{clientes.rows}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 900, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "postgres_1" },
    { "source": "postgres_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: Query é executada e retorna clientes da cidade especificada.

responseVariable (string, opcional)

O que é: Nome da variável para armazenar resultado no contexto.

Padrão: Se não especificado, resultado não é salvo em variável

Parâmetros

Campo Tipo Obrigatório Descrição
operation string Sim Deve ser "executeQuery"
config object Sim Configuração de conexão PostgreSQL
config.host string Sim Endereço do servidor PostgreSQL
config.port number Não Porta (padrão: 5432)
config.database string Sim Nome do database
config.user string Sim Usuário PostgreSQL
config.password string Sim Senha do usuário
config.ssl boolean Não Usar SSL (padrão: false)
query string Sim Consulta SQL a executar
responseVariable string Não Variável para armazenar resultado

Exemplo 1: Relatório de Vendas com JOIN

Objetivo: Buscar vendas com dados de cliente e produto usando JOIN

JSON para Importar

{
  "name": "PostgreSQL - Relatório Vendas",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "date_1",
      "type": "date",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Data Início",
        "parameters": {
          "message": "Data inicial (DD/MM/YYYY):",
          "variable": "dataInicio",
          "format": "DD/MM/YYYY"
        }
      }
    },
    {
      "id": "postgres_1",
      "type": "postgresql",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Buscar Vendas",
        "parameters": {
          "operation": "executeQuery",
          "config": {
            "host": "localhost",
            "port": 5432,
            "database": "ecommerce",
            "user": "app_user",
            "password": "secure_password",
            "ssl": false
          },
          "query": "SELECT v.id, v.data_venda, v.total, c.nome AS cliente, p.nome AS produto FROM vendas v INNER JOIN clientes c ON v.cliente_id = c.id INNER JOIN produtos p ON v.produto_id = p.id WHERE v.data_venda >= '{{dataInicio}}' ORDER BY v.data_venda DESC LIMIT 20",
          "responseVariable": "vendas"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Mostrar Resultado",
        "parameters": {
          "message": "Vendas desde {{dataInicio}}:\n\nTotal: {{vendas.rowCount}} vendas\n\n{{vendas.rows}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 900, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "date_1" },
    { "source": "date_1", "target": "postgres_1" },
    { "source": "postgres_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: Data inicial (DD/MM/YYYY):
Usuário: 01/01/2025
Sistema: Vendas desde 01/01/2025:

Total: 15 vendas

[Array com dados das vendas incluindo cliente e produto]

Exemplo 2: Agregação com GROUP BY

Objetivo: Relatório de total de vendas por categoria de produto

JSON para Importar

{
  "name": "PostgreSQL - Vendas por Categoria",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "postgres_1",
      "type": "postgresql",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Agregar Vendas",
        "parameters": {
          "operation": "executeQuery",
          "config": {
            "host": "localhost",
            "port": 5432,
            "database": "ecommerce",
            "user": "app_user",
            "password": "secure_password",
            "ssl": false
          },
          "query": "SELECT p.categoria, COUNT(v.id) AS total_vendas, SUM(v.total) AS receita_total, AVG(v.total) AS ticket_medio FROM vendas v INNER JOIN produtos p ON v.produto_id = p.id WHERE v.data_venda >= CURRENT_DATE - INTERVAL '30 days' GROUP BY p.categoria ORDER BY receita_total DESC",
          "responseVariable": "relatorio"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Exibir Relatório",
        "parameters": {
          "message": "Vendas dos últimos 30 dias por categoria:\n\n{{relatorio.rows}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 700, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "postgres_1" },
    { "source": "postgres_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: Vendas dos últimos 30 dias por categoria:

[
  { categoria: 'Eletrônicos', total_vendas: 45, receita_total: 85000, ticket_medio: 1888.89 },
  { categoria: 'Livros', total_vendas: 78, receita_total: 3240, ticket_medio: 41.54 }
]

Exemplo 3: CTE (Common Table Expression)

Objetivo: Query recursiva usando WITH para hierarquia de categorias

JSON para Importar

{
  "name": "PostgreSQL - CTE Recursivo",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Categoria",
        "parameters": {
          "message": "ID da categoria raiz:",
          "variable": "categoriaId"
        }
      }
    },
    {
      "id": "postgres_1",
      "type": "postgresql",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Buscar Hierarquia",
        "parameters": {
          "operation": "executeQuery",
          "config": {
            "host": "localhost",
            "port": 5432,
            "database": "ecommerce",
            "user": "app_user",
            "password": "secure_password",
            "ssl": false
          },
          "query": "WITH RECURSIVE categoria_tree AS (SELECT id, nome, parent_id, 0 AS nivel FROM categorias WHERE id = {{categoriaId}} UNION ALL SELECT c.id, c.nome, c.parent_id, ct.nivel + 1 FROM categorias c INNER JOIN categoria_tree ct ON c.parent_id = ct.id) SELECT * FROM categoria_tree ORDER BY nivel, nome",
          "responseVariable": "hierarquia"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Mostrar Árvore",
        "parameters": {
          "message": "Hierarquia de categorias:\n\n{{hierarquia.rows}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 900, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "postgres_1" },
    { "source": "postgres_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: ID da categoria raiz:
Usuário: 1
Sistema: Hierarquia de categorias:

[
  { id: 1, nome: 'Eletrônicos', parent_id: null, nivel: 0 },
  { id: 2, nome: 'Computadores', parent_id: 1, nivel: 1 },
  { id: 3, nome: 'Notebooks', parent_id: 2, nivel: 2 }
]

Resposta do Node

{
  "rows": [
    {
      "id": 1,
      "nome": "João Silva",
      "email": "joao@example.com",
      "cidade": "São Paulo"
    },
    {
      "id": 2,
      "nome": "Maria Santos",
      "email": "maria@example.com",
      "cidade": "São Paulo"
    }
  ],
  "rowCount": 2,
  "command": "SELECT"
}

Boas Práticas

SIM:

  • Use prepared statements para prevenir SQL injection
  • Limite resultados com LIMIT para evitar sobrecarga
  • Use índices em colunas de WHERE e JOIN
  • Use EXPLAIN ANALYZE para otimizar queries lentas
  • Normalize dados adequadamente (3FN geralmente)
  • Use transações para operações múltiplas relacionadas
  • Valide input antes de construir queries

NÃO:

  • Não concatene variáveis diretamente no SQL (SQL injection!)
  • Não use SELECT * em produção (especifique colunas)
  • Não faça queries dentro de loops (N+1 problem)
  • Não exponha credenciais de banco em código
  • Não use DISTINCT quando GROUP BY resolve
  • Não ignore índices em queries frequentes

Dicas

💡 Variáveis: Use {{variavel}} para substituição segura de valores

💡 Performance: EXPLAIN mostra plano de execução e custos

💡 Índices: CREATE INDEX acelera queries com WHERE e JOIN

💡 Transações: BEGIN, COMMIT, ROLLBACK para operações atômicas

💡 Window Functions: ROW_NUMBER(), RANK() para análises avançadas

💡 Full-text search: Use tsvector e tsquery para busca textual

💡 JSON: PostgreSQL suporta jsonb para dados semi-estruturados

Próximo Node

POSTGRESQL INSERT - Inserir registros → POSTGRESQL UPDATE - Atualizar registros → POSTGRESQL DELETE - Deletar registros → POSTGRESQL INSERTORUPDATE - Upsert (Insert ou Update)