diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f3acb2d --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +__pycache__/ +*.pyc +*.pyo +*.pyd +venv/ +.env \ No newline at end of file diff --git a/desafio_RafaelaAyres/output/generos_maior_receita.png b/desafio_RafaelaAyres/output/generos_maior_receita.png new file mode 100644 index 0000000..91c2368 Binary files /dev/null and b/desafio_RafaelaAyres/output/generos_maior_receita.png differ diff --git a/desafio_RafaelaAyres/output/top_10_filmes.png b/desafio_RafaelaAyres/output/top_10_filmes.png new file mode 100644 index 0000000..f405151 Binary files /dev/null and b/desafio_RafaelaAyres/output/top_10_filmes.png differ diff --git a/desafio_RafaelaAyres/readme.md b/desafio_RafaelaAyres/readme.md new file mode 100644 index 0000000..c8e69e9 --- /dev/null +++ b/desafio_RafaelaAyres/readme.md @@ -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! \ No newline at end of file diff --git a/desafio_RafaelaAyres/requirements.txt b/desafio_RafaelaAyres/requirements.txt new file mode 100644 index 0000000..1ae819c --- /dev/null +++ b/desafio_RafaelaAyres/requirements.txt @@ -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 diff --git a/desafio_RafaelaAyres/sql/__init__.py b/desafio_RafaelaAyres/sql/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/desafio_RafaelaAyres/sql/questao_1.sql b/desafio_RafaelaAyres/sql/questao_1.sql new file mode 100644 index 0000000..9ae46b6 --- /dev/null +++ b/desafio_RafaelaAyres/sql/questao_1.sql @@ -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; diff --git a/desafio_RafaelaAyres/sql/questao_2.sql b/desafio_RafaelaAyres/sql/questao_2.sql new file mode 100644 index 0000000..b0a2c99 --- /dev/null +++ b/desafio_RafaelaAyres/sql/questao_2.sql @@ -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; diff --git a/desafio_RafaelaAyres/sql/questao_3.sql b/desafio_RafaelaAyres/sql/questao_3.sql new file mode 100644 index 0000000..563d5f6 --- /dev/null +++ b/desafio_RafaelaAyres/sql/questao_3.sql @@ -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; diff --git a/desafio_RafaelaAyres/src/__init__.py b/desafio_RafaelaAyres/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/desafio_RafaelaAyres/src/cases/__init__.py b/desafio_RafaelaAyres/src/cases/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/desafio_RafaelaAyres/src/cases/questao_1.py b/desafio_RafaelaAyres/src/cases/questao_1.py new file mode 100644 index 0000000..0295766 --- /dev/null +++ b/desafio_RafaelaAyres/src/cases/questao_1.py @@ -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) \ No newline at end of file diff --git a/desafio_RafaelaAyres/src/cases/questao_2.py b/desafio_RafaelaAyres/src/cases/questao_2.py new file mode 100644 index 0000000..7391ce1 --- /dev/null +++ b/desafio_RafaelaAyres/src/cases/questao_2.py @@ -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) + diff --git a/desafio_RafaelaAyres/src/cases/questao_3.py b/desafio_RafaelaAyres/src/cases/questao_3.py new file mode 100644 index 0000000..52ed510 --- /dev/null +++ b/desafio_RafaelaAyres/src/cases/questao_3.py @@ -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) \ No newline at end of file diff --git a/desafio_RafaelaAyres/src/conexao_db.py b/desafio_RafaelaAyres/src/conexao_db.py new file mode 100644 index 0000000..75c3d7b --- /dev/null +++ b/desafio_RafaelaAyres/src/conexao_db.py @@ -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" + ) \ No newline at end of file diff --git a/desafio_RafaelaAyres/src/respostas_questoes.py b/desafio_RafaelaAyres/src/respostas_questoes.py new file mode 100644 index 0000000..1a1fbb7 --- /dev/null +++ b/desafio_RafaelaAyres/src/respostas_questoes.py @@ -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)