PostgreSQL: Consultas SELECT Básicas no PostgreSQL

Última atualização: 2026-08-26

1. O Que Você Vai Aprender


2. A História

Bob é um engenheiro de banco de dados em uma plataforma de e-commerce. A plataforma gera cerca de 10.000 pedidos por dia, acumulando 100.000 registros nos últimos 30 dias. A equipe de operações pede a ele para:

  1. Consultar todos os pedidos dos últimos 30 dias, ordenados por valor do maior para o menor
  2. Exibir 50 por página, com suporte a paginação
  3. Filtrar pedidos cancelados
  4. Remover IDs de clientes duplicados da exibição

Bob precisa de SELECT, WHERE, ORDER BY, LIMIT/OFFSET e DISTINCT para realizar o trabalho.


3. Conceito: Fundamentos do SELECT

(1) Visão Geral da Sintaxe do SELECT

SQL
SELECT coluna1, coluna2, ...
FROM nome_tabela
[WHERE condicao]
[ORDER BY coluna [ASC|DESC] [NULLS FIRST|NULLS LAST]]
[LIMIT quantidade [OFFSET inicio]];

SELECT é a instrução SQL mais usada, utilizada para recuperar dados de uma ou mais tabelas.

(2) Todas as Colunas vs Colunas Específicas

Estilo Descrição Desempenho Recomendado para
SELECT * Retorna todas as colunas Pior—transmite dados redundantes Explorar rapidamente a estrutura da tabela
SELECT col1, col2 Retorna apenas colunas especificadas Melhor—menos E/S Consultas em produção

▶ Exemplo: Consultar Todas as Colunas

SQL
SELECT * FROM orders;

Output:

TEXT 📖 Somente leitura
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

▶ Exemplo: Consultar Colunas Específicas

SQL
SELECT order_id, customer_id, total_amount, order_date
FROM orders;

Output:

TEXT 📖 Somente leitura
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(3) Aliases de Coluna

Use a palavra-chave AS (opcional) para dar a uma coluna ou expressão um alias, tornando os resultados mais legíveis.

Uso Exemplo Descrição
AS explícito price * qty AS subtotal Recomendado—claro
Omitir AS price * qty subtotal Válido, mas menos legível
Alias com aspas total_amount AS "Order Total" Necessário quando o alias tem espaços / maiúsculas

▶ Exemplo: Usando Aliases de Coluna

SQL
SELECT
  order_id,
  total_amount AS amount,
  order_date AS "Order Date",
  total_amount * 0.08 AS tax
FROM orders;

Output:

TEXT 📖 Somente leitura
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(4) Expressões e Colunas Calculadas

SELECT pode fazer mais do que ler colunas—também pode escrever expressões aritméticas, chamadas de função, etc., para produzir colunas calculadas.

▶ Exemplo: Coluna Calculada

SQL
SELECT
  product_name,
  unit_price,
  unit_price * 1.1 AS price_with_tax,
  ROUND(unit_price * 1.1, 2) AS rounded_price
FROM products;

Output:

TEXT 📖 Somente leitura
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

4. Conceito: Desduplicação com DISTINCT

(1) Desduplicação Básica

DISTINCT remove linhas duplicadas do conjunto de resultados, comumente usado para contar valores únicos.

▶ Exemplo: Consultar IDs de Clientes Distintos

SQL
SELECT DISTINCT customer_id
FROM orders;

Output:

TEXT 📖 Somente leitura
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(2) Desduplicação com Múltiplas Colunas

DISTINCT aplica-se à combinação de todas as colunas especificadas, não a uma única coluna.

Instrução Escopo da desduplicação
SELECT DISTINCT a Desduplica por a
SELECT DISTINCT a, b Desduplica pela combinação (a, b)
SELECT DISTINCT ON (a) a, b Exclusivo do PostgreSQL: desduplica por a, mantém a primeira linha por grupo

▶ Exemplo: Desduplicação com Combinação de Múltiplas Colunas

SQL
SELECT DISTINCT customer_id, order_status
FROM orders;

Output:

TEXT 📖 Somente leitura
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(3) DISTINCT ON: Sintaxe Exclusiva do PostgreSQL

DISTINCT ON (expr) desduplica por uma determinada expressão e retorna a primeira linha de cada grupo (combine com ORDER BY para decidir qual linha).

▶ Exemplo: Último Pedido de Cada Cliente

SQL
SELECT DISTINCT ON (customer_id)
  customer_id, order_id, order_date, total_amount
FROM orders
ORDER BY customer_id, order_date DESC;

Output:

TEXT 📖 Somente leitura
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

5. Conceito: Filtragem com WHERE

(1) Operadores de Comparação Básicos

Operador Significado Exemplo
= Igual order_status = 'completed'
<> ou != Diferente total_amount <> 0
> Maior que total_amount > 100
< Menor que total_amount < 50
>= Maior ou igual total_amount >= 100
<= Menor ou igual total_amount <= 500

▶ Exemplo: Filtrar Pedidos Concluídos

SQL
SELECT order_id, customer_id, total_amount
FROM orders
WHERE order_status = 'completed';

Output:

TEXT 📖 Somente leitura
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(2) Filtragem por Data

A comparação de datas é uma das necessidades de filtragem mais comuns em e-commerce.

▶ Exemplo: Pedidos dos Últimos 30 Dias

SQL
SELECT order_id, customer_id, total_amount, order_date
FROM orders
WHERE order_date >= CURRENT_DATE - INTERVAL '30 days';

Output:

TEXT 📖 Somente leitura
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(3) Combinando Múltiplas Condições

Use AND, OR, NOT para combinar condições. Precedência: NOT > AND > OR; use parênteses para controlar explicitamente.

▶ Exemplo: Filtro com Condição Combinada

SQL
SELECT order_id, total_amount, order_status
FROM orders
WHERE order_status = 'completed'
  AND total_amount > 500
  AND order_date >= '2025-01-01';

Output:

TEXT 📖 Somente leitura
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

6. Conceito: Ordenação com ORDER BY

(1) Ordenação Básica

ORDER BY por padrão é crescente (ASC); você pode especificar decrescente (DESC). Suporta ordenação por nome de coluna, alias ou posição da coluna.

Estilo de ordenação Sintaxe Descrição
Crescente ORDER BY col ASC Padrão, ASC é opcional
Decrescente ORDER BY col DESC Do maior para o menor
Por alias ORDER BY amount DESC Usa alias do SELECT
Por posição ORDER BY 3 DESC Pela 3ª coluna na lista SELECT (não recomendado)

▶ Exemplo: Ordenar por Valor Decrescente

SQL
SELECT order_id, customer_id, total_amount
FROM orders
ORDER BY total_amount DESC;

Output:

TEXT 📖 Somente leitura
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(2) Ordenação por Múltiplas Colunas

Com ordenação por múltiplas colunas, as linhas são ordenadas pela primeira coluna; empates são resolvidos pela segunda coluna, e assim por diante.

▶ Exemplo: Ordenar por Status, depois por Valor

SQL
SELECT order_id, order_status, total_amount
FROM orders
ORDER BY order_status ASC, total_amount DESC;

Output:

TEXT 📖 Somente leitura
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(3) NULLS FIRST / NULLS LAST: Recurso do PostgreSQL

O PostgreSQL trata NULL como o maior valor por padrão (último na ordenação crescente, primeiro na decrescente). Você pode controlar explicitamente a posição dos NULLs com NULLS FIRST e NULLS LAST.

Ordenação Posição padrão do NULL Ajustável para
ASC NULL no final NULLS FIRST move NULL para o início
DESC NULL no início NULLS LAST move NULL para o final

▶ Exemplo: Controle com NULLS FIRST/LAST

SQL
SELECT product_name, discount_rate
FROM products
ORDER BY discount_rate DESC NULLS LAST;

Output:

TEXT 📖 Somente leitura
 count 
-------
     5
(1 row)

7. Conceito: Paginação com LIMIT e FETCH FIRST

(1) LIMIT / OFFSET

LIMIT limita o número de linhas retornadas; OFFSET pula um determinado número de linhas. Juntos, implementam a paginação.

▶ Exemplo: 50 por página, página 3

SQL
SELECT order_id, customer_id, total_amount, order_date
FROM orders
WHERE order_status = 'completed'
ORDER BY total_amount DESC
LIMIT 50 OFFSET 100;

Output:

TEXT 📖 Somente leitura
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(2) FETCH FIRST: Sintaxe Padrão SQL

O PostgreSQL também suporta a sintaxe padrão SQL FETCH FIRST, semanticamente idêntica ao LIMIT.

Sintaxe Equivalente Descrição
LIMIT 10 FETCH FIRST 10 ROWS ONLY Forma padrão
LIMIT 10 OFFSET 20 OFFSET 20 ROWS FETCH FIRST 10 ROWS ONLY Forma padrão de paginação

▶ Exemplo: Paginação com FETCH FIRST

SQL
SELECT order_id, customer_id, total_amount
FROM orders
ORDER BY total_amount DESC
OFFSET 100 ROWS
FETCH FIRST 50 ROWS ONLY;

Output:

TEXT 📖 Somente leitura
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(3) Fórmula de Paginação

Parâmetro Cálculo
Página page Começa em 1
Tamanho da página size ex.: 50
OFFSET (page - 1) * size
LIMIT size

▶ Exemplo: Paginação Dinâmica (pseudocódigo)

BASH
page=3
size=50
offset=$(( (page - 1) * size ))
psql -c "SELECT order_id, total_amount FROM orders ORDER BY total_amount DESC LIMIT $size OFFSET $offset;"

Output:

TEXT 📖 Somente leitura
# comando psql executado com sucesso

8. Fluxograma: Ordem de Execução da Consulta SELECT

100%
flowchart TD
    A[FROM orders] --> B[filtro WHERE]
    B --> C[colunas / expressões SELECT]
    C --> D[DISTINCT]
    D --> E[ordenação ORDER BY]
    E --> F[paginação LIMIT / OFFSET]
    F --> G[Conjunto de Resultados]

    style A fill:#e1f5fe
    style B fill:#fff3e0
    style C fill:#e8f5e9
    style D fill:#f3e5f5
    style E fill:#fce4ec
    style F fill:#e0f2f1
    style G fill:#c8e6c9

9. Exemplo Completo

Bob concluiu as solicitações da equipe de operações: consultar pedidos concluídos dos últimos 30 dias, paginar por valor decrescente e reportar contagens de clientes distintos.

SQL
-- Passo 1: Pedidos concluídos dos últimos 30 dias, paginados por valor DESC
SELECT
  order_id,
  customer_id,
  total_amount,
  total_amount * 0.08 AS tax_amount,
  order_date AS "Order Date",
  order_status
FROM orders
WHERE order_status = 'completed'
  AND order_date >= CURRENT_DATE - INTERVAL '30 days'
ORDER BY total_amount DESC NULLS LAST
LIMIT 50 OFFSET 0;

-- Passo 2: Contar clientes distintos nesses pedidos
SELECT COUNT(DISTINCT customer_id) AS unique_customers
FROM orders
WHERE order_status = 'completed'
  AND order_date >= CURRENT_DATE - INTERVAL '30 days';

-- Passo 3: Último pedido de cada cliente (DISTINCT ON)
SELECT DISTINCT ON (customer_id)
  customer_id,
  order_id,
  total_amount,
  order_date
FROM orders
WHERE order_status = 'completed'
  AND order_date >= CURRENT_DATE - INTERVAL '30 days'
ORDER BY customer_id, total_amount DESC;

-- Passo 4: Top 10 pedidos com total calculado (preço + imposto)
SELECT
  order_id,
  customer_id,
  total_amount,
  ROUND(total_amount * 1.08, 2) AS total_with_tax,
  order_date
FROM orders
WHERE order_status = 'completed'
  AND order_date >= CURRENT_DATE - INTERVAL '30 days'
ORDER BY total_with_tax DESC
FETCH FIRST 10 ROWS ONLY;

❓ Perguntas Frequentes

P: Posso usar SELECT * em produção? R: Não recomendado. SELECT * retorna todas as colunas, adicionando sobrecarga de transferência de rede e memória, e pode quebrar a lógica da aplicação quando o esquema da tabela muda. Sempre liste explicitamente as colunas que você precisa.

P: Qual a diferença entre DISTINCT e GROUP BY para desduplicação? R: DISTINCT apenas remove linhas duplicadas; GROUP BY também pode fazer agregação. Se você apenas desduplica sem agregar, DISTINCT é mais intuitivo; use GROUP BY quando precisar de agregação.

P: Como a paginação LIMIT OFFSET se comporta com grandes offsets? R: OFFSET precisa pular as primeiras N linhas, então quanto maior o offset, mais lento fica. Para grandes conjuntos de dados, recomenda-se a paginação por chave (filtragem WHERE em uma chave de ordenação), ex.: WHERE order_id > last_seen_id LIMIT 50.

P: NULLS FIRST/LAST é SQL padrão? R: Não, é uma extensão do PostgreSQL. MySQL e SQL Server não suportam; você emularia com CASE ou COALESCE.

P: DISTINCT ON pode ser usado sem ORDER BY? R: Sintaticamente sim, mas sem ORDER BY, qual linha é mantida por grupo é indefinido. Você deve combiná-lo com ORDER BY para resultados previsíveis.

P: Um alias de coluna pode ser usado no WHERE? R: Não. Na ordem de execução SQL, WHERE executa antes de SELECT, então o alias ainda não existe. Mas aliases podem ser usados em ORDER BY, já que ORDER BY executa depois de SELECT.

P: FETCH FIRST e LIMIT são completamente equivalentes? R: Funcionalmente idênticos. FETCH FIRST é a sintaxe padrão SQL:2008; LIMIT é a sintaxe tradicional do PostgreSQL. Para código novo, FETCH FIRST melhora a portabilidade.

P: ORDER BY pode referenciar uma coluna que não está na lista SELECT? R: Sim. O PostgreSQL permite que ORDER BY referencie uma coluna não presente no SELECT, mas se DISTINCT ou GROUP BY for usado, a coluna de ordenação deve aparecer no SELECT ou GROUP BY.


📖 Resumo


📝 Exercícios

  1. ⭐ Escreva uma consulta selecionando product_name e unit_price de products, ordenada por preço crescente, retornando apenas as primeiras 10 linhas.

  2. ⭐⭐ Escreva uma consulta selecionando pedidos dos últimos 7 dias de orders, filtrando por total_amount > 200, ordenados por order_date DESC, usando FETCH FIRST 20 ROWS ONLY.

  3. ⭐⭐⭐ Use DISTINCT ON para consultar o pedido de maior valor de cada customer_id (dica: ORDER BY customer_id, total_amount DESC), e conte quantos desses clientes têm um pedido máximo único acima de 1.000 USD.

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%