← Voltar para conteúdos

Estudo / projeto

Guia para Evoluir de Júnior para Pleno em SQL

Para evoluir de um nível júnior para um nível pleno em SQL

Publicado em Jun 16, 2025

Guia para Evoluir de Júnior para Pleno em SQL

Para evoluir de um nível júnior para um nível pleno em SQL, é necessário desenvolver habilidades técnicas, práticas e conceituais, além de ganhar experiência em cenários reais. Abaixo está um guia com os principais pontos que você deve dominar ou aprimorar, dividido em categorias claras: Este guia é destinado a profissionais que já possuem uma base em SQL e desejam avançar para um nível pleno. O objetivo é fornecer um caminho claro e estruturado para aprimorar suas habilidades, cobrindo desde fundamentos até conceitos avançados, além de práticas recomendadas e exercícios práticos.

Objetivos

  • Dominar SQL: Aprender a escrever queries complexas, otimizar performance e entender conceitos avançados.
  • Modelagem de dados: Compreender como estruturar bancos de dados de forma eficiente.
  • Otimização de performance: Aprender a analisar e melhorar o desempenho de queries.
  • Integração com outras ferramentas: Conectar SQL com linguagens de programação e ferramentas de BI.
  • Experiência prática: Aplicar conhecimentos em projetos reais ou simulados.

Como Praticar os Exercícios

  • Datasets sugeridos:

  • Ferramentas:

    • Bancos: MySQL, PostgreSQL, SQLite (para testes locais).
    • IDEs: DBeaver, pgAdmin, SQL Server Management Studio.
    • Plataformas online: SQLFiddle, DB Fiddle, LeetCode.
  • Portfólio: Documente seus exercícios em um repositório no GitHub com o código SQL, explicações e resultados (ex.: capturas de tela ou CSVs).

Dicas para os Exercícios

  • Comece simples: Foque nos exercícios 1 e 2 para reforçar fundamentos.
  • Progrida gradualmente: Passe para exercícios avançados (3, 4, 6) à medida que ganhar confiança.
  • Peça feedback: Compartilhe suas queries em fóruns (ex.: Stack Overflow) ou com colegas sêniores.
  • Simule cenários reais: Tente replicar relatórios ou problemas do seu trabalho atual.
  • Documente seu aprendizado: Mantenha um diário de aprendizado com as queries que você escreveu, os problemas que resolveu e as lições aprendidas.

1. Fundamentos Sólidos em SQL

  • Domínio das operações básicas:

    • SELECT, INSERT, UPDATE, DELETE: Entenda como manipular dados com precisão, incluindo filtros (WHERE), ordenação (ORDER BY) e agrupamento (GROUP BY).

    • Joins: Domine INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL JOIN e CROSS JOIN. Saiba quando usar cada um e como otimizar queries com múltiplos joins. Joins

    • Funções agregadas: COUNT, SUM, AVG, MIN, MAX, e como combiná-las com GROUP BY e HAVING.

      • COUNT: Conta o número de linhas.
        SELECT COUNT(*) FROM vendas;
      • SUM: Soma valores.
        SELECT vendedor, SUM(valor) AS valor_total
        FROM vendas
        GROUP BY vendedor
        HAVING SUM(valor) > 1000;
      • AVG: Calcula a média.
        SELECT AVG(preco) AS preco_medio
        FROM produtos;  
      • MIN e MAX: Encontram o menor e maior valor, respectivamente.
        SELECT MIN(preco) AS preco_minimo, MAX(preco) AS preco_maximo
        FROM produtos;
    • GROUP BY: Agrupa resultados para aplicar funções agregadas.

      • HAVING: Filtra grupos após a agregação, diferentemente do WHERE, que filtra antes da agregação.
      • Exemplo de uso de GROUP BY e HAVING:
        SELECT vendedor, SUM(valor) AS valor_total
        FROM vendas
        GROUP BY vendedor
        HAVING SUM(valor) > 1000; 
        • Explicação:
        • FROM vendas: Seleciona a tabela de vendas.
        • GROUP BY vendedor: Agrupa os resultados por vendedor.
        • HAVING SUM(valor) > 1000: Filtra os grupos onde a soma dos valores de vendas é maior que 1000.
        • SELECT vendedor, SUM(valor) AS valor_total: Exibe o vendedor e o total de vendas.
    • WHERE vs HAVING: Entenda a diferença entre os dois.

      • WHERE: Filtra linhas antes da agregação.
        SELECT vendedor, SUM(valor) AS valor_total
        FROM vendas
        WHERE data_venda >= '2025-01-01'
        GROUP BY vendedor;
        • Explicação:
        • FROM vendas: Seleciona a tabela de vendas.
        • WHERE data_venda >= '2025-01-01': Filtra as vendas a partir de 1º de janeiro de 2025.
        • GROUP BY vendedor: Agrupa os resultados por vendedor.
        • SELECT vendedor, SUM(valor) AS valor_total: Exibe o vendedor e o total de vendas.
      • HAVING: Filtra grupos após a agregação.
        SELECT vendedor, SUM(valor) AS valor_total
        FROM vendas
        GROUP BY vendedor
        HAVING SUM(valor) > 1000;
        • Explicação:
        • FROM vendas: Seleciona a tabela de vendas.
        • GROUP BY vendedor: Agrupa os resultados por vendedor.
        • HAVING SUM(valor) > 1000: Filtra os grupos onde a soma dos valores de vendas é maior que 1000.
        • SELECT vendedor, SUM(valor) AS valor_total: Exibe o vendedor e o total de vendas.

    Exercício 1: Filtros e Agregações

    • Objetivo: Criar uma query que resuma vendas por categoria de produto em um período específico.
    • Tarefa: Usando uma tabela de vendas (order_id, product_id, category, order_date, amount), escreva uma query que:
      • Filtre pedidos de 2024.
      • Agrupe por categoria de produto.
      • Calcule o total de vendas (SUM(amount)) e a quantidade de pedidos (COUNT(order_id)).
      • Ordene por total de vendas em ordem decrescente.
    • Dica: Use GROUP BY, WHERE e ORDER BY. Teste com um dataset como o do Kaggle (ex.: "Retail Sales Dataset").
    • Extra: Adicione uma condição com HAVING para mostrar apenas categorias com mais de 100 pedidos.

    Exercício 2: Joins Complexos

    • Objetivo: Combinar múltiplas tabelas para obter informações detalhadas.
    • Tarefa: Em um banco com tabelas customers, orders e products, escreva uma query que:
      • Liste todos os clientes, mesmo aqueles sem pedidos (usando LEFT JOIN).
      • Inclua o nome do produto de cada pedido.
      • Mostre o total gasto por cliente.
    • Dica: Use LEFT JOIN entre customers e orders, e INNER JOIN entre orders e products. Trate valores nulos com COALESCE para o total gasto.
    • Extra: Adicione uma coluna que indique se o cliente é "ativo" (fez pedidos nos últimos 6 meses).
  • Manipulação de strings: Use funções como CONCAT, SUBSTRING, TRIM, UPPER, LOWER e REPLACE para manipular dados textuais.

    • CONCAT: Junta strings.
      SELECT CONCAT(nome, ' ', sobrenome) AS nome_completo
      FROM clientes;
    • SUBSTRING: Extrai parte de uma string.
      SELECT SUBSTRING(nome, 1, 5) AS nome_curto
      FROM clientes;
    • TRIM: Remove espaços em branco do início e do fim de uma string.
      SELECT TRIM(nome) AS nome_limpo
      FROM clientes;
    • UPPER: Converte uma string para maiúsculas.
      SELECT UPPER(nome) AS nome_maiusculo
      FROM clientes;
    • LOWER: Converte uma string para minúsculas.
      SELECT LOWER(nome) AS nome_minusculo
      FROM clientes;
    • REPLACE: Substitui parte de uma string por outra.
      SELECT REPLACE(nome, 'Antigo', 'Novo') AS nome_atualizado
      FROM clientes;
  • Data e hora: Trabalhe com tipos de dados de data e hora, usando funções como NOW(), DATEADD, DATEDIFF, FORMAT e EXTRACT.

    • NOW(): Retorna a data e hora atuais.
      SELECT NOW() AS data_atual;
    • DATEADD: Adiciona um intervalo a uma data.
      SELECT DATEADD(DAY, 7, data_venda) AS data_futura
      FROM vendas;
    • DATEDIFF: Calcula a diferença entre duas datas.
      SELECT DATEDIFF(DAY, data_inicio, data_fim) AS dias_diferenca
      FROM projetos;
    • FORMAT: Formata uma data em um formato específico.
      SELECT FORMAT(data_venda, 'dd/MM/yyyy') AS data_formatada
      FROM vendas;
    • EXTRACT: Extrai partes de uma data (ano, mês, dia, etc.).
      SELECT EXTRACT(YEAR FROM data_venda) AS ano_venda
      FROM vendas;
  • Tratamento de nulos: Use IS NULL, IS NOT NULL para lidar com valores nulos.

    • IS NULL: Verifica se um valor é nulo.
      SELECT nome
      FROM clientes
      WHERE email IS NULL;
    • IS NOT NULL: Verifica se um valor não é nulo.
      SELECT nome
      FROM clientes
      WHERE email IS NOT NULL;
  • Filtros avançados: Use CASE, COALESCE e NULLIF para manipulação de dados e tratamento de valores nulos.

    • CASE: Permite criar condições dentro de uma query, semelhante a um if em outras linguagens.

      SELECT produto, 
            CASE 
                WHEN categoria = 'Eletrônicos' THEN 'Tecnologia'
                WHEN categoria = 'Roupas' THEN 'Moda'
                ELSE 'Outros'
            END AS categoria_modificada
      FROM produtos;
      • COALESCE: Retorna o primeiro valor não nulo em uma lista de expressões.
      SELECT nome, COALESCE(email, 'sem email') AS email_contato
      FROM clientes;
      • NULLIF: Retorna NULL se os dois valores forem iguais, caso contrário, retorna o primeiro valor.
      SELECT produto, NULLIF(preco, 0) AS preco_unitario
      FROM produtos;
  • Operadores: Domine operadores lógicos (AND, OR, NOT), de comparação (=, <>, <, >, <=, >=) e de conjunto (IN, BETWEEN, LIKE).

    • Operadores lógicos:

      • AND: Combina condições, retornando resultados que atendem a todas as condições.

        SELECT nome
        FROM clientes 
        WHERE idade > 18 AND cidade = 'São Paulo';
      • OR: Retorna resultados que atendem a pelo menos uma das condições.

        SELECT nome
        FROM clientes 
        WHERE cidade = 'São Paulo' OR cidade = 'Rio de Janeiro';
      • NOT: Inverte a condição, retornando resultados que não atendem à condição especificada.

        SELECT nome
        FROM clientes 
        WHERE NOT cidade = 'São Paulo'; 
    • Operadores de comparação:

      • =: Igualdade.

        SELECT nome
        FROM clientes 
        WHERE idade = 30;  
      • <>: Diferença.

        SELECT nome
        FROM clientes 
        WHERE idade <> 30; 
      • <, >, <=, >=: Comparações numéricas.

        SELECT nome
        FROM clientes   
        WHERE idade > 18; 
    • Operadores de conjunto:

      • BETWEEN: Verifica se um valor está dentro de um intervalo.

        SELECT nome
        FROM clientes 
        WHERE idade BETWEEN 18 AND 30; 
      • BETWEEN também pode ser usado com datas:

        SELECT nome
        FROM clientes   
        WHERE data_cadastro BETWEEN '2024-01-01' AND '2024-12-31'; 
      • LIKE: Usado para busca de padrões em strings.

        SELECT nome
        FROM clientes 
        WHERE nome LIKE 'A%'; 
      • IN: Verifica se um valor está dentro de um conjunto.

        SELECT produto
        FROM produtos
        WHERE categoria IN ('Eletrônicos', 'Roupas'); 
  • Subqueries: Escreva subqueries correlacionadas e não correlacionadas, entendendo a diferença entre elas.

    • Subquery simples: Retorna um único valor ou uma lista de valores.

      SELECT nome
      FROM clientes
      WHERE id IN (SELECT cliente_id FROM pedidos WHERE valor > 100);
    • Subquery correlacionada: Depende de uma coluna da query externa.

      SELECT nome, (SELECT COUNT(*) FROM pedidos WHERE pedidos.cliente_id = clientes.id) AS total_pedidos
      FROM clientes;
      • Subquery não correlacionada: Não depende de nenhuma coluna da query externa.
      SELECT nome
      FROM clientes
      WHERE id IN (SELECT cliente_id FROM pedidos WHERE valor > 100);
  • Índices e desempenho: Compreenda como índices (CLUSTERED e NON-CLUSTERED) funcionam e como afetam a performance de queries.

    • Índices: Índices são estruturas de dados que permitem acesso rápido a linhas em uma tabela. Eles melhoram a performance de consultas, mas podem impactar operações de escrita (inserções, atualizações, exclusões).
      • CLUSTERED: Define a ordem física dos dados na tabela. Cada tabela pode ter apenas um índice clustered.
        CREATE CLUSTERED INDEX idx_nome ON clientes(nome);
      • NON-CLUSTERED: Cria um índice separado da tabela, permitindo múltiplos índices non-clustered por tabela.
        CREATE NONCLUSTERED INDEX idx_idade ON clientes(idade);

Dica: Pratique escrevendo queries complexas e otimizando-as. Use plataformas como LeetCode, HackerRank ou SQLZoo.

2. Conceitos Avançados

  • Common Table Expressions (CTEs): Saiba usar CTEs para simplificar queries complexas e melhorar a legibilidade.

    • CTE: Uma CTE é uma declaração que define uma tabela temporária que pode ser usada várias vezes em uma consulta.
  • Window Functions : Domine funções como ROW_NUMBER, RANK, DENSE_RANK, PARTITION BY e OVER para análises avançadas, como cálculos acumulados ou rankings.

    • PARTITION BY: Divide os resultados em grupos para aplicar funções de janela.

      SELECT nome, 
             SUM(salario) OVER (PARTITION BY departamento) AS total_departamento
      FROM funcionarios;
      • Explicação:
      • PARTITION BY departamento: Divide os resultados por departamento.
      • SUM(salario) OVER (PARTITION BY departamento): Calcula o total de salários por departamento, aplicando a função de janela SUM sobre cada partição.
    • OVER: Define a janela de dados sobre a qual a função de janela será aplicada.

      SELECT nome, 
             SUM(salario) OVER (ORDER BY data_contratacao) AS salario_acumulado
      FROM funcionarios;
      • Explicação:
      • ORDER BY data_contratacao: Ordena os funcionários pela data de contratação.
      • SUM(salario) OVER (ORDER BY data_contratacao): Calcula o salário acumulado ao longo do tempo, aplicando a função de janela SUM sobre a janela definida pela ordenação.
    • ROW_NUMBER: Atribui um número sequencial a cada linha dentro de uma partição.

      SELECT nome, 
        ROW_NUMBER() OVER (PARTITION BY departamento ORDER BY salario DESC) AS ranking
      FROM funcionarios;  
      • Explicação:
      • PARTITION BY departamento: Divide os resultados por departamento.
      • ORDER BY salario DESC: Ordena os funcionários por salário em ordem decrescente.
      • ROW_NUMBER(): Atribui um número sequencial a cada funcionário dentro do seu departamento, começando do 1.
    • RANK: Atribui um ranking, permitindo empates.

      SELECT nome, 
             RANK() OVER (PARTITION BY departamento ORDER BY salario DESC) AS ranking
      FROM funcionarios;
      • Explicação:
      • PARTITION BY departamento: Divide os resultados por departamento.
      • ORDER BY salario DESC: Ordena os funcionários por salário em ordem decrescente.
      • RANK(): Atribui um ranking a cada funcionário, permitindo empates. Se dois funcionários tiverem o mesmo salário, eles receberão o mesmo ranking, e o próximo ranking será pulado.
    • DENSE_RANK: Semelhante ao RANK, mas não pula rankings em caso de empate.

      SELECT nome, 
             DENSE_RANK() OVER (PARTITION BY departamento ORDER BY salario DESC) AS ranking
      FROM funcionarios;
      • Explicação:
      • PARTITION BY departamento: Divide os resultados por departamento.
      • ORDER BY salario DESC: Ordena os funcionários por salário em ordem decrescente.
      • DENSE_RANK(): Atribui um ranking a cada funcionário, sem pular rankings em caso de empate. Se dois funcionários tiverem o mesmo salário, eles receberão o mesmo ranking, mas o próximo ranking será o próximo número sequencial.

      Outras dicas sobre windows funcitions aqui

Exercício 3: Window Functions

  • Objetivo: Calcular rankings e acumulados com funções de janela.
  • Tarefa: Usando uma tabela de vendas (order_id, customer_id, amount, order_date), escreva uma query que:
    • Atribua um ranking (RANK) para cada cliente com base no total de vendas.
    • Calcule o total acumulado de vendas por cliente ao longo do tempo (SUM com OVER).
  • Dica: Use PARTITION BY customer_id e ORDER BY order_date para o acumulado. Teste com PostgreSQL ou SQL Server, pois MySQL tem limitações em versões antigas.
  • Extra: Adicione uma coluna com a diferença entre o amount do pedido atual e o pedido anterior do mesmo cliente.

Exercício 4: CTEs para Queries Complexas

  • Objetivo: Simplificar uma query complexa usando CTEs.

  • Tarefa: Em um dataset de funcionários (employee_id, department_id, salary, hire_date), escreva uma query que:

    • Use uma CTE para calcular o salário médio por departamento.
    • Junte a CTE com a tabela original para listar funcionários com salário acima da média do seu departamento.
  • Dica: Crie a CTE com SELECT department_id, AVG(salary) FROM employees GROUP BY department_id.

  • Extra: Adicione uma segunda CTE para contar o número de funcionários por departamento e inclua essa informação na query final.

  • Observação: CTEs são úteis para evitar a necessidade de subconsultas complexas e melhorar a legibilidade do código.

  • Stored Procedures e Functions: Aprenda a criar e usar procedures e funções para encapsular lógica de negócio no banco.

    • Stored Procedures: São blocos de código SQL que podem ser executados no banco de dados. Elas permitem encapsular lógica complexa e reutilizar código.
      • Criação de uma Stored Procedure:
        CREATE PROCEDURE calcular_bonus(IN funcionario_id INT)
        BEGIN
            DECLARE bonus DECIMAL(10,2);
            SELECT salario * 0.1 INTO bonus FROM funcionarios WHERE id = funcionario_id;
            UPDATE funcionarios SET bonus = bonus WHERE id = funcionario_id;
        END;
      • Execução de uma Stored Procedure:
        CALL calcular_bonus(1);
  • Triggers: Entenda como criar triggers para automatizar ações no banco, como auditoria ou validações.

    • Triggers: São procedimentos que são automaticamente executados em resposta a eventos específicos no banco de dados, como inserções, atualizações ou exclusões.
      • Criação de um Trigger:
        CREATE TRIGGER antes_de_atualizar_salario
        BEFORE UPDATE ON funcionarios
        FOR EACH ROW
        BEGIN
            IF NEW.salario < 0 THEN
                SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Salário não pode ser negativo';
            END IF;
        END;
      • Explicação:
        • BEFORE UPDATE ON funcionarios: O trigger será executado antes de qualquer atualização na tabela funcionarios.
        • FOR EACH ROW: O trigger será executado para cada linha afetada pela atualização.
        • IF NEW.salario < 0 THEN: Verifica se o novo salário é negativo.
        • SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Salário não pode ser negativo';: Lança um erro se a condição for verdadeira, impedindo a atualização.
    • Tipos de Triggers:
      • BEFORE: Executado antes de uma operação (INSERT, UPDATE, DELETE).
      • AFTER: Executado após uma operação.
      • INSTEAD OF: Executado no lugar de uma operação, útil para views.
    • Exemplo de Trigger:
      • Trigger de Auditoria: Registra alterações em uma tabela de auditoria.
        CREATE TRIGGER auditoria_atualizacao
        AFTER UPDATE ON funcionarios
        FOR EACH ROW
        BEGIN
            INSERT INTO auditoria (funcionario_id, campo, valor_antigo, valor_novo, data)
            VALUES (NEW.id, 'salario', OLD.salario, NEW.salario, NOW());
        END;
      • Explicação:
        • AFTER UPDATE ON funcionarios: O trigger será executado após uma atualização na tabela funcionarios.
        • FOR EACH ROW: O trigger será executado para cada linha afetada pela atualização.
        • INSERT INTO auditoria: Insere um registro na tabela de auditoria com os detalhes da atualização.
        • NEW.id, 'salario, OLD.salario, NEW.salario, NOW(): Captura o ID do funcionário, o campo alterado, o valor antigo, o novo valor e a data da alteração.
    • Dicas para Triggers:
      • Evite lógica complexa: Mantenha os triggers simples para evitar problemas de performance e manutenção.
      • Teste cuidadosamente: Triggers podem causar efeitos colaterais inesperados, então teste-os em um ambiente controlado antes de aplicá-los em produção.
  • Transações: Compreenda o uso de BEGIN TRANSACTION, COMMIT e ROLLBACK para garantir consistência de dados.

    • Transações: São conjuntos de operações que são executadas como um único bloco. Elas garantem que todas as operações sejam concluídas com sucesso ou nenhuma delas seja aplicada, mantendo a integridade dos dados.
      • BEGIN TRANSACTION: Inicia uma nova transação.
        BEGIN TRANSACTION;
      • COMMIT: Confirma todas as operações realizadas na transação, tornando-as permanentes.
        COMMIT;
      • ROLLBACK: Desfaz todas as operações realizadas na transação, revertendo os dados ao estado anterior.
        • Exemplo de uso de transações:
        BEGIN TRANSACTION;
        UPDATE contas SET saldo = saldo - 100 WHERE id = 1;
        UPDATE contas SET saldo = saldo + 100 WHERE id = 2;
        IF @@ERROR <> 0 THEN
            ROLLBACK;
        ELSE
            COMMIT;
        END IF;

3. Modelagem de Dados

  • Normalização: Entenda as formas normais (1NF, 2NF, 3NF) e quando aplicá-las para evitar redundâncias.

    • 1NF (Primeira Forma Normal): Cada atributo deve ser único e não deve conter valores repetidos. Tabelas devem ter uma chave primária.
      • Exemplo: Uma tabela de clientes onde cada cliente tem um ID único, nome e email.
        CREATE TABLE clientes (
            cliente_id INT PRIMARY KEY,
            nome VARCHAR(100),
            email VARCHAR(100)
        );
      • 2NF (Segunda Forma Normal): Cada atributo não-chave deve depender completamente da chave primária. Elimine dependências parciais.
      • Exemplo: Uma tabela de pedidos onde cada pedido tem um ID único e um cliente associado, mas o nome do cliente não deve ser armazenado na tabela de pedidos, pois depende apenas do cliente.
        CREATE TABLE pedidos (
            pedido_id INT PRIMARY KEY,
            cliente_id INT,
            produto VARCHAR(100),
            quantidade INT,
            FOREIGN KEY (cliente_id) REFERENCES clientes(cliente_id)
        );
        • 3NF (Terceira Forma Normal): Se uma tabela estiver em 2NF, mas ainda tiver atributos que dependem de outros atributos não-chave, deve-se remover essas dependências transitivas.
        • Exemplo: Uma tabela de pedidos onde cada pedido tem um ID único e um cliente associado, e o produto não deve conter informações adicionais que dependam de outro atributo, como categoria.
          CREATE TABLE produtos (
              produto_id INT PRIMARY KEY,
              nome VARCHAR(100),
              categoria VARCHAR(50)
          );
          • Exemplo de tabela normalizada:
            CREATE TABLE clientes (
                cliente_id INT PRIMARY KEY,
                nome VARCHAR(100),
                email VARCHAR(100)
            );
            
            CREATE TABLE pedidos (
                pedido_id INT PRIMARY KEY,
                cliente_id INT,
                produto_id INT,
                quantidade INT,
                FOREIGN KEY (cliente_id) REFERENCES clientes(cliente_id),
                FOREIGN KEY (produto_id) REFERENCES produtos(produto_id)
            );
            
            CREATE TABLE produtos (
                produto_id INT PRIMARY KEY,
                nome VARCHAR(100),
                categoria VARCHAR(50)
            );
  • Desnormalização: Saiba quando desnormalizar para melhorar performance, especialmente em sistemas de relatórios.

    • Desnormalização: Em alguns casos, pode ser vantajoso desnormalizar dados para melhorar a performance de leitura, especialmente em sistemas de relatórios ou OLAP. Isso envolve combinar tabelas ou duplicar dados para evitar joins complexos.
      • Exemplo de desnormalização: Combinar informações de clientes e pedidos em uma única tabela para consultas frequentes.
        CREATE TABLE pedidos_completos (
            pedido_id INT PRIMARY KEY,
            cliente_nome VARCHAR(100),
            produto VARCHAR(100),
            quantidade INT
        );
      • Dica: Use desnormalização com cautela, pois pode levar a redundâncias e inconsistências nos dados.
  • Relacionamentos: Domine chaves primárias, chaves estrangeiras e como modelar relacionamentos 1:1, 1:N e N:N.

  • Chaves primárias: Identificam de forma única cada registro em uma tabela.

    • Exemplo: cliente_id em uma tabela de clientes.
      CREATE TABLE clientes (
          cliente_id INT PRIMARY KEY,
          nome VARCHAR(100),
          email VARCHAR(100)
      );
  • Chaves estrangeiras: Referenciam chaves primárias em outras tabelas, estabelecendo relacionamentos.

    • Exemplo: cliente_id em uma tabela de pedidos que referencia a tabela de clientes.
      CREATE TABLE pedidos (
          pedido_id INT PRIMARY KEY,
          cliente_id INT,
          produto VARCHAR(100),
          quantidade INT,
          FOREIGN KEY (cliente_id) REFERENCES clientes(cliente_id)
      );
  • Relacionamentos:

    • 1:1 (Um para Um): Cada registro em uma tabela corresponde a um único registro em outra tabela.
      • Exemplo: Uma tabela de usuários e uma tabela de perfis, onde cada usuário tem um perfil único.
        CREATE TABLE usuarios (
            usuario_id INT PRIMARY KEY,
            nome VARCHAR(100),
            email VARCHAR(100)
        );
        CREATE TABLE perfis (
            perfil_id INT PRIMARY KEY,
            usuario_id INT UNIQUE,
            bio TEXT,
            FOREIGN KEY (usuario_id) REFERENCES usuarios(usuario_id)
        );
    • 1:N (Um para Muitos): Um registro em uma tabela pode estar relacionado a vários registros em outra tabela.
      • Exemplo: Uma tabela de clientes e uma tabela de pedidos, onde cada cliente pode ter vários pedidos.
        CREATE TABLE clientes (
            cliente_id INT PRIMARY KEY,
            nome VARCHAR(100),
            email VARCHAR(100)
        );
        CREATE TABLE pedidos (
            pedido_id INT PRIMARY KEY,
            cliente_id INT,
            produto VARCHAR(100),
            quantidade INT,
            FOREIGN KEY (cliente_id) REFERENCES clientes(cliente_id)
        );
    • N:N (Muitos para Muitos): Vários registros em uma tabela podem estar relacionados a vários registros em outra tabela. Isso é feito através de uma tabela intermediária.
      • Exemplo: Uma tabela de alunos e uma tabela de cursos, onde um aluno pode estar matriculado em vários cursos e um curso pode ter vários alunos.
        CREATE TABLE alunos (
            aluno_id INT PRIMARY KEY,
            nome VARCHAR(100),
            email VARCHAR(100)
        );
        CREATE TABLE cursos (
            curso_id INT PRIMARY KEY,
            nome VARCHAR(100)
        );
        CREATE TABLE matriculas (
            aluno_id INT,
            curso_id INT,
            PRIMARY KEY (aluno_id, curso_id),
            FOREIGN KEY (aluno_id) REFERENCES alunos(aluno_id),
            FOREIGN KEY (curso_id) REFERENCES cursos(curso_id)
        );

    Exercício 5: Normalização

  • Objetivo: Transformar uma tabela não normalizada em 3NF.

  • Tarefa: Dado um dataset não normalizado (ex.: tabela com order_id, customer_name, customer_address, product_name, product_category, amount), crie:

    • Tabelas normalizadas (customers, products, orders).
    • Escreva o SQL para criar as tabelas com chaves primárias e estrangeiras.
    • Insira dados de exemplo e teste com uma query que junte as tabelas.
  • Dica: Identifique redundâncias (ex.: customer_name repetido) e separe em tabelas relacionadas.

  • Extra: Crie um diagrama ER simples (pode ser desenhado à mão ou em ferramentas como Lucidchart).

  • Diagramas ER: Saiba criar e interpretar diagramas de entidade-relacionamento.

    • Diagramas ER (Entidade-Relacionamento): São representações gráficas de entidades (tabelas) e seus relacionamentos. Eles ajudam a visualizar a estrutura do banco de dados e a identificar chaves primárias, chaves estrangeiras e relacionamentos.
      • Exemplo de diagrama ER:
        • Entidades: clientes, pedidos, produtos.
        • Relacionamentos: clientes tem muitos pedidos, pedidos contém muitos produtos.
        • Ferramentas: Use ferramentas como Lucidchart, Draw.io ou até mesmo papel e caneta para desenhar diagramas ER simples.

Exercício 6: Consultas

  • Objetivo: Escrever consultas SQL para resolver problemas de negócios.
  • Tarefa: Dado um dataset de vendas (order_id, customer_id, product_id, order_date, amount), escreva queries que:
    • Calcule o total de vendas por mês.
    • Liste os 10 produtos mais vendidos.
    • Encontre os clientes com maior gasto total.
  • Dica: Use GROUP BY, ORDER BY e funções de agregação como SUM, COUNT e AVG.
  • Extra: Crie uma view que mostre o total de vendas por cliente e mês, facilitando relatórios futuros.

4. Otimização de Performance

  • Análise de Query Plans: Aprenda a ler planos de execução (EXPLAIN PLAN ou equivalentes) para identificar gargalos.
    • EXPLAIN: Use o comando EXPLAIN para analisar o plano de execução de uma query e identificar possíveis gargalos de performance.
      • Exemplo:
        EXPLAIN SELECT nome, SUM(salario) 
        FROM funcionarios 
        GROUP BY nome;
      • Explicação:
        • EXPLAIN: Informa ao banco de dados que você deseja ver o plano de execução da query.
        • SELECT nome, SUM(salario): Seleciona o nome dos funcionários e a soma dos salários.
        • FROM funcionarios: Indica a tabela de onde os dados serão extraídos.
        • GROUP BY nome: Agrupa os resultados pelo nome do funcionário.
  • Otimização de consultas: Aprenda a otimizar queries, evitando joins desnecessários, usando índices e evitando subconsultas complexas.
    • Dicas de otimização:
      • Use índices: Crie índices em colunas frequentemente usadas em filtros (WHERE), junções (JOIN) e ordenações (ORDER BY).
        CREATE INDEX idx_nome ON funcionarios(nome);
      • Evite joins desnecessários: Use apenas as tabelas necessárias para a consulta.
      • Minimize subconsultas: Use joins ou CTEs quando possível, pois subconsultas podem ser menos eficientes.
      • Use EXISTS em vez de IN: Em alguns casos, EXISTS pode ser mais eficiente que IN.
        SELECT nome 
        FROM funcionarios 
        WHERE EXISTS (SELECT 1 FROM departamentos WHERE departamentos.id = funcionarios.departamento_id);
      • Limite o número de registros retornados: Use LIMIT ou TOP para restringir o número de resultados.
        SELECT nome FROM funcionarios ORDER BY salario DESC LIMIT 10;
  • Índices Estratégicos: Saiba quando criar índices compostos ou cobertos e como evitar over-indexing.
    • Dicas de índices:
  • Evitar maus hábitos: Minimize o uso de SELECT *, subqueries desnecessárias ou loops em procedures.
  • Particionamento e Sharding: Entenda como particionar tabelas grandes ou distribuir dados em bancos maiores.

Exercício 6: Análise e Otimização de Query

  • Objetivo: Identificar e melhorar uma query lenta.
  • Tarefa: Escreva uma query que filtre uma tabela grande (ex.: orders com milhões de registros) por data e categoria, sem índices. Então:
    • Use EXPLAIN (ou equivalente) para analisar o plano de execução.
    • Crie um índice apropriado (ex.: índice composto em order_date e category).
    • Compare o desempenho antes e depois do índice.
  • Dica: Use um dataset grande (ex.: do Google BigQuery) or gere dados sintéticos com ferramentas como pgbench (PostgreSQL).
  • Extra: Teste o impacto de adicionar um índice desnecessário (over-indexing) na performance de INSERT.

5. Conhecimento de Bancos Específicos

  • Dialetos SQL: Cada banco de dados (MySQL, PostgreSQL, SQL Server, Oracle, etc.) tem particularidades. Estude as diferenças em sintaxe, funções específicas e ferramentas de administração.
  • Ferramentas de administração: Familiarize-se com ferramentas como pgAdmin (PostgreSQL), SQL Server Management Studio (SSMS) ou Oracle SQL Developer.
  • Configurações do banco: Entenda conceitos como configuração de memória, cache e tuning básico do servidor.

Exercício 7: SQL + Python

  • Objetivo: Conectar SQL a Python para análise de dados.

  • Tarefa: Usando Python com pandas e SQLAlchemy, conecte-se a um banco (ex.: SQLite ou PostgreSQL) e:

    • Execute uma query que calcule o total de vendas por mês.
    • Exporte o resultado para um arquivo CSV.
    • Gere um gráfico simples (ex.: barras) com matplotlib.
  • Dica: Use um dataset público como o "Northwind" ou "AdventureWorks".

  • Extra: Crie um script que automatize a extração diária de dados e envie por e-mail (usando smtplib).

  • Objetivo: Implementar auditoria com triggers.

  • Tarefa: Em uma tabela de produtos (product_id, name, price), crie:

    • Uma tabela de auditoria (audit_log) para registrar alterações no preço.
    • Um trigger que insira um registro em audit_log sempre que o preço de um produto for atualizado.
  • Dica: Use AFTER UPDATE no trigger e capture valores antigos e novos com OLD e NEW (em PostgreSQL/MySQL).

  • Extra: Adicione uma query que mostre o histórico de alterações de preço para um produto específico.

6. Habilidades Práticas e de Negócio

  • Resolução de problemas reais: Participe de projetos onde você precise extrair insights de dados, criar relatórios ou resolver problemas de negócio com SQL.
  • Integração com outras ferramentas: Aprenda a conectar SQL com linguagens como Python (usando bibliotecas como SQLAlchemy ou pandas) ou ferramentas de BI (Power BI, Tableau).
  • Documentação e legibilidade: Escreva queries claras, com comentários e padrões de nomenclatura consistentes.
  • Segurança: Entenda como evitar SQL Injection e implementar boas práticas de segurança, como controle de acesso e criptografia de dados sensíveis.

7. Soft Skills e Experiência

  • Comunicação: Saiba explicar suas queries e decisões técnicas para equipes não técnicas (ex.: analistas de negócio).
  • Colaboração: Trabalhe bem com desenvolvedores, analistas de dados e administradores de banco (DBAs).
  • Proatividade: Identifique problemas de performance ou modelagem antes que sejam apontados.
  • Experiência prática: Busque projetos reais, como freelas, contribuições em open-source ou desafios internos na empresa.

8. Certificações e Estudo Contínuo

  • Considere certificações específicas, como:
    • Microsoft Certified: Data Analyst Associate (para SQL Server).
    • Oracle Database SQL Certified Associate.
    • PostgreSQL Certified Professional (se disponível).
  • Estude livros como:
    • SQL Performance Explained de Markus Winand.
    • SQL for Data Scientists de Renee M. P. Teate.
  • Acompanhe blogs, fóruns e comunidades como Stack Overflow, Reddit ou grupos no X para se manter atualizado.

9. Prática e Portfólio

  • Projetos práticos: Crie um portfólio com exemplos de queries complexas, scripts de automação ou dashboards baseados em SQL.
  • Datasets reais: Use datasets públicos (Kaggle, Google BigQuery) para simular cenários de negócio.
  • Simulações de entrevistas: Pratique resolver problemas de SQL em tempo real, como os encontrados em entrevistas técnicas.

10. Mindset de Pleno

  • Autonomia: Resolva problemas sem depender de supervisão constante.
  • Visão de negócio: Entenda como suas queries impactam o negócio (ex.: relatórios que orientam decisões estratégicas).
  • Mentoria: Comece a ajudar colegas juniores, compartilhando conhecimento.

Plano de Ação

  1. Avalie seu nível atual: Identifique lacunas em suas habilidades com testes práticos ou revisando projetos.
  2. Estude e pratique diariamente: Dedique 1-2 horas por dia a exercícios e projetos.
  3. Participe de projetos reais: Busque oportunidades na empresa ou em freelas para aplicar o conhecimento.
  4. Peça feedback: Mostre suas queries a colegas sêniores ou DBAs para sugestões de melhoria.
  5. Monitore sua evolução: Após 6-12 meses de prática consistente, avalie se você está pronto para assumir responsabilidades de um pleno.

Recursos Adicionais

  • Cursos online: Plataformas como Coursera, Udemy e DataCamp oferecem cursos avançados em SQL.
  • Livros: SQL Performance Explained (Markus Winand).
  • Blogs e sites: SQLServerCentral, DataCamp Blog, Mode Analytics SQL Tutorial.
  • Comunidades: Participe de fóruns como Stack Overflow, Reddit (r/SQL) e grupos no LinkedIn para trocar experiências e tirar dúvidas.

Publicado por Jefferson Peixoto em 07 de junho de 2025

Jefferson Peixoto | Data & AI Analyst