├── .vscode └── settings.json ├── ReadMe.md ├── ep01 ├── conceitos.md ├── ex_01.sql ├── ex_02.sql ├── ex_03.sql ├── ex_04.sql └── query_ep01.sql ├── ep02 ├── conceitos.md ├── ex_01.sql ├── ex_02.sql ├── ex_03.sql ├── ex_04.sql ├── minha_query.sql ├── query_functions.sql ├── query_groupby.sql └── query_groupby_multi.sql ├── ep03 ├── case_when_full.sql └── coalesce.sql ├── ep04 ├── ex01.sql ├── ex02.sql ├── ex03.sql ├── exercicios.md ├── join.sql ├── relacionamentos.xlsx └── revisao_case_when.sql ├── ep05 ├── fluxo_data.jpg ├── subquery.sql └── with_clausule.sql ├── ep06 ├── pct_rank_categoria.sql ├── sorteio_seller.sql └── window.sql └── ep07 ├── create.py ├── create.sql ├── create_table.sql ├── make_etl.py └── select.sql /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.pythonPath": "/home/teo/anaconda3/envs/tsql/bin/python" 3 | } -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | # TeoSQL - Curso de SQL do zero!! 2 | 3 | Curso de SQL voltado à análise de dados e geração de relatórios para Business Analytics e Data Analytics. Nossos encontros serão sempre às 20hrs nas terças e quintas: Twitch - [TeoMeWhy](https://www.twitch.tv/teomewhy). 4 | 5 | O conteúdo deste curso foi influenciado e pautado pelo livro _Introdução à Linguagem SQL_ de Thomas Nield (O`Reilly). Copyright 2016 Thomas Nield, 978-1-49-19-3861-4. Recomendamos fortemente a leitura deste livro, principalmente para os iniciantes, podendo assim aproveitar melhor o conteúdo ao longo das aulas. 6 | 7 | Deixamos claro desde o início que este material é totalmente gratuíto e não pretendemos ter retorno financeiro a partir deste. Somos orientados em disseminar conhecimento, possibilitanto que o maior número de pessoas possam acessá-lo e aprender com ele. Sinta-se livre para compartilhar e divulgar este material de forma gratuíta, mas ressaltamos a **proibição** da comercialização deste material, sob a licença [_Creative Commons BY-NC-SA 3.0 BR_](https://creativecommons.org/licenses/by-nc-sa/3.0/br/). 8 | 9 | 10 | 11 | ## Dados 12 | 13 | Vamos utilizar os dados da empresa Olist para realizar nossas consultas e aprendizado. Os dados são de uma empresa real, que trabalha no ramo de varejo com market places. Os dados podem ser obtidos [aqui](https://drive.google.com/file/d/12jKtfHsvDz8hGznIKffK-fZAsaKfsA8W/view?usp=sharing). 14 | 15 | Ainda, tem-se o seguinte esquema dos relacionamentos entre as tabelas destes banco de dados 16 | 17 | 18 | 19 | ## Ferramentas 20 | 21 | Para facilitar o aprendizado, vamos utilizar o SGBD SQLite3. Além de também fazer uso do [SQLite Studio](https://sqlitestudio.pl/). 22 | 23 | ## Cronograma 24 | 25 | | Episódio | Tema | Data | Vídeo | 26 | | ------- | ---- | ----| --- | 27 | | 01 | Introdução, SELECT, WHERE | 23/07 | [Twitch](https://www.twitch.tv/videos/689312999) | 28 | | 02 | GROUP BY, ORDER BY, HAVING | 28/07 | [Twitch](https://www.twitch.tv/videos/695248512) | 29 | | 03 | CASE, ISNULL, COALESCE, DISTINCT, COUNT, AVG... | 30/07 | [Twitch](https://www.twitch.tv/videos/704130093) | 30 | | 04 | JOIN's | 04/08 | [Twitch](https://www.twitch.tv/videos/704172105) | 31 | | 05 | SUBQUERIES | 06/08 | [Twitch](https://www.twitch.tv/videos/704177890) | 32 | | 06 | WINDOW FUNCTIONS | 11/08 | | 33 | | 07 | CREATE TABLE, VIEWS | 13/08 | | 34 | | 08 | Dúvidas e outros tópicos | 18/08 | | 35 | 36 | ### [Episódio 01](https://github.com/TeoCalvo/teoSQL/blob/master/ep01/conceitos.md) 37 | 38 | Primeira aula de SQL, apresentando os bancos de dados, aplicações e ferramentas para uso. Começamos com o ```SELECT```, realizando as consultas mais simples em nosso banco de dados da Olist. Ainda nesta aula, entenderemos como realizamos filtros em nossos dados com o comando ```WHERE```. 39 | 40 | ### [Episódio 02](https://github.com/TeoCalvo/teoSQL/blob/master/ep02/conceitos.md) 41 | 42 | Como já aprendemos a fazer as queries mais simples, agora vamos entender como agrupar (agregar) dados!! O uso do ```GROUP BY``` tem este propósito. Também podemos ordernar o resultado das consultas por meio de um campo especificado, ```ORDER BY```. Agora, como podemos filtrar o resultado de um consulta sem precisar gerar outra consulta a partir do resultado de uma consulta anterior? ```HAVING``` nos ajudará com isso! 43 | 44 | ### Episódio 03 45 | 46 | Agora podemos criar também colunas personalizadas conforme condições lógicas a serem respeitadas, ```CASE```. Aproveitamos ainda para apresentar alguns funções básicas de sobrevivência no SQL. 47 | 48 | ### Episódio 04 49 | 50 | Até o momento trabalhamos com tabelas apartadas, uma de cada vez em cada consulta distinta. Chegou a hora de trazer informações mais interessantes para serem cruzadas e enriquecerem uma análise. Bora entender o que são os ```JOINs```. 51 | 52 | ### Episódio 05 53 | 54 | Já pensou em filtrar uma query com o resultado de outra? Ou seja, dado o resultado de uma consulta, usá-la como critério de filtro em uma outra consulta? Vamos falar de SUBQUERIES então! 55 | 56 | ### Episódio 06 57 | 58 | Entrando no nosso tópico mais avançado do curso, ```WINDOWS FUNCTIONS```. Bora entender como essa maravilha funciona! 59 | 60 | ### Episódio 07 61 | 62 | Depois de executarmos nossas queries, desejamos salvar o resultado em um nova tabela, ou até mesmo guardar a query no banco. Assim, ```CREATE TABLE``` e ```CREATE VIEW``` nos ajudam com esta tarefa. 63 | 64 | ### Episódio 08 65 | 66 | Chegou a hora de tirar dúvidas e abordar tópicos diversos que deixamos de falar ou que merecem maior destaque. 67 | 68 | -------------------------------------------------------------------------------- /ep01/conceitos.md: -------------------------------------------------------------------------------- 1 | # Episódio 01 2 | 3 | Neste episódio vamos entender o porque de usar bancos de dados, bem como o que os define. Ao decorrer da aula realizaremos nossas primeiras queries (consultas) no dialeto SQL (_Structured Query Language_). 4 | 5 | ## Por que SQL? 6 | 7 | Se você chegou até esta página e porque está minimamente curioso a respeito dessa tecnologia. Mas afinal, por que deveria demandar tempo e energia em aprender algo novo? 8 | 9 | Bom, SQL é sinônimo de autonomia. Isso mesmo! E não pense que estou me referindo à apenas Cientista de Dados e a galera de TI, pelo contrário! Sabe aquela análise que seu processador de planílias favorito leva um tempão para realizar, ou nem consegue abrir um arquivo tão grande na sua máquina? Pois bem, é disso que estou falando. SQL dará autonomia até para analistas de negócio e me arrisco dizer, ao nível executivo também. 10 | 11 | Com um sistema de bancos de dados também garantimos segurança e minimizamos riscos. Eu sei (e todos nós sabemos) das incontáveis planilhas e arquivos pingando de um email para o outro. Alguem extrai a base de um canto, anexa no email e manda para frente. Nada mais comum no mundo corporativo. Pois bem, precisamos acabar com isso! Imagine se pessoas tiverem acesso à estes dados em um ambiente controlado, seguro e com os devidos acesso e permissões? Bem melhor, não? 12 | 13 | E este é o foco de todo nosso conteúdo. Meu desejo é que as pessoas possam realizar suas entregas de forma mais independente, rápida e correta. 14 | 15 | ## O que é banco de dados 16 | 17 | É comum que uma planilha eletrônica ou arquivos de textos sejam considerados bancos de dados. O que não está errado. Mas no contexto deste curso, falaremos especificamente _Sistema de Gerenciamento de Banco de Dados Relacional_ (SGDB) ou em inglês _Relational Database Management System_ (RDBMS). Não se assuste, isso não passa de um tipo de bancos de dados que contêm uma ou mais tabelas que podem ser relacionadas de alguma maneira. 18 | 19 | ### Tabelas 20 | 21 | As tabelas são um conjunto de informações organizados em linhas e colunas. Tais informações devem trazer algum sentido e o contexto onde estão inseridas, isto é, uma representação do mundo real. Algo muito similar com uma planílha eletrônica. 22 | 23 | Exemplo de tabela (tb_pessoas): 24 | 25 | | nome | cor_olhos | idade | cidade_atual | uf_atual | flag_humano | 26 | | --- | --- | --- | --- | --- | --- | 27 | | Téo | castanho | 28 | são paulo | sp | 1 | 28 | | Nah | preto | 29 | são paulo | sp | 1 | 29 | | Lara | castanho | 27 | são josé dos campos | sp | 1 | 30 | | Kira | preto | 3 | são paulo | sp | 0 | 31 | | Zaha | castanho | 2 | são josé dos campos | sp | 0 | 32 | 33 | Note que a tabela anterior contém 5 linhas (registros) e 6 colunas (campos). 34 | 35 | Dependendo do propósito de estudo ou ação, podemos realizar filtros e transformações nessa tabela. Como por exemplo, filtrar os moradores da cidade de São Paulo, adicionando uma coluna com a marcação se são maiores de idade ou não. 36 | 37 | | nome | cor_olhos | idade | cidade_atual | uf_atual | flag_humano | flag_adulto | 38 | | --- | --- | --- | --- | --- | --- | --- | 39 | | Téo | castanho | 28 | são paulo | sp | 1 | 1 | 40 | | Nah | preto | 29 | são paulo | sp | 1 | 1 | 41 | | Kira | preto | 3 | são paulo | sp | 0 | 0 | 42 | 43 | ### Consultas 44 | 45 | Para sairmos da tabela um, e aplicar as regras de negócio (ou critérios) para chegarmos na segunda tabela, é necessário realizar uma consulta: ```query```. Neste momento que entra o famoso ```SQL```, nos possibilitando conversar com o banco de dados, solicitando os dados conforme nossas necessidades. 46 | 47 | Vamos realizar a menor query que poderíamos! Ou a maior? 48 | 49 | ```sql 50 | SELECT * FROM tb_pessoas 51 | ``` 52 | 53 | Leia-se: Selecione (```SELECT```) todas colunas (```*```) da (```FROM```) tabela ```tb_pessoas```. Simples, não? 54 | 55 | Imagine que quisessemos apenas as colunas (campos): nome, idade e cidade_atual. Assim teríamos: 56 | 57 | ```sql 58 | SELECT nome, 59 | idade, 60 | cidade_atual 61 | FROM tb_pessoas 62 | ``` 63 | 64 | Leia-se Selecione (```SELECT```) ```nome```, ```idade``` e ```cidade``` da (```FROM```) tabela ```tb_pessoas```. E teríamos o seguinte resultado: 65 | 66 | | nome | idade | cidade_atual | 67 | | --- | --- | --- | 68 | | Téo | 28 | são paulo | 69 | | Nah | 29 | são paulo | 70 | | Lara | 27 | são josé dos campos | 71 | | Kira | 3 | são paulo | 72 | | Zaha | 2 | são josé dos campos | 73 | 74 | A partir de agora, vamos para os dados reais fazer queries e tirar insights!! 75 | HANDS-ON!!! 76 | 77 | ## Tarefa de casa!! 78 | 79 | Ex1: Quantos produtos temos da categoria 'artes'? 80 | 81 | Ex2: Quantos produtos tem mais de 5 litros? 82 | 83 | Ex3: Crie uma coluna nova que contenha a informação de volume em m3 84 | 85 | Ex4: Quantos produtos de 'beleza_saude' com menos de 1 litro? 86 | -------------------------------------------------------------------------------- /ep01/ex_01.sql: -------------------------------------------------------------------------------- 1 | --Ex1: Quantos produtos temos da categoria 'artes'? 2 | 3 | SELECT product_id, 4 | product_category_name, 5 | product_name_lenght, 6 | product_description_lenght, 7 | product_photos_qty, 8 | product_weight_g, 9 | product_length_cm, 10 | product_height_cm, 11 | product_width_cm 12 | FROM tb_products 13 | 14 | where product_category_name = 'artes' 15 | -- 55 linhas 16 | ; 17 | -------------------------------------------------------------------------------- /ep01/ex_02.sql: -------------------------------------------------------------------------------- 1 | --Ex2: Quantos produtos tem mais de 5 litros? 2 | 3 | SELECT product_id, 4 | product_category_name, 5 | product_name_lenght, 6 | product_description_lenght, 7 | product_photos_qty, 8 | product_weight_g, 9 | product_length_cm, 10 | product_height_cm, 11 | product_width_cm, 12 | product_length_cm * product_height_cm * product_width_cm as volume_item_cm3 13 | FROM tb_products 14 | 15 | where product_length_cm * product_height_cm * product_width_cm > 5000 16 | 17 | -- 19407 linhas 18 | ; 19 | -------------------------------------------------------------------------------- /ep01/ex_03.sql: -------------------------------------------------------------------------------- 1 | -- Ex3 Crie uma coluna nova que contenha a informação de volume em m3 2 | 3 | SELECT product_id, 4 | product_category_name, 5 | product_name_lenght, 6 | product_description_lenght, 7 | product_photos_qty, 8 | product_weight_g, 9 | product_length_cm, 10 | product_height_cm, 11 | product_width_cm, 12 | (product_length_cm * product_height_cm * product_width_cm) / 1000000 as volume_m3 13 | 14 | FROM tb_products -------------------------------------------------------------------------------- /ep01/ex_04.sql: -------------------------------------------------------------------------------- 1 | 2 | -- Ex4: Quantos produtos de 'beleza_saude' com menos de 1 litro? 3 | 4 | SELECT product_id, 5 | product_category_name, 6 | product_length_cm * product_height_cm * product_width_cm as vol_cm3 7 | 8 | FROM tb_products 9 | 10 | where product_category_name = 'beleza_saude' 11 | and product_length_cm * product_height_cm * product_width_cm < 1000 12 | 13 | -- 132 linhas 14 | ; 15 | -------------------------------------------------------------------------------- /ep01/query_ep01.sql: -------------------------------------------------------------------------------- 1 | SELECT product_id, 2 | product_category_name, 3 | product_weight_g , 4 | product_weight_g / 1000 as product_weight_kg, 5 | product_length_cm, 6 | product_height_cm, 7 | product_width_cm, 8 | product_length_cm * product_height_cm * product_width_cm as product_volume_cm3 9 | FROM tb_products 10 | 11 | WHERE (product_weight_g / 1000) >= 1 12 | AND product_category_name in ('automotivo', 'brinquedos') 13 | AND (product_length_cm * product_height_cm * product_width_cm) >= 1000 14 | ; -------------------------------------------------------------------------------- /ep02/conceitos.md: -------------------------------------------------------------------------------- 1 | # Episódio 02 2 | 3 | Agora que somos capazes de realizar uma consulta simples, selecionando colunas e linhas que desejamos, vamos avança para parte de "agregar dados" com o ```GROUP BY```. Mas antes, vamos conhecer algumas funções de agregações, ou resumo. 4 | 5 | ## Funções no SQL? 6 | 7 | Considere a seguinte tabela: 8 | 9 | | nome | idade | qtd_pets | receita_mensal | cidade_atual | uf_atual 10 | | --- | --- | --- | --- | --- | --- | 11 | | Téo | 28 | 1 | 2780 | são paulo | sp | 12 | | Nah | 29 | 1 | 8910 | são paulo | sp | 13 | | Lara | 27 | 2 | 13987 | são josé dos campos | sp | 14 | | Karla | 32 | 4 | 6610 | guarulho | sp | 15 | | Bruno | 34 | 4 |18000 | guarulho | sp | 16 | | Fernando | 27 | 0 | 2572 | londrina | pr | 17 | | Maira | 35 | 0 | 3651 | curitiba | pr | 18 | | Josefina | 45 | 10 | 23651 | curitiba | pr | 19 | 20 | Agora, gostaríamos de realizar consultas nesta tabela para descobrir algumas estatísticas das variáveis numéricas: ```idade```, ```qtd_pets``` e ```receita_mensal```. Como fazemos para chegar em algo do tipo? 21 | 22 | | idade_min | idade_avg | receita_mensal_total | qtd_pets_max | qtd_cidade_atual | qtd_uf_atual_dst | 23 | | --- | --- | --- | --- | --- | --- | 24 | | 27 | 32.125 | 80161 | 10 | 8 | 2 | 25 | 26 | Apresentamos então as funções: ```MIN()```, ```AVG()```, ```SUM()```, ```MAX```, ```COUNT()``` e ```DISTINCT```. para conferir a documentação dessas funções, [clique aqui](https://www.sqlite.org/lang_aggfunc.html). 27 | 28 | E se quisermos tirar essas estatísticas em cada ```cidade_atual``` ou ```uf_atual```, como faríamos? 29 | 30 | ## Tarefa!! 31 | 32 | Ex1. Faça uma query que apresente o tamanho médio, máximo e mínimo da descrição do objeto por categoria 33 | 34 | Ex2. Faça uma query que apresente o tamanho médio, máximo e mínimo do nome do objeto por categoria 35 | 36 | Ex3. Faça uma query que apresente o tamanho médio, máximo e mínimo do nome do objeto por categoria. Considere apenas os objetos que tenham a descrição maior que 50. 37 | 38 | Ex4. Faça uma query que apresente o tamanho médio, máximo e mínimo do nome do objeto por categoria. Considere apenas os objetos que tenham a descrição maior que 50. Exiba apenas as categorias com tamanho médio de descrição do objeto maior que 100 caracteres. 39 | -------------------------------------------------------------------------------- /ep02/ex_01.sql: -------------------------------------------------------------------------------- 1 | -- Ex1. Faça uma query que apresente o tamanho médio, máximo e mínimo da descrição do objeto por categoria 2 | 3 | select product_category_name, 4 | avg( product_description_lenght) as media_descricao, 5 | max( product_description_lenght ) as max_descricao, 6 | min( product_description_lenght ) as min_descricao 7 | 8 | from tb_products 9 | 10 | group by product_category_name 11 | -------------------------------------------------------------------------------- /ep02/ex_02.sql: -------------------------------------------------------------------------------- 1 | -- Ex2. Faça uma query que apresente o tamanho médio, máximo e mínimo do nome do objeto por categoria 2 | 3 | select product_category_name, 4 | avg( product_name_lenght) as media_nome, 5 | max( product_name_lenght) as max_nome, 6 | min( product_name_lenght) as min_nome 7 | 8 | from tb_products 9 | 10 | group by product_category_name 11 | -------------------------------------------------------------------------------- /ep02/ex_03.sql: -------------------------------------------------------------------------------- 1 | -- Ex3. Faça uma query que apresente o tamanho médio, máximo e mínimo do nome do objeto por categoria. 2 | -- Considere apenas os objetos que tenham a descrição maior que 50. 3 | 4 | select product_category_name, 5 | avg( product_name_lenght) as media_nome, 6 | max( product_name_lenght) as max_nome, 7 | min( product_name_lenght) as min_nome 8 | 9 | from tb_products 10 | 11 | where product_description_lenght > 50 12 | 13 | group by product_category_name 14 | -------------------------------------------------------------------------------- /ep02/ex_04.sql: -------------------------------------------------------------------------------- 1 | --Ex4. Faça uma query que apresente o tamanho médio, máximo e mínimo do nome do objeto por categoria. 2 | --Considere apenas os objetos que tenham a descrição maior que 50. 3 | -- Exiba apenas as categorias com tamanho médio de descrição do objeto maior que 100 caracteres. 4 | 5 | select product_category_name, 6 | max( product_name_lenght ) as max_nome, 7 | min( product_name_lenght ) as min_nome, 8 | avg( product_name_lenght ) as avg_nome 9 | 10 | from tb_products 11 | 12 | where product_description_lenght > 50 13 | 14 | group by product_category_name 15 | 16 | having product_description_lenght > 100 -------------------------------------------------------------------------------- /ep02/minha_query.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeoCalvo/teoSQL/e1942e7895dd24fcdb0248455bf4593725903408/ep02/minha_query.sql -------------------------------------------------------------------------------- /ep02/query_functions.sql: -------------------------------------------------------------------------------- 1 | SELECT count(1) as qtd_linhas, 2 | count( product_category_name) as qtd_categorias, -- conta linhas nao nulas no campo categoria 3 | count( distinct product_category_name) as qtd_categorias_dstc, -- conta linhas distintas para o campo categoria 4 | max( product_photos_qty ) as max_photo_qty, -- maior valor do campo quantidade de fotos 5 | min( product_photos_qty ) as min_photo_qty, -- menor valor do campo quantidade de fotos 6 | round(avg( product_photos_qty ) ,2 )as avg_photo_qty , -- valor médio do campo quantidade de fotos 7 | sum( product_photos_qty ) as sum_photo_qty, -- soma total dos valores do campo quantidade de fotos 8 | round(sum( product_photos_qty ) / count( product_photos_qty ),2) as avg_unha_photo_qty -- divisao entre soma de valores e contagem nao nula de qtde fotos 9 | 10 | FROM tb_products 11 | ; 12 | -------------------------------------------------------------------------------- /ep02/query_groupby.sql: -------------------------------------------------------------------------------- 1 | SELECT 2 | product_category_name, 3 | count(1) as qtd_linhas, 4 | count( product_category_name) as qtd_categorias, -- conta linhas nao nulas no campo categoria 5 | count( distinct product_category_name) as qtd_categorias_dstc, -- conta linhas distintas para o campo categoria 6 | max( product_photos_qty ) as max_photo_qty, -- maior valor do campo quantidade de fotos 7 | min( product_photos_qty ) as min_photo_qty, -- menor valor do campo quantidade de fotos 8 | round(avg( product_photos_qty ) ,2 )as avg_photo_qty , -- valor médio do campo quantidade de fotos 9 | sum( product_photos_qty ) as sum_photo_qty, -- soma total dos valores do campo quantidade de fotos 10 | round(sum( product_photos_qty ) / count( product_photos_qty ),2) as avg_unha_photo_qty -- divisao entre soma de valores e contagem nao nula de qtde fotos 11 | 12 | FROM tb_products 13 | 14 | WHERE product_category_name IS NOT NULL 15 | 16 | GROUP BY product_category_name 17 | 18 | HAVING COUNT(1) > 50 19 | 20 | ORDER BY count(1) -------------------------------------------------------------------------------- /ep02/query_groupby_multi.sql: -------------------------------------------------------------------------------- 1 | SELECT 2 | product_category_name, 3 | product_photos_qty, 4 | count(1) as qtd_produtos, 5 | round( AVG(product_length_cm * product_height_cm * product_width_cm),2) AS avg_volume 6 | 7 | FROM tb_products 8 | 9 | WHERE product_category_name IS NOT NULL 10 | 11 | GROUP BY product_category_name, product_photos_qty 12 | 13 | ORDER BY product_category_name, product_photos_qty -------------------------------------------------------------------------------- /ep03/case_when_full.sql: -------------------------------------------------------------------------------- 1 | SELECT 2 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'agro_industria_e_comercio'THEN 1 ELSE 0 END ),2) AS agro_industria_e_comercio, 3 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'alimentos'THEN 1 ELSE 0 END ),2) AS alimentos, 4 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'alimentos_bebidas'THEN 1 ELSE 0 END ),2) AS alimentos_bebidas, 5 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'artes'THEN 1 ELSE 0 END ),2) AS artes, 6 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'artes_e_artesanato'THEN 1 ELSE 0 END ),2) AS artes_e_artesanato, 7 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'artigos_de_festas'THEN 1 ELSE 0 END ),2) AS artigos_de_festas, 8 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'artigos_de_natal'THEN 1 ELSE 0 END ),2) AS artigos_de_natal, 9 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'audio'THEN 1 ELSE 0 END ),2) AS audio, 10 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'automotivo'THEN 1 ELSE 0 END ),2) AS automotivo, 11 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'bebes'THEN 1 ELSE 0 END ),2) AS bebes, 12 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'bebidas'THEN 1 ELSE 0 END ),2) AS bebidas, 13 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'beleza_saude'THEN 1 ELSE 0 END ),2) AS beleza_saude, 14 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'brinquedos'THEN 1 ELSE 0 END ),2) AS brinquedos, 15 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'cama_mesa_banho'THEN 1 ELSE 0 END ),2) AS cama_mesa_banho, 16 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'casa_conforto'THEN 1 ELSE 0 END ),2) AS casa_conforto, 17 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'casa_conforto_2'THEN 1 ELSE 0 END ),2) AS casa_conforto_2, 18 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'casa_construcao'THEN 1 ELSE 0 END ),2) AS casa_construcao, 19 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'cds_dvds_musicais'THEN 1 ELSE 0 END ),2) AS cds_dvds_musicais, 20 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'cine_foto'THEN 1 ELSE 0 END ),2) AS cine_foto, 21 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'climatizacao'THEN 1 ELSE 0 END ),2) AS climatizacao, 22 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'consoles_games'THEN 1 ELSE 0 END ),2) AS consoles_games, 23 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'construcao_ferramentas_construcao'THEN 1 ELSE 0 END ),2) AS construcao_ferramentas_construcao, 24 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'construcao_ferramentas_ferramentas'THEN 1 ELSE 0 END ),2) AS construcao_ferramentas_ferramentas, 25 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'construcao_ferramentas_iluminacao'THEN 1 ELSE 0 END ),2) AS construcao_ferramentas_iluminacao, 26 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'construcao_ferramentas_jardim'THEN 1 ELSE 0 END ),2) AS construcao_ferramentas_jardim, 27 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'construcao_ferramentas_seguranca'THEN 1 ELSE 0 END ),2) AS construcao_ferramentas_seguranca, 28 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'cool_stuff'THEN 1 ELSE 0 END ),2) AS cool_stuff, 29 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'dvds_blu_ray'THEN 1 ELSE 0 END ),2) AS dvds_blu_ray, 30 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'eletrodomesticos'THEN 1 ELSE 0 END ),2) AS eletrodomesticos, 31 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'eletrodomesticos_2'THEN 1 ELSE 0 END ),2) AS eletrodomesticos_2, 32 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'eletronicos'THEN 1 ELSE 0 END ),2) AS eletronicos, 33 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'eletroportateis'THEN 1 ELSE 0 END ),2) AS eletroportateis, 34 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'esporte_lazer'THEN 1 ELSE 0 END ),2) AS esporte_lazer, 35 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'fashion_bolsas_e_acessorios'THEN 1 ELSE 0 END ),2) AS fashion_bolsas_e_acessorios, 36 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'fashion_calcados'THEN 1 ELSE 0 END ),2) AS fashion_calcados, 37 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'fashion_esporte'THEN 1 ELSE 0 END ),2) AS fashion_esporte, 38 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'fashion_roupa_feminina'THEN 1 ELSE 0 END ),2) AS fashion_roupa_feminina, 39 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'fashion_roupa_infanto_juvenil'THEN 1 ELSE 0 END ),2) AS fashion_roupa_infanto_juvenil, 40 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'fashion_roupa_masculina'THEN 1 ELSE 0 END ),2) AS fashion_roupa_masculina, 41 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'fashion_underwear_e_moda_praia'THEN 1 ELSE 0 END ),2) AS fashion_underwear_e_moda_praia, 42 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'ferramentas_jardim'THEN 1 ELSE 0 END ),2) AS ferramentas_jardim, 43 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'flores'THEN 1 ELSE 0 END ),2) AS flores, 44 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'fraldas_higiene'THEN 1 ELSE 0 END ),2) AS fraldas_higiene, 45 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'industria_comercio_e_negocios'THEN 1 ELSE 0 END ),2) AS industria_comercio_e_negocios, 46 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'informatica_acessorios'THEN 1 ELSE 0 END ),2) AS informatica_acessorios, 47 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'instrumentos_musicais'THEN 1 ELSE 0 END ),2) AS instrumentos_musicais, 48 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'la_cuisine'THEN 1 ELSE 0 END ),2) AS la_cuisine, 49 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'livros_importados'THEN 1 ELSE 0 END ),2) AS livros_importados, 50 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'livros_interesse_geral'THEN 1 ELSE 0 END ),2) AS livros_interesse_geral, 51 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'livros_tecnicos'THEN 1 ELSE 0 END ),2) AS livros_tecnicos, 52 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'malas_acessorios'THEN 1 ELSE 0 END ),2) AS malas_acessorios, 53 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'market_place'THEN 1 ELSE 0 END ),2) AS market_place, 54 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'moveis_colchao_e_estofado'THEN 1 ELSE 0 END ),2) AS moveis_colchao_e_estofado, 55 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'moveis_cozinha_area_de_servico_jantar_e_jardim'THEN 1 ELSE 0 END ),2) AS moveis_cozinha_area_de_servico_jantar_e_jardim, 56 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'moveis_decoracao'THEN 1 ELSE 0 END ),2) AS moveis_decoracao, 57 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'moveis_escritorio'THEN 1 ELSE 0 END ),2) AS moveis_escritorio, 58 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'moveis_quarto'THEN 1 ELSE 0 END ),2) AS moveis_quarto, 59 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'moveis_sala'THEN 1 ELSE 0 END ),2) AS moveis_sala, 60 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'musica'THEN 1 ELSE 0 END ),2) AS musica, 61 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'papelaria'THEN 1 ELSE 0 END ),2) AS papelaria, 62 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'pc_gamer'THEN 1 ELSE 0 END ),2) AS pc_gamer, 63 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'pcs'THEN 1 ELSE 0 END ),2) AS pcs, 64 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'perfumaria'THEN 1 ELSE 0 END ),2) AS perfumaria, 65 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'pet_shop'THEN 1 ELSE 0 END ),2) AS pet_shop, 66 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'portateis_casa_forno_e_cafe'THEN 1 ELSE 0 END ),2) AS portateis_casa_forno_e_cafe, 67 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'portateis_cozinha_e_preparadores_de_alimentos'THEN 1 ELSE 0 END ),2) AS portateis_cozinha_e_preparadores_de_alimentos, 68 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'relogios_presentes'THEN 1 ELSE 0 END ),2) AS relogios_presentes, 69 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'seguros_e_servicos'THEN 1 ELSE 0 END ),2) AS seguros_e_servicos, 70 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'sinalizacao_e_seguranca'THEN 1 ELSE 0 END ),2) AS sinalizacao_e_seguranca, 71 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'tablets_impressao_imagem'THEN 1 ELSE 0 END ),2) AS tablets_impressao_imagem, 72 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'telefonia'THEN 1 ELSE 0 END ),2) AS telefonia, 73 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'telefonia_fixa'THEN 1 ELSE 0 END ),2) AS telefonia_fixa, 74 | ROUND( 100 * AVG( CASE WHEN product_category_name = 'utilidades_domesticas'THEN 1 ELSE 0 END ),2) AS utilidades_domesticas 75 | 76 | FROM tb_products 77 | 78 | ORDER BY product_category_name 79 | 80 | ; 81 | -------------------------------------------------------------------------------- /ep03/coalesce.sql: -------------------------------------------------------------------------------- 1 | SELECT *, 2 | case when product_category_name isnull then 'esse caraio é nulo' else product_category_name end as categoria_nova, 3 | coalesce( product_category_name, 'esse caraio é nulo' ) as categoria_nova 4 | FROM tb_products 5 | ; -------------------------------------------------------------------------------- /ep04/ex01.sql: -------------------------------------------------------------------------------- 1 | -- ### Ex1 2 | -- Qual o valor total de receita gerada por consumidores de cada estado? 3 | -- Considere a base completa, com apenas pedidos entregues 4 | 5 | SELECT T2.customer_state, 6 | SUM(T3.price) as receita_total 7 | 8 | FROM tb_orders AS T1 9 | 10 | LEFT JOIN tb_customers AS T2 11 | ON T1.customer_id = T2.customer_id 12 | 13 | LEFT JOIN tb_order_items AS T3 14 | ON T1.order_id = T3.order_id 15 | 16 | WHERE order_status = 'delivered' 17 | 18 | GROUP BY T2.customer_state -------------------------------------------------------------------------------- /ep04/ex02.sql: -------------------------------------------------------------------------------- 1 | 2 | -- ### Ex2 3 | -- Qual o valor total de receita gerada por sellers de cada estado? 4 | -- Considere a base completa, com apenas pedidos entregues 5 | 6 | SELECT T3.seller_state, 7 | sum( T2.price ) AS receita_total 8 | 9 | FROM tb_orders as T1 10 | 11 | LEFT JOIN tb_order_items as T2 12 | ON T1.order_id = T2.order_id 13 | 14 | LEFT JOIN tb_sellers as T3 15 | ON T2.seller_id = T3.seller_id 16 | 17 | WHERE order_status = 'delivered' 18 | 19 | GROUP BY T3.seller_state -------------------------------------------------------------------------------- /ep04/ex03.sql: -------------------------------------------------------------------------------- 1 | -- ### Ex3 2 | -- Qual o peso médio dos produtos vendidos por sellers de cada estado? 3 | -- Considere apenas o ano de 2017 e pedidos entregues nesta análise. 4 | 5 | SELECT T3.seller_state, 6 | AVG(T4.product_weight_g) AS pedo_medio 7 | 8 | FROM tb_orders as T1 9 | 10 | LEFT JOIN tb_order_items as T2 11 | ON T1.order_id = T2.order_id 12 | 13 | LEFT JOIN tb_sellers AS T3 14 | ON T2.seller_id = T3.seller_id 15 | 16 | LEFT JOIN tb_products as T4 17 | ON T2.product_id = T4.product_id 18 | 19 | WHERE T1.order_status = 'delivered' 20 | AND cast( strftime( '%Y', T1.order_purchase_timestamp) as integer) = 2017 21 | 22 | GROUP BY T3.seller_state -------------------------------------------------------------------------------- /ep04/exercicios.md: -------------------------------------------------------------------------------- 1 | # Exercícios para fixação 2 | 3 | ### Ex1 4 | 5 | Qual o valor total de receita gerada por consumidores de cada estado? Considere a base completa, com apenas pedidos entregues 6 | 7 | ### Ex2 8 | 9 | Qual o valor total de receita gerada por sellers de cada estado? Considere a base completa, com apenas pedidos entregues 10 | 11 | ### Ex3 12 | 13 | Qual o peso médio dos produtos vendidos por sellers de cada estado? 14 | Considere apenas o ano de 2017 e pedidos entregues nesta análise. -------------------------------------------------------------------------------- /ep04/join.sql: -------------------------------------------------------------------------------- 1 | -- OBEJTIVO: Calcular quantidade de vendas (pedidos), itens vendidos, e Receita (dinheiros) por categoria de produto, 2 | -- durante o ano de 2017 e foram entregues 3 | 4 | SELECT T3.product_category_name, -- categoria de produto 5 | 6 | COUNT(T1.order_id) AS qtd_itens_vendidos, 7 | COUNT(DISTINCT T1.order_id) AS qtd_pedidos, 8 | ROUND(SUM(T2.price),2 )AS receita -- receita 9 | /*T1.customer_id, 10 | T1.order_status, 11 | T1.order_purchase_timestamp, 12 | T2.product_id, */ 13 | 14 | FROM tb_orders AS T1 -- Primeira tabela, tabela de pedidos 15 | 16 | LEFT JOIN tb_order_items AS T2 -- Segunda tabela, tabela de pedido/item 17 | ON T1.order_id = T2.order_id 18 | 19 | LEFT JOIN tb_products AS T3 -- Terceira tabela, tabela de produtos 20 | ON T2.product_id = T3.product_id 21 | 22 | WHERE strftime( '%Y', date(T1.order_approved_at )) = '2017' -- ano 2017 23 | AND T1.order_status = 'delivered' -- pedidos entregues com sucesso 24 | 25 | GROUP BY T3.product_category_name 26 | 27 | ; -------------------------------------------------------------------------------- /ep04/relacionamentos.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeoCalvo/teoSQL/e1942e7895dd24fcdb0248455bf4593725903408/ep04/relacionamentos.xlsx -------------------------------------------------------------------------------- /ep04/revisao_case_when.sql: -------------------------------------------------------------------------------- 1 | SELECT product_id, 2 | product_category_name, 3 | product_name_lenght, 4 | product_description_lenght, 5 | product_photos_qty, 6 | product_weight_g, 7 | product_length_cm, 8 | product_height_cm, 9 | product_width_cm, 10 | product_length_cm * product_height_cm * product_width_cm as volume_cm3, 11 | case when product_weight_g > 1000 then 1 else 0 end as peso_maior_1kg, 12 | 13 | case when product_weight_g < 500 then '0_500' 14 | when product_weight_g < 1000 then '500_1000' 15 | when product_weight_g < 2000 then '1000_2000' 16 | else 'mais_2000' end as fx_peso 17 | 18 | FROM tb_products 19 | 20 | where product_category_name = 'perfumaria' 21 | ; 22 | -------------------------------------------------------------------------------- /ep05/fluxo_data.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeoCalvo/teoSQL/e1942e7895dd24fcdb0248455bf4593725903408/ep05/fluxo_data.jpg -------------------------------------------------------------------------------- /ep05/subquery.sql: -------------------------------------------------------------------------------- 1 | -- Queremos produtos 2 | -- cuja média de peso da categoria seja maior que 2 kilos 3 | 4 | select * 5 | 6 | from tb_products as t1 7 | 8 | where t1.product_category_name in ( select product_category_name 9 | from tb_products 10 | where product_category_name is not null 11 | group by product_category_name 12 | having avg( product_weight_g ) > 2000 ) 13 | -------------------------------------------------------------------------------- /ep05/with_clausule.sql: -------------------------------------------------------------------------------- 1 | with tb_categorias_2kg as ( 2 | 3 | select product_category_name 4 | from tb_products 5 | where product_category_name is not null 6 | group by product_category_name 7 | having avg( product_weight_g ) > 2000 8 | 9 | ) 10 | 11 | select t1.* 12 | from tb_products as t1 13 | where t1.product_category_name in (select product_category_name from tb_categorias_2kg) 14 | 15 | ; -------------------------------------------------------------------------------- /ep06/pct_rank_categoria.sql: -------------------------------------------------------------------------------- 1 | select product_id, 2 | product_category_name, 3 | percent_rank() over (partition by product_category_name order by product_weight_g) 4 | 5 | from tb_products 6 | 7 | where product_category_name is not null -------------------------------------------------------------------------------- /ep06/sorteio_seller.sql: -------------------------------------------------------------------------------- 1 | SELECT * 2 | 3 | FROM( 4 | 5 | SELECT t1.order_id, 6 | t2.seller_id, 7 | t1.order_purchase_timestamp, 8 | row_number() OVER (PARTITION by seller_id ORDER BY RANDOM() ) AS linha 9 | 10 | FROM tb_orders as t1 -- uma linha por pedido 11 | 12 | left join tb_order_items as t2 -- uma linha por pedido e item (pode ter mais de duas linhas por pedido) 13 | on t1.order_id = t2.order_id 14 | 15 | where seller_id is not null 16 | 17 | order by t2.seller_id, 18 | t1.order_id 19 | 20 | ) 21 | 22 | WHERE linha = 1 -------------------------------------------------------------------------------- /ep06/window.sql: -------------------------------------------------------------------------------- 1 | SELECT * 2 | 3 | FROM ( 4 | 5 | SELECT *, 6 | -- isso é um caraio de uma window function 7 | ROW_NUMBER() OVER (PARTITION BY seller_id order by dt_venda desc) as numero_linha, 8 | LEAD(dt_venda) OVER (PARTITION BY seller_id order by dt_venda desc) as lag_data, 9 | LEAD(dt_venda,2) OVER (PARTITION BY seller_id order by dt_venda desc) as lag_data2 10 | FROM TB_SELLER_ORDER 11 | 12 | ) 13 | WHERE numero_linha = 1 -------------------------------------------------------------------------------- /ep07/create.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import sqlalchemy 3 | import os 4 | from tqdm import tqdm 5 | import time 6 | 7 | import argparse 8 | parser = argparse.ArgumentParser() 9 | parser.add_argument("--date_start", "-s", default="2016-06-01") 10 | parser.add_argument("--date_end", "-e", default="2017-01-01") 11 | args = parser.parse_args() 12 | 13 | EP_DIR = os.path.join( os.path.abspath('.'), 'ep07') 14 | EP_DIR = os.path.dirname(os.path.abspath(__file__)) 15 | 16 | with open( os.path.join(EP_DIR, 'create_table.sql'), 'r' ) as open_file: 17 | query = open_file.read() 18 | 19 | query_format = query.format( date_start=args.date_start, 20 | date_end=args.date_end ) 21 | 22 | queries = query_format.split(";")[:-1] 23 | 24 | con = sqlalchemy.create_engine("sqlite:///" + "/home/teo/Área de trabalho/cursoSQL/olist.db") 25 | 26 | for q in tqdm(queries): 27 | con.execute(q) 28 | 29 | -------------------------------------------------------------------------------- /ep07/create.sql: -------------------------------------------------------------------------------- 1 | 2 | drop table if exists tb_orders_delivered; 3 | create table tb_orders_delivered as 4 | 5 | select t1.* 6 | 7 | from tb_orders as t1 8 | 9 | -- Filtro ou regra de negócio 10 | where order_status = 'delivered' 11 | ; -------------------------------------------------------------------------------- /ep07/create_table.sql: -------------------------------------------------------------------------------- 1 | drop table if exists tb_venda_itens_seller_customers; 2 | create table tb_venda_itens_seller_customers as 3 | select * 4 | 5 | from tb_orders_delivered as t1 6 | 7 | left join tb_order_items as t2 8 | on t1.order_id = t2.order_id 9 | 10 | left join tb_sellers as t3 11 | on t2.seller_id = t3.seller_id 12 | 13 | left join tb_customers as t4 14 | on t1.customer_id = t4.customer_id 15 | 16 | left join tb_products as t5 17 | on t2.product_id = t5.product_id 18 | 19 | where t1.order_status = 'delivered' 20 | 21 | and t1.order_approved_at >= '{date_start}' 22 | and t1.order_approved_at < '{date_end}' 23 | ; -------------------------------------------------------------------------------- /ep07/make_etl.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import sqlalchemy 3 | import os 4 | 5 | import argparse 6 | parser = argparse.ArgumentParser() 7 | parser.add_argument("--date_start", "-s") 8 | parser.add_argument("--date_end", "-e") 9 | args = parser.parse_args() 10 | 11 | EP_DIR = os.path.join( os.path.abspath('.'), 'ep07') 12 | EP_DIR = os.path.dirname(os.path.abspath(__file__)) 13 | 14 | with open( os.path.join(EP_DIR, 'select.sql'), 'r' ) as open_file: 15 | query = open_file.read() 16 | 17 | query_format = query.format( date_start=args.date_start, 18 | date_end=args.date_end ) 19 | 20 | con = sqlalchemy.create_engine("sqlite:///" + "/home/teo/Área de trabalho/cursoSQL/olist.db") 21 | # mostra as tabelas do banco 22 | con.table_names() 23 | 24 | df = pd.read_sql_query(query_format, con) # Dispara a query, executa, traz o dado e tranforma em DF 25 | print("Os dados tem", df.shape[0], "linhas") 26 | 27 | df_describe = df.describe().T.reset_index().rename(columns={"index":"stats"}) 28 | df_describe['date_start'] = args.date_start 29 | df_describe['date_end'] = args.date_end 30 | 31 | df_describe.to_sql('decribe_orders', con, index=False, if_exists='append') -------------------------------------------------------------------------------- /ep07/select.sql: -------------------------------------------------------------------------------- 1 | select * 2 | 3 | from tb_orders_delivered as t1 4 | 5 | left join tb_order_items as t2 6 | on t1.order_id = t2.order_id 7 | 8 | left join tb_sellers as t3 9 | on t2.seller_id = t3.seller_id 10 | 11 | left join tb_customers as t4 12 | on t1.customer_id = t4.customer_id 13 | 14 | left join tb_products as t5 15 | on t2.product_id = t5.product_id 16 | 17 | where t1.order_status = 'delivered' 18 | 19 | and t1.order_approved_at >= '{date_start}' 20 | and t1.order_approved_at < '{date_end}' 21 | --------------------------------------------------------------------------------