Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
__pycache__/
*.pyc
*.pyo
*.pyd
venv/
.env
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added desafio_RafaelaAyres/output/top_10_filmes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
96 changes: 96 additions & 0 deletions desafio_RafaelaAyres/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Desafio Técnico: Analista de Dados e BI (Python/SQL)

Olá! Meu nome é **Rafaela Ayres** e este repositório contém a minha resolução para o desafio técnico do processo seletivo para a vaga de **Analista de Dados e BI (Python/SQL - Remoto)**.

O desafio é composto por duas frentes principais:

- **3 Testes de consultas em SQL**
- **3 Cases práticos desenvolvidos em Python**

---

## 🚀 Como Executar o Projeto

Para garantir a reprodutibilidade dos scripts, certifique-se de ter o **Python 3** instalado em sua máquina e siga os passos abaixo no seu terminal:

### 1. Clonar o repositório e acessar a pasta do projeto

```bash
cd desafio_RafaelaAyres
```

### 2. Configurar o Ambiente Virtual (venv)

Crie e ative o ambiente isolado para evitar conflitos de dependências:

**Linux / macOS:**

```bash
python3 -m venv venv
source venv/bin/activate
```

**Windows (Prompt de Comando / PowerShell):**

```bash
python -m venv venv
.\venv\Scripts\activate
```

### 3. Instalar as Dependências

Com o ambiente virtual ativo, instale os pacotes necessários listados dentro da pasta:

```bash
pip install -r requirements.txt
```

> **Nota:** Certifique-se de que o arquivo de requerimentos está nesta pasta antes de rodar o comando.

---

## ⚙️ Estrutura do Projeto e Conexão

### Conexão com o Banco de Dados

Toda a lógica de autenticação e comunicação com o banco de dados está centralizada na pasta de módulos principais:

- 📂 `src/conexao_db.py`

---

## 📊 Resolução dos Testes

### 1. Testes SQL

Os arquivos de consulta estruturada contendo a lógica individual de cada questão estão localizados em:

- 📂 `sql/questao_1.sql`
- 📂 `sql/questao_2.sql`
- 📂 `sql/questao_3.sql`

Para visualizar as saídas e resultados reais dessas consultas no terminal, execute o script unificado de respostas:

```bash
python src/respostas_questoes.py
```

### 2. Cases Python

Os scripts de manipulação de dados, lógica de negócios e análises gráficas estão separados por arquivos dentro do diretório de cases:

- 📂 `src/cases/questao_1.py`
- 📂 `src/cases/questao_2.py`
- 📂 `src/cases/questao_3.py`

**Como executar:** Você pode rodar cada arquivo separadamente para analisar os outputs. Exemplo:

```bash
python src/cases/questao_1.py
```

> 📌 **Observação sobre a Questão 3:** Os gráficos e visualizações gerados por este script serão salvos automaticamente no diretório de saída em `src/output/`.

---

Disponível para feedbacks e dúvidas técnicas sobre a arquitetura da solução!
17 changes: 17 additions & 0 deletions desafio_RafaelaAyres/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
contourpy==1.3.3
cycler==0.12.1
fonttools==4.63.0
greenlet==3.5.1
kiwisolver==1.5.0
matplotlib==3.10.9
numpy==2.4.6
packaging==26.2
pandas==3.0.3
pillow==12.2.0
PyMySQL==1.2.0
pyparsing==3.3.2
python-dateutil==2.9.0.post0
seaborn==0.13.2
six==1.17.0
SQLAlchemy==2.0.49
typing_extensions==4.15.0
Empty file.
6 changes: 6 additions & 0 deletions desafio_RafaelaAyres/sql/questao_1.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- 1) Quais são os 10 produtos mais caros da empresa?

SELECT product_cod as codigo, product_name as nome_produto, product_val as valor_produto, dep_name as departamento
FROM data_product
ORDER BY Product_val DESC
LIMIT 10;
6 changes: 6 additions & 0 deletions desafio_RafaelaAyres/sql/questao_2.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- 2) Quais são as seções dos departamentos 'BEBIDAS' e 'PADARIA'?

SELECT DISTINCT section_cod AS cod_secao, section_name AS secao, DEP_cod AS cod_dep, dep_name AS departamento
FROM data_product
WHERE dep_name IN ('BEBIDAS', 'PADARIA')
ORDER BY dep_name, section_name;
8 changes: 8 additions & 0 deletions desafio_RafaelaAyres/sql/questao_3.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-- 3) Qual foi o total de vendas de produtos (em dólares) de cada área de negócios no primeiro trimestre de 2019?

SELECT store.business_name AS area_de_negocios, SUM(sales.sales_value) AS total_vendas
FROM data_store_cad as store
JOIN data_store_sales as sales
WHERE store.store_code = sales.store_code AND sales.date BETWEEN '2019-01-01' AND '2019-03-31'
GROUP BY store.business_name
ORDER BY total_vendas DESC;
Empty file.
Empty file.
55 changes: 55 additions & 0 deletions desafio_RafaelaAyres/src/cases/questao_1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# 1) A equipe de desenvolvimento estava cansada de desenvolver as mesmas consultas de sempre,
# variando apenas os filtros de acordo com as exigências do chefe.

import pandas as pd
from src.conexao_db import get_engine

engine = get_engine()

def retrieve_data(product_code=None, store_code=None, date=None):

query = "SELECT * FROM data_product_sales WHERE 1=1"

if product_code is not None:
query += f" AND PRODUCT_CODE = {product_code}"

if store_code is not None:
query += f" AND STORE_CODE = {store_code}"

if date is not None:
query += f" AND DATE BETWEEN '{date[0]}' AND '{date[1]}'"

df = pd.read_sql(query, engine)

return df

#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#= LISTA DE TESTES #=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=

teste_product = retrieve_data(
product_code=None,
store_code=7,
date=None
)

teste_store = retrieve_data(
product_code=18,
store_code=None,
date=None
)

teste_data = retrieve_data(
product_code=None,
store_code=None,
date=['2019-01-01', '2019-01-31']
)

#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#= RESULTADOS #=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=

print("\nTeste por código de produto:")
print(teste_product)

print("Teste por código de loja:")
print(teste_store)

print("\nTeste por intervalo de datas:")
print(teste_data)
63 changes: 63 additions & 0 deletions desafio_RafaelaAyres/src/cases/questao_2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# pylint : disable=line-too-long
# 2) Um novo cliente lhe enviou duas consultas prontas para serem respondidas. Elas estão listadas abaixo:

import pandas as pd
from src.conexao_db import get_engine

engine = get_engine()

#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#= CONSULTAS #=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=

consulta_1 = """
SELECT
STORE_CODE,
STORE_NAME,
START_DATE,
END_DATE,
BUSINESS_NAME,
BUSINESS_CODE
FROM data_store_cad
"""

consulta_2 = """
SELECT
STORE_CODE,
DATE,
SALES_VALUE,
SALES_QTY
FROM data_store_sales
WHERE DATE BETWEEN '2019-01-01' AND '2019-12-31'
"""

#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#= MERGE DAS CONSULTAS #=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=

df1 = pd.read_sql(consulta_1, engine)
df2 = pd.read_sql(consulta_2, engine)

merge_consultas = df1.merge(df2, on="STORE_CODE", how="inner")

df_final = (
merge_consultas
.groupby(["STORE_NAME", "BUSINESS_NAME"], as_index=False)
.agg({
"SALES_VALUE": "sum",
"SALES_QTY": "sum"
})
)

#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#= TRATAMENTO #=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=

df_final["TM"] = (df_final["SALES_VALUE"] / df_final["SALES_QTY"]).round(2)

df_final = df_final.rename(columns={
'STORE_NAME': 'Loja',
'BUSINESS_NAME': 'Categoria'
})

df_final = df_final[["Loja", "Categoria", "TM"]].to_string(index=False)

#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#= RESULTADOS #=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=

print("\nQuestão 2:")
print(df_final)

66 changes: 66 additions & 0 deletions desafio_RafaelaAyres/src/cases/questao_3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# 3) Criando sua própria visualização
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from src.conexao_db import get_engine

engine = get_engine()

#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#= CONSULTAS #=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=

# O top 10 dos filmes mais bem avaliados do IMDB

Consulta_1 = """
SELECT Title AS 'Filme', Genre AS 'Gênero', Year as 'Ano de lançamento', Votes as 'Votos'
FROM IMDB_movies
ORDER BY Votos DESC
LIMIT 10;
"""

# Os gêneros dos filmes que tem maior receita em bilheteria no ano de 2016

consulta_2 = """
SELECT Genre AS 'Gênero', SUM(RevenueMillions) as 'Receita Total(USD Milhões)'
FROM IMDB_movies
WHERE year = 2016
GROUP BY Genre
ORDER BY SUM(RevenueMillions) DESC
LIMIT 8;
"""

df_filmes_avaliados = pd.read_sql(Consulta_1, engine)

df_generos_maior_receita = pd.read_sql(consulta_2, engine)

#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#= GERAÇÃO DE GRÁFICOS #=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=

# O top 10 dos filmes mais bem avaliados do IMDB
df_filmes_avaliados['Votos_Milhoes'] = df_filmes_avaliados['Votos'] / 1000000.0
plt.figure(figsize=(10, 6))
sns.barplot(x='Votos_Milhoes', y='Filme', data=df_filmes_avaliados, color='royalblue')

plt.title('TOP 10 Filmes com maior engajamento no IMDB', fontsize=14, pad=15)
plt.xlabel('Votos (Em Milhões)', fontsize=12, labelpad=10)
plt.ylabel('Filme', fontsize=12)
plt.savefig('output/top_10_filmes.png', bbox_inches='tight')
plt.close()


# Os gêneros dos filmes que tem maior receita em bilheteria no ano de 2016
plt.figure(figsize=(10, 6))
sns.barplot(x='Receita Total(USD Milhões)', y='Gênero', data=df_generos_maior_receita, color='royalblue')
plt.title('Os gêneros com maior receita em 2016', fontsize=12)
plt.xlabel('Receita Total(USD Milhões)', fontsize=12, labelpad=10)
plt.ylabel('Gênero', fontsize=12)
plt.savefig('output/generos_maior_receita.png', bbox_inches='tight')
plt.close()

# Ambos gráficos foram salvos na pasta output do projeto.

#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#= RESULTADOS #=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=

print("Questão 1:")
print(df_filmes_avaliados)

print("Questão 2:")
print(df_generos_maior_receita)
14 changes: 14 additions & 0 deletions desafio_RafaelaAyres/src/conexao_db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import os
from sqlalchemy import create_engine
from dotenv import load_dotenv

load_dotenv()

def get_engine():
User = os.getenv("User")
Pass = os.getenv("Pass")
IP = os.getenv("IP")

return create_engine(
f"mysql+pymysql://{User}:{Pass}@{IP}/looqbox-challenge"
)
40 changes: 40 additions & 0 deletions desafio_RafaelaAyres/src/respostas_questoes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import pandas as pd
from .conexao_db import get_engine

engine = get_engine()

# src/respostas_questoes/questao_1.sql

with open("sql/questao_1.sql", "r") as file:
query = file.read()

df = pd.read_sql(query, engine)

print("Questão 1:")
print(df)

#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=

# src/respostas_questoes/questao_2.sql

with open("sql/questao_2.sql", "r") as file:
query = file.read()

df2 = pd.read_sql(query, engine)

print("\nQuestão 2:")
print(df2)

#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=

# src/respostas_questoes/questao_3.sql

with open("sql/questao_3.sql", "r") as file:
query = file.read()

df3 = pd.read_sql(query, engine)

df3["total_vendas"] = df3["total_vendas"].map(lambda x: f"$ {x:,.2f}")

print("\nQuestão 3:")
print(df3)