├── .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 |
--------------------------------------------------------------------------------