Voltar para a lista de artigos Artigos
10 minutos de leitura

Criando um “mecanismo de recomendação” personalizado em 10 linhas de SQL

Os motores de recomendação nem sempre começam com IA ou aprendizado de máquina. Em muitos casos, algumas consultas SQL bem escritas são suficientes para descobrir produtos que os clientes compram juntos com frequência. Neste artigo, você criará um motor de recomendação simples em cerca de 10 linhas de SQL usando auto-junções e agregação.

Quando você ouve “mecanismo de recomendação”, provavelmente pensa em aprendizado de máquina, notebooks Python e modelos complexos de IA. Essa associação se tornou tão comum que muitas vezes esquecemos quantas recomendações em sistemas reais são construídas sobre bases muito mais simples. Na prática, grande parte das recomendações de comércio eletrônico e marketing começa com SQL e uma questão analítica clara.

Uma das abordagens mais comuns é baseada na coocorrência. Se dois produtos aparecem juntos na mesma transação com frequência suficiente, essa relação é significativa do ponto de vista comercial. Essa lógica está por trás de padrões familiares, como seções “Os clientes também compraram”, pacotes de produtos, sugestões de vendas cruzadas e até mesmo algumas análises de segmentação de marketing. Não há previsão aqui no sentido de aprendizado de máquina — apenas contagem, comparação e classificação do que realmente aconteceu.

O SQL é particularmente adequado para esse tipo de trabalho. Com JOIN e GROUP BY, você pode analisar as relações dentro dos dados transacionais e transformar o histórico de compras bruto em insights acionáveis. Se você está familiarizado com esses conceitos, já tem quase tudo o que precisa para construir um mecanismo de recomendação básico.

Neste artigo, você criará um mecanismo básico de recomendação usando uma ideia: os clientes que compraram isso também compraram aquilo.

Produziremos recomendações reais usando apenas SQL analítico, sem Python ou bibliotecas de IA. Esse tipo de pensamento é exatamente o que a prática intermediária e avançada de SQL no LearnSQL.com.br foi projetada para desenvolver.

A questão comercial

Vamos tornar o problema mais concreto.

Imagine que você trabalha para uma loja online de eletrônicos. Um dos seus itens mais vendidos são fones de ouvido sem fio. Você deseja melhorar a página do produto, mostrando aos clientes quais outros produtos são mais frequentemente comprados junto com esses fones de ouvido.

A questão passa a ser:

Para o produto Fones de ouvido sem fio, quais são os três outros produtos mais frequentemente comprados na mesma transação?

Essa é uma questão simples, mas muito prática. A resposta pode ser usada diretamente em uma página de produto, em widgets de vendas cruzadas ou por uma equipe de marketing que planeja pacotes e promoções. Para um gerente de comércio eletrônico ou um analista de produto, esse tipo de insight é imediatamente acionável.

O modelo de dados

Para manter o exemplo realista, suponha que você trabalhe com um banco de dados típico de comércio eletrônico. Pedidos, produtos e itens comprados são armazenados separadamente, o que torna as consultas analíticas flexíveis e escalonáveis.

Usaremos três tabelas.

transactions — Esta tabela armazena informações sobre cada pedido concluído.

transaction_id transaction_date customer_id total_amount
1001 2024-05-01 501 249.00
1002 2024-05-01 502 179.00
1003 2024-05-02 501 219.00

Cada linha representa uma única transação feita por um cliente. Em sistemas reais, essa tabela geralmente inclui status de pagamento, método de envio ou moeda, mas esses detalhes não são relevantes para esta análise.

productsEsta tabela armazena o catálogo de produtos.

product_id product_name category price
101 Wireless Headphones Audio 199.00
102 Phone Case Accessories 29.00
103 USB-C Charger Accessories 49.00
104 Screen Protector Accessories 19.00

Essa tabela nos fornece nomes de produtos legíveis e permite filtrar ainda mais por categoria ou preço, se necessário.

transaction_items — Esta tabela vincula produtos a transações e é o núcleo da nossa análise.

transaction_id product_id quantity
1001 101 1
1001 102 1
1001 103 1
1002 101 1
1002 104 1
1003 101 1
1003 102 1

Cada linha representa um produto incluído em uma transação. Se um cliente comprar vários produtos em um único pedido, a transação aparecerá em várias linhas.

O design dessa tabela é extremamente comum em bancos de dados de produção e também é a estrutura usada em muitos exercícios práticos de LearnSQL.com.br. Se você deseja praticar com exatamente esse tipo de dados de loja — trabalhando com pedidos, produtos e itens de transação —, o curso Basic Trilha de Práticas em SQL: Store em LearnSQL.com.br é o próximo passo natural.

A ideia central: auto-junção

Antes de aplicá-la a produtos, vejamos um exemplo simples do que uma auto-junção realmente faz. Uma auto-junção é uma junção de uma tabela consigo mesma.

Imagine uma tabela chamada “employees” com as seguintes colunas: employee_id, employee_name, manager_id. Cada funcionário tem um gerente, e esse gerente também está armazenado na mesma tabela. Para exibir os funcionários junto com os nomes de seus gerentes, você não faz a junção com uma tabela diferente — você faz a junção da tabela employees consigo mesma.

Quando você usa a mesma tabela duas vezes em uma consulta, o SQL exige que cada cópia tenha seu próprio alias. Sem aliases, o SQL não saberia a qual instância da tabela você está se referindo. É melhor escolher aliases que reflitam a função que cada cópia desempenha na consulta, não apenas rótulos técnicos curtos.

Neste exemplo:

  • e representa o funcionário
  • m representa o gerente

Aqui está a consulta:

SELECT
    e.employee_name,
    m.employee_name AS manager_name
FROM employees e
JOIN employees m
    ON e.manager_id = m.employee_id;

Vamos ver como isso funciona.

O SQL lê a employees tabela duas vezes. Na primeira vez, ele trata as linhas como funcionários (e). Na segunda vez, ele trata as mesmas linhas como gerentes (m). A JOIN condição conecta as duas funções, combinando o manager_id com a do gerente employee_id. Como resultado, cada linha de funcionário é emparelhada com a linha que representa seu gerente.

Se as auto-junções parecem pouco intuitivas, esse padrão exato é amplamente praticado no curso Cláusulas JOIN em SQL em LearnSQL.com.br , incluindo uma seção dedicada às auto-junções.

Aplicando a auto-junção ao problema da recomendação

Para encontrar produtos comprados juntos, precisamos comparar produtos dentro da mesma transação. Isso significa unir a transaction_items tabela a si mesma e dar a cada cópia uma função clara. Uma instância representa o produto que estamos analisando e a outra representa os outros produtos que aparecem no mesmo pedido. O que os une transaction_id é o que os vincula.

Conceitualmente, isso se parece com:

  • a primeira instância representa o produto que nos interessa
  • a segunda instância representa os outros produtos na mesma transação

É aqui que uma auto-junção se torna extremamente útil. Ela permite que o SQL raciocine sobre as relações dentro do mesmo conjunto de dados, usando a mesma tabela vista de duas perspectivas diferentes.

Antes de escrever a consulta, vamos delinear a lógica passo a passo:

  • Pegue todos os produtos de uma transação
  • Combine cada produto com outros produtos da mesma transação
  • Exclua a correspondência de um produto consigo mesmo
  • Contar quantas vezes cada par de produtos aparece
  • Classificar os resultados por frequência
  • Retorne os principais resultados

Essa análise passo a passo é exatamente como os problemas analíticos de SQL devem ser abordados. A sintaxe vem por último. O raciocínio vem primeiro.

A consulta

Aqui está uma consulta completa que faz tudo isso em aproximadamente dez linhas de SQL:

SELECT
    t1.product_id AS base_product,
    t2.product_id AS recommended_product,
    COUNT(*) AS times_bought_together
FROM transaction_items t1
JOIN transaction_items t2
    ON t1.transaction_id = t2.transaction_id
   AND t1.product_id <> t2.product_id
WHERE t1.product_id = 101
GROUP BY t1.product_id, t2.product_id
ORDER BY times_bought_together DESC
LIMIT 3;

Esta consulta encontra os três produtos mais frequentemente comprados junto com o produto 101.

Vamos detalhar o que acontece aqui, passo a passo.

A consulta começa lendo a transaction_items tabela duas vezes. A primeira cópia, t1, representa o produto base que estamos analisando. A segunda cópia, t2, representa os outros produtos que aparecem na mesma transação. Dar a cada cópia um alias claro torna suas funções explícitas e mantém a consulta legível.

A JOIN condição conecta as linhas de ambas as cópias usando transaction_id. Isso garante que estamos comparando apenas produtos que foram comprados no mesmo pedido. A condição adicional t1.product_id <> t2.product_id impede que um produto seja combinado consigo mesmo, o que adicionaria pares sem sentido aos resultados.

A WHERE restringe a análise a um produto específico. Nesse caso, t1.product_id = 101 significa que estamos perguntando: quando o produto 101 aparece em uma transação, quais outros produtos aparecem junto com ele? É isso que transforma uma consulta geral de coocorrência em um mecanismo de recomendação concreto para um único produto.

Em seguida, a GROUP BY agrupa os resultados por pares de produtos: o produto base e o produto recomendado. Para cada par único, COUNT(*) conta quantas vezes essa combinação aparece em todas as transações. Essa contagem representa a força da relação entre os dois produtos.

A ORDER BY cláusula classifica esses pares do mais frequente ao menos frequente, e a LIMIT cláusula mantém apenas os três primeiros resultados. Esses são os três produtos mais frequentemente comprados junto com o produto 101.

O resultado é simples, mas poderoso: uma lista classificada de produtos relacionados com base inteiramente no comportamento real de compra. Sem previsões, sem modelos — apenas SQL expressando uma ideia analítica clara. Esse é o seu mecanismo de recomendação.

Como ler o resultado

A saída da consulta é semelhante a esta:

base_product recommended_product times_bought_together
101 102 2
101 103 1
101 104 1

Cada linha representa uma recomendação para o produto base.

Neste exemplo, o produto 101 (fones de ouvido sem fio) foi comprado com mais frequência junto com o produto 102 (capa de celular). O valor em times_bought_together mostra quantas transações continham os dois produtos. Quanto maior o número, mais forte é a relação entre os dois produtos.

Esse resultado pode ser usado diretamente em painéis, relatórios ou lógica de aplicativos — por exemplo, para alimentar uma seção “Os clientes também compraram” em uma página de produto ou para ajudar uma equipe de marketing a decidir quais produtos combinar.

Como ampliar isso com mais SQL

Depois de entender esse padrão, ampliá-lo se torna uma questão de fazer perguntas melhores, não de aprender novas ferramentas. A lógica central permanece a mesma; você simplesmente refina quais transações analisa e como interpreta os resultados.

Um primeiro passo comum é filtrar as transações por tempo. Você pode querer recomendações baseadas apenas nos últimos 30 dias ou na temporada atual, em vez de todos os dados históricos. Adicionar uma condição de data permite adaptar as recomendações ao comportamento de compra recente, que geralmente é mais relevante para decisões de marketing e merchandising.

Você também pode limitar a análise a segmentos específicos de clientes. Por exemplo, você pode querer ver quais produtos são comumente comprados juntos por clientes recorrentes, clientes de alto valor ou clientes de uma região específica. Isso transforma uma recomendação genérica em algo mais direcionado, sem alterar a estrutura geral da consulta.

A classificação é outra extensão natural. Em vez de depender apenas de ORDER BY e LIMIT, você pode usar funções de janela para classificar as recomendações por produto ou por segmento. Isso é especialmente útil quando você deseja gerar recomendações para muitos produtos de uma vez, em vez de analisar um produto por vez.

Por fim, muitas vezes vale a pena excluir ruídos de baixo volume. Produtos que foram comprados juntos apenas uma ou duas vezes podem não representar uma relação significativa. Adicionar um limite mínimo ajuda a garantir que as recomendações sejam baseadas em padrões consistentes, em vez de coincidências aleatórias.

Todas essas extensões dependem de técnicas analíticas de SQL: JOINs, agregações, filtragem e funções de janela. Essas são exatamente as habilidades desenvolvidas nos cursos intermediário e avançado dLearnSQL.com.br, onde padrões semelhantes aparecem repetidamente em cenários de negócios realistas.

O SQL é frequentemente o primeiro mecanismo de recomendação

Antes de recorrer a ferramentas Python ou de IA, vale a pena parar e fazer uma pergunta mais simples: o SQL já pode resolver esse problema? Como mostra este exemplo, em muitos cenários de negócios reais, a resposta é sim. Com uma pergunta clara e uma compreensão sólida de JOIN e agregações, o SQL é suficiente para transformar dados transacionais brutos em recomendações práticas.

É por isso que fundamentos sólidos de SQL são importantes. Se você consegue raciocinar sobre as relações entre os dados e expressar essa lógica claramente em SQL, pode criar soluções que agreguem valor real aos negócios sem complexidade desnecessária. Desenvolver esse tipo de confiança requer prática em muitos cenários realistas, não apenas em uma consulta.

Se você quiser ir além, o Ilimitado Vitalício SQL Plan em LearnSQL.com.br dá acesso a todos os cursos atuais de SQL e a todos os novos cursos adicionados no futuro. É uma maneira de desenvolver e expandir continuamente as habilidades exatas usadas neste artigo: pensamento analítico, trabalho com conjuntos de dados reais e transformação de questões comerciais em consultas SQL claras e eficazes.