Funções esquecidas do SQL e onde utilizá-las

Muitos analistas de dados se limitam às funções básicas do SQL como SELECT, JOIN, GROUP BY e WHERE. No entanto o SQL oferecem um arsenal de funções mais avançadas que podem simplificar consultas complexas e melhorar significativamente a performance. Neste tutorial, exploraremos essas funções usando exemplos práticos, tanto no MySQL quando no PostgreSQL.

Base de Dados de Exemplo

Para demonstrar essas funções, vamos criar um sistema de e-commerce simples com as seguintes tabelas:

-- Criação das tabelas de exemplo
CREATE TABLE categorias (
    id INT PRIMARY KEY,
    nome VARCHAR(100),
    descricao TEXT
);

CREATE TABLE produtos (
    id INT PRIMARY KEY,
    nome VARCHAR(200),
    preco DECIMAL(10,2),
    categoria_id INT,
    estoque INT,
    data_criacao DATE,
    ativo BOOLEAN
);

CREATE TABLE clientes (
    id INT PRIMARY KEY,
    nome VARCHAR(200),
    email VARCHAR(150),
    data_nascimento DATE,
    cidade VARCHAR(100),
    estado VARCHAR(50)
);

CREATE TABLE pedidos (
    id INT PRIMARY KEY,
    cliente_id INT,
    data_pedido TIMESTAMP,
    valor_total DECIMAL(10,2),
    status VARCHAR(50)
);

CREATE TABLE itens_pedido (
    id INT PRIMARY KEY,
    pedido_id INT,
    produto_id INT,
    quantidade INT,
    preco_unitario DECIMAL(10,2)
);

-- Inserção de dados de exemplo
INSERT INTO categorias VALUES 
(1, 'Eletrônicos', 'Dispositivos eletrônicos'),
(2, 'Roupas', 'Vestuário em geral'),
(3, 'Livros', 'Literatura e educação'),
(4, 'Casa', 'Itens para casa');

INSERT INTO produtos VALUES 
(1, 'Smartphone', 899.99, 1, 50, '2024-01-15', true),
(2, 'Laptop', 1299.99, 1, 30, '2024-01-20', true),
(3, 'Camiseta', 29.99, 2, 100, '2024-02-01', true),
(4, 'Livro SQL', 49.99, 3, 75, '2024-02-10', true),
(5, 'Mesa', 199.99, 4, 25, '2024-02-15', true);

INSERT INTO clientes VALUES 
(1, 'João Silva', 'joao@email.com', '1985-05-15', 'São Paulo', 'SP'),
(2, 'Maria Santos', 'maria@email.com', '1990-08-22', 'Rio de Janeiro', 'RJ'),
(3, 'Pedro Costa', 'pedro@email.com', '1988-12-03', 'Belo Horizonte', 'MG');

INSERT INTO pedidos VALUES 
(1, 1, '2024-03-01 10:30:00', 929.98, 'entregue'),
(2, 2, '2024-03-02 14:15:00', 1349.98, 'processando'),
(3, 1, '2024-03-03 09:45:00', 79.98, 'cancelado'),
(4, 3, '2024-03-04 16:20:00', 249.98, 'entregue');

INSERT INTO itens_pedido VALUES 
(1, 1, 1, 1, 899.99),
(2, 1, 3, 1, 29.99),
(3, 2, 2, 1, 1299.99),
(4, 2, 4, 1, 49.99),
(5, 3, 3, 2, 29.99),
(6, 3, 4, 1, 49.99),
(7, 4, 5, 1, 199.99),
(8, 4, 4, 1, 49.99);
erDiagram
    categorias {
        int id PK
        varchar nome
        text descricao
    }
    
    produtos {
        int id PK
        varchar nome
        decimal preco
        int categoria_id FK
        int estoque
        date data_criacao
        boolean ativo
    }
    
    clientes {
        int id PK
        varchar nome
        varchar email
        date data_nascimento
        varchar cidade
        varchar estado
    }
    
    pedidos {
        int id PK
        int cliente_id FK
        timestamp data_pedido
        decimal valor_total
        varchar status
    }
    
    itens_pedido {
        int id PK
        int pedido_id FK
        int produto_id FK
        int quantidade
        decimal preco_unitario
    }
    
    %% Relacionamentos
    categorias ||--o{ produtos : "possui"
    clientes ||--o{ pedidos : "faz"
    pedidos ||--o{ itens_pedido : "contém"
    produtos ||--o{ itens_pedido : "está em"

Parte 1: Funções que Funcionam em Ambos os SGBDs

1. Funções de Janela (Window Functions)
ROW_NUMBER()

Esta função atribui um número sequencial único para cada linha dentro de uma partição dos dados. É extremamente útil para paginação e ranking.

-- Numerar pedidos por cliente em ordem cronológica
SELECT 
    cliente_id,
    id as pedido_id,
    data_pedido,
    valor_total,
    ROW_NUMBER() OVER (PARTITION BY cliente_id ORDER BY data_pedido) as numero_pedido
FROM pedidos;
cliente_id,pedido_id,data_pedido,valor_total,numero_pedido
1,1,"2024-03-01 10:30:00",929.98,1
1,3,"2024-03-03 09:45:00",79.98,2
2,2,"2024-03-02 14:15:00",1349.98,1
3,4,"2024-03-04 16:20:00",249.98,1
Code language: CSS (css)
RANK() e DENSE_RANK()

Essas funções criam rankings, sendo que RANK() pula números quando há empates, enquanto DENSE_RANK() não pula.

-- Ranking de produtos por preço (com empates)
SELECT 
    nome,
    preco,
    RANK() OVER (ORDER BY preco DESC) as ranking,
    DENSE_RANK() OVER (ORDER BY preco DESC) as ranking_denso
FROM produtos
WHERE ativo = true;
nome,preco,ranking,ranking_denso
Laptop,1299.99,1,1
Smartphone,899.99,2,2
Mesa,199.99,3,3
"Livro SQL",49.99,4,4
Camiseta,29.99,5,5
Code language: CSS (css)
LAG() e LEAD()

Essas funções permitem acessar dados de linhas anteriores (LAG) ou posteriores (LEAD) sem usar self-joins complexos.

-- Comparar valor do pedido atual com o anterior do mesmo cliente
SELECT 
    cliente_id,
    data_pedido,
    valor_total,
    LAG(valor_total, 1) OVER (PARTITION BY cliente_id ORDER BY data_pedido) as valor_anterior,
    valor_total - LAG(valor_total, 1) OVER (PARTITION BY cliente_id ORDER BY data_pedido) as diferenca
FROM pedidos;
cliente_id,data_pedido,valor_total,valor_anterior,diferenca
1,"2024-03-01 10:30:00",929.98,,
1,"2024-03-03 09:45:00",79.98,929.98,-850.0
2,"2024-03-02 14:15:00",1349.98,,
3,"2024-03-04 16:20:00",249.98,,
Code language: CSS (css)

2. Expressões CASE Avançadas

CASE com Agregações

O CASE pode ser usado dentro de funções de agregação para criar relatórios pivotados dinâmicos.

-- Contar pedidos por status em colunas separadas
SELECT 
    EXTRACT(MONTH FROM data_pedido) as mes,
    COUNT(CASE WHEN status = 'entregue' THEN 1 END) as entregues,
    COUNT(CASE WHEN status = 'processando' THEN 1 END) as processando,
    COUNT(CASE WHEN status = 'cancelado' THEN 1 END) as cancelados,
    COUNT(*) as total
FROM pedidos
GROUP BY EXTRACT(MONTH FROM data_pedido);
mes,entregues,processando,cancelados,total
03,2,1,1,4
3. CTEs (Common Table Expressions)
CTE Básico

CTEs criam consultas temporárias nomeadas que tornam o código mais legível e permitem referências múltiplas.

-- CTE para calcular estatísticas de vendas por categoria
WITH vendas_categoria AS (
    SELECT 
        c.nome as categoria,
        SUM(ip.quantidade * ip.preco_unitario) as total_vendas,
        COUNT(DISTINCT p.id) as total_pedidos
    FROM categorias c
    JOIN produtos pr ON c.id = pr.categoria_id
    JOIN itens_pedido ip ON pr.id = ip.produto_id
    JOIN pedidos p ON ip.pedido_id = p.id
    WHERE p.status = 'entregue'
    GROUP BY c.id, c.nome
)
SELECT 
    categoria,
    total_vendas,
    total_pedidos,
    total_vendas / total_pedidos as ticket_medio
FROM vendas_categoria
ORDER BY total_vendas DESC;
categoria,total_vendas,total_pedidos,ticket_medio
"Eletrônicos",899.99,1,899.99
Casa,199.99,1,199.99
Livros,49.99,1,49.99
Roupas,29.99,1,29.99Code language: CSS (css)
CTE Recursivo

CTEs recursivos são poderosos para trabalhar com hierarquias ou gerar sequências.

-- Gerar série de datas para análise de vendas diárias
WITH RECURSIVE serie_datas AS (
    SELECT DATE '2024-03-01' as data
    UNION ALL
    SELECT data + INTERVAL '1 day'
    FROM serie_datas
    WHERE data < DATE '2024-03-31'
)
SELECT 
    sd.data,
    COALESCE(COUNT(p.id), 0) as pedidos_dia,
    COALESCE(SUM(p.valor_total), 0) as vendas_dia
FROM serie_datas sd
LEFT JOIN pedidos p ON DATE(p.data_pedido) = sd.data
GROUP BY sd.data
ORDER BY sd.data;
data,pedidos_dia,vendas_dia
2024-03-01,1,929.98
2024-03-02,1,1349.98
2024-03-03,1,79.98
2024-03-04,1,249.98
2024-03-05,0,0Code language: CSS (css)
4. Função COALESCE()

Esta função retorna o primeiro valor não nulo de uma lista de expressões. É extremamente útil para tratar valores nulos.

-- Tratar valores nulos em relatórios
SELECT 
    nome,
    COALESCE(estoque, 0) as estoque_atual,
    COALESCE(estoque * preco, 0) as valor_estoque,
    CASE 
        WHEN COALESCE(estoque, 0) = 0 THEN 'Sem estoque'
        WHEN COALESCE(estoque, 0) < 10 THEN 'Estoque baixo'
        ELSE 'Estoque normal'
    END as status_estoque
FROM produtos;
nome,estoque_atual,valor_estoque,status_estoque
Smartphone,50,44999.5,"Estoque normal"
Laptop,30,38999.7,"Estoque normal"
Camiseta,100,2999.0,"Estoque normal"
"Livro SQL",75,3749.25,"Estoque normal"
Mesa,25,4999.75,"Estoque normal"Code language: SQL (Structured Query Language) (sql)
5. Funções de String Avançadas
CONCAT() e CONCAT_WS()

Para concatenar strings de forma segura, tratando valores nulos automaticamente.

-- Criar nomes completos e endereços formatados
SELECT 
    CONCAT(nome, ' (', email, ')') as cliente_completo,
    CONCAT_WS(', ', cidade, estado) as localizacao
FROM clientes;
cliente_completo,localizacao
"João Silva (joao@email.com)","São Paulo, SP"
"Maria Santos (maria@email.com)","Rio de Janeiro, RJ"
"Pedro Costa (pedro@email.com)","Belo Horizonte, MG"Code language: JavaScript (javascript)
SUBSTRING() e POSITION()

Para extrair e localizar partes específicas de strings.

-- Extrair domínio do email e primeira letra do nome
SELECT 
    nome,
    SUBSTRING(nome, 1, 1) as inicial,
    SUBSTRING(email, POSITION('@' IN email) + 1) as dominio_email
FROM clientes;
nome,inicial,dominio_email
"João Silva",J,email.com
"Maria Santos",M,email.com
"Pedro Costa",P,email.comCode language: JavaScript (javascript)

Parte 2: Funções Específicas do PostgreSQL

1. Arrays

PostgreSQL oferece suporte nativo robusto para arrays, permitindo armazenar múltiplos valores em uma única coluna.

-- Exemplo com arrays (PostgreSQL)
-- Criar uma tabela com campo array
CREATE TABLE tags_produto (
    produto_id INT,
    tags TEXT[]
);

-- Inserir dados com arrays
INSERT INTO tags_produto VALUES 
(1, ARRAY['tecnologia', 'comunicação', 'móvel']),
(2, ARRAY['tecnologia', 'trabalho', 'portátil']),
(3, ARRAY['moda', 'casual', 'algodão']);

-- Consultar usando operadores de array
SELECT 
    p.nome,
    tp.tags,
    array_length(tp.tags, 1) as numero_tags
FROM produtos p
JOIN tags_produto tp ON p.id = tp.produto_id
WHERE 'tecnologia' = ANY(tp.tags);
    nome     |           tags            | numero_tags 
-------------+---------------------------+-------------
 Smartphone  | {tecnologia,comunicação,móvel} |           3
 Laptop      | {tecnologia,trabalho,portátil} |           3
2. Funções JSON/JSONB

PostgreSQL tem excelente suporte para dados JSON, permitindo armazenar e consultar dados semi-estruturados.

-- Exemplo com JSONB (PostgreSQL)
-- Adicionar coluna JSON à tabela produtos
ALTER TABLE produtos ADD COLUMN especificacoes JSONB;

-- Atualizar com dados JSON
UPDATE produtos 
SET especificacoes = '{"peso": "150g", "cor": "preto", "garantia": "12 meses"}'::jsonb 
WHERE id = 1;

UPDATE produtos 
SET especificacoes = '{"peso": "2kg", "tela": "15.6", "memoria": "8GB"}'::jsonb 
WHERE id = 2;

-- Consultar dados JSON
SELECT 
    nome,
    especificacoes->>'peso' as peso,
    especificacoes->>'cor' as cor,
    especificacoes ? 'garantia' as tem_garantia
FROM produtos
WHERE especificacoes IS NOT NULL;
    nome     | peso | cor   | tem_garantia 
-------------+------+-------+--------------
 Smartphone  | 150g | preto | t
 Laptop      | 2kg  |       | f
3. Função GENERATE_SERIES()

Gera sequências de valores, muito útil para criar relatórios com períodos completos.

-- Gerar relatório de vendas por dia (PostgreSQL)
SELECT 
    data_serie::date as data,
    COALESCE(COUNT(p.id), 0) as pedidos,
    COALESCE(SUM(p.valor_total), 0) as total_vendas
FROM generate_series('2024-03-01'::date, '2024-03-10'::date, '1 day') as data_serie
LEFT JOIN pedidos p ON DATE(p.data_pedido) = data_serie::date
GROUP BY data_serie
ORDER BY data_serie;
    data    | pedidos | total_vendas 
------------+---------+--------------
 2024-03-01 |       1 |       929.98
 2024-03-02 |       1 |      1349.98
 2024-03-03 |       1 |        79.98
 2024-03-04 |       1 |       249.98
 2024-03-05 |       0 |         0.00
 2024-03-06 |       0 |         0.00
 2024-03-07 |       0 |         0.00
 2024-03-08 |       0 |         0.00
 2024-03-09 |       0 |         0.00
 2024-03-10 |       0 |         0.00
4. Função STRING_AGG()

Concatena valores de múltiplas linhas em uma única string, com separador personalizado.

-- Listar todos os produtos por categoria (PostgreSQL)
SELECT 
    c.nome as categoria,
    STRING_AGG(p.nome, ', ' ORDER BY p.nome) as produtos,
    COUNT(p.id) as total_produtos
FROM categorias c
LEFT JOIN produtos p ON c.id = p.categoria_id
GROUP BY c.id, c.nome;
  categoria  |       produtos        | total_produtos 
-------------+-----------------------+----------------
 Eletrônicos | Laptop, Smartphone    |              2
 Roupas      | Camiseta              |              1
 Livros      | Livro SQL             |              1
 Casa        | Mesa                  |              1

Parte 3: Funções Específicas do MySQL

1. Função GROUP_CONCAT()

Equivalente ao STRING_AGG do PostgreSQL, mas com sintaxe diferente.

-- Listar produtos por categoria (MySQL)
SELECT 
    c.nome as categoria,
    GROUP_CONCAT(p.nome ORDER BY p.nome SEPARATOR ', ') as produtos,
    COUNT(p.id) as total_produtos
FROM categorias c
LEFT JOIN produtos p ON c.id = p.categoria_id
GROUP BY c.id, c.nome;
+-------------+-----------------------+----------------+
| categoria   | produtos              | total_produtos |
+-------------+-----------------------+----------------+
| Eletrônicos | Laptop, Smartphone    |              2 |
| Roupas      | Camiseta              |              1 |
| Livros      | Livro SQL             |              1 |
| Casa        | Mesa                  |              1 |
+-------------+-----------------------+----------------+
2. Funções JSON (MySQL 5.7+)

MySQL também oferece suporte para JSON, mas com sintaxe ligeiramente diferente.

-- Trabalhar com JSON no MySQL
-- Adicionar coluna JSON
ALTER TABLE produtos ADD COLUMN detalhes JSON;

-- Inserir dados JSON
UPDATE produtos 
SET detalhes = JSON_OBJECT('peso', '150g', 'cor', 'preto', 'garantia', '12 meses')
WHERE id = 1;

-- Consultar dados JSON
SELECT 
    nome,
    JSON_EXTRACT(detalhes, '$.peso') as peso,
    JSON_EXTRACT(detalhes, '$.cor') as cor,
    JSON_CONTAINS_PATH(detalhes, 'one', '$.garantia') as tem_garantia
FROM produtos
WHERE detalhes IS NOT NULL;
+------------+--------+---------+--------------+
| nome       | peso   | cor     | tem_garantia |
+------------+--------+---------+--------------+
| Smartphone | "150g" | "preto" |            1 |
+------------+--------+---------+--------------+Code language: JavaScript (javascript)
3. Função FIND_IN_SET()

Específica do MySQL para buscar em listas separadas por vírgula.

-- Exemplo com FIND_IN_SET (MySQL)
-- Criar campo com lista de características
ALTER TABLE produtos ADD COLUMN caracteristicas VARCHAR(255);

UPDATE produtos SET caracteristicas = 'resistente,portátil,moderno' WHERE id = 1;
UPDATE produtos SET caracteristicas = 'leve,rápido,silencioso' WHERE id = 2;

-- Buscar produtos com característica específica
SELECT nome, caracteristicas
FROM produtos
WHERE FIND_IN_SET('portátil', caracteristicas) > 0;
+------------+-----------------------------+
| nome       | caracteristicas             |
+------------+-----------------------------+
| Smartphone | resistente,portátil,moderno |
+------------+-----------------------------+
4. Função IF()

Uma alternativa mais concisa ao CASE para condições simples.

-- Usar IF para classificações simples (MySQL)
SELECT 
    nome,
    preco,
    IF(preco > 500, 'Caro', 'Barato') as classificacao_preco,
    IF(estoque > 50, 'Alto', IF(estoque > 20, 'Médio', 'Baixo')) as nivel_estoque
FROM produtos;
+------------+---------+--------------------+--------------+
| nome       | preco   | classificacao_preco| nivel_estoque|
+------------+---------+--------------------+--------------+
| Smartphone |  899.99 | Caro               | Médio        |
| Laptop     | 1299.99 | Caro               | Médio        |
| Camiseta   |   29.99 | Barato             | Alto         |
| Livro SQL  |   49.99 | Barato             | Alto         |
| Mesa       |  199.99 | Barato             | Médio        |
+------------+---------+--------------------+--------------+

Casos de Uso Práticos

1. Análise de Coorte de Clientes

Vamos criar uma análise de coorte para entender o comportamento de recompra dos clientes.

-- Análise de coorte (funciona em ambos os SGBDs)
WITH primeira_compra AS (
    SELECT 
        cliente_id,
        MIN(DATE(data_pedido)) as data_primeira_compra
    FROM pedidos
    WHERE status = 'entregue'
    GROUP BY cliente_id
),
compras_mensais AS (
    SELECT 
        p.cliente_id,
        pc.data_primeira_compra,
        DATE(p.data_pedido) as data_compra,
        EXTRACT(MONTH FROM AGE(DATE(p.data_pedido), pc.data_primeira_compra)) as mes_desde_primeira
    FROM pedidos p
    JOIN primeira_compra pc ON p.cliente_id = pc.cliente_id
    WHERE p.status = 'entregue'
)
SELECT 
    data_primeira_compra,
    COUNT(DISTINCT CASE WHEN mes_desde_primeira = 0 THEN cliente_id END) as mes_0,
    COUNT(DISTINCT CASE WHEN mes_desde_primeira = 1 THEN cliente_id END) as mes_1,
    COUNT(DISTINCT CASE WHEN mes_desde_primeira = 2 THEN cliente_id END) as mes_2
FROM compras_mensais
GROUP BY data_primeira_compra
ORDER BY data_primeira_compra;
 data_primeira_compra | mes_0 | mes_1 | mes_2 
----------------------+-------+-------+-------
 2024-03-01           |     1 |     0 |     0
 2024-03-04           |     1 |     0 |     0
2. Detecção de Outliers

Identificar pedidos com valores anômalos usando funções estatísticas.

-- Detectar outliers em valores de pedidos
WITH estatisticas AS (
    SELECT 
        AVG(valor_total) as media,
        STDDEV(valor_total) as desvio_padrao
    FROM pedidos
    WHERE status = 'entregue'
)
SELECT 
    p.id,
    p.valor_total,
    e.media,
    ABS(p.valor_total - e.media) / e.desvio_padrao as z_score,
    CASE 
        WHEN ABS(p.valor_total - e.media) / e.desvio_padrao > 2 THEN 'Outlier'
        ELSE 'Normal'
    END as classificacao
FROM pedidos p
CROSS JOIN estatisticas e
WHERE p.status = 'entregue'
ORDER BY z_score DESC;
 id | valor_total |     media     |      z_scor    | classificacao 
----+-------------+---------------+----------------+---------------
  1 |      929.98 | 589.980000000 | 1.000000000000 | Normal
  4 |      249.98 | 589.980000000 | 1.000000000000 | Normal

Resumindo tudão:

Pensando em ajudar os pequenos garfanhotos com essas funções, aqui está um cheatsheet do SQL

FunçãoSintaxeDescrição
ROW_NUMBER()ROW_NUMBER() OVER (PARTITION BY col ORDER BY col)Numera linhas sequencialmente
RANK()RANK() OVER (ORDER BY col DESC)Ranking com pulos em empates
DENSE_RANK()DENSE_RANK() OVER (ORDER BY col DESC)Ranking sem pulos em empates
LAG()LAG(col, n) OVER (PARTITION BY col ORDER BY col)Acessa valor de linha anterior
LEAD()LEAD(col, n) OVER (PARTITION BY col ORDER BY col)Acessa valor de linha posterior
TipoSintaxeUso
CTE SimplesWITH nome AS (SELECT ...) SELECT * FROM nomeConsultas temporárias nomeadas
CTE RecursivoWITH RECURSIVE nome AS (SELECT ... UNION ALL SELECT ...)Hierarquias e séries
FunçãoSintaxeDescrição
COALESCE()COALESCE(col1, col2, 'default')Primeiro valor não nulo
CASECASE WHEN condição THEN valor ELSE outro ENDCondições complexas
CONCAT()CONCAT(str1, str2, str3)Concatenação de strings
CONCAT_WS()CONCAT_WS(separador, str1, str2)Concatenação com separador
SUBSTRING()SUBSTRING(string, posição, comprimento)Extrai parte da string
POSITION()POSITION(substring IN string)Localiza posição na string
Específicas do PostgreSQL
CategoriaFunçãoSintaxeDescrição
ArraysARRAY[]ARRAY['val1', 'val2']Cria array
ANY()WHERE 'valor' = ANY(array_col)Busca em array
array_length()array_length(array_col, 1)Tamanho do array
JSON->json_col->'key'Extrai como JSON
->>json_col->>'key'Extrai como texto
?json_col ? 'key'Verifica se key existe
Sériesgenerate_series()generate_series(1, 100, 1)Gera sequência numérica
generate_series('2024-01-01', '2024-12-31', '1 day')Gera sequência de datas
StringSTRING_AGG()STRING_AGG(col, ', ' ORDER BY col)Concatena valores agrupados
Específicas do MySQL
CategoriaFunçãoSintaxeDescrição
StringGROUP_CONCAT()GROUP_CONCAT(col ORDER BY col SEPARATOR ', ')Concatena valores agrupados
FIND_IN_SET()FIND_IN_SET('valor', 'lista,separada,virgula')Busca em lista CSV
CondicionalIF()IF(condição, valor_true, valor_false)Condicional simples
JSONJSON_OBJECT()JSON_OBJECT('key', value, 'key2', value2)Cria objeto JSON
JSON_EXTRACT()JSON_EXTRACT(json_col, '$.key')Extrai valor do JSON
JSON_CONTAINS_PATH()JSON_CONTAINS_PATH(json_col, 'one', '$.key')Verifica se path existe
Dicas de Performance
CenárioDicaExemplo
Window FunctionsUse PARTITION BY para limitar escopoOVER (PARTITION BY categoria_id)
CTEsPrefira CTEs a subqueries aninhadasWITH dados AS (...) SELECT * FROM dados
JSONCrie índices em campos JSON consultadosCREATE INDEX idx_json ON tab ((json_col->>'key'))
Arrays (PG)Use índices GIN para arraysCREATE INDEX idx_tags ON tab USING GIN (tags)
StringsCONCAT é mais eficiente que ||CONCAT(a, b, c) vs `a
Compatibilidade
FunçãoMySQLPostgreSQLNota
Window Functions✅ 8.0+
CTEs✅ 8.0+
CTEs Recursivos✅ 8.0+
JSON✅ 5.7+✅ 9.2+Sintaxes diferentes
ArraysMySQL: use JSON arrays
STRING_AGGMySQL: use GROUP_CONCAT
GROUP_CONCATPostgreSQL: use STRING_AGG

Dica Final: Sempre teste essas funções com seus dados reais e monitore a performance. Algumas funções podem necessitar de índices específicos para otimização adequada.


Comentários

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *