Mostrando postagens com marcador MySQL. Mostrar todas as postagens
Mostrando postagens com marcador MySQL. Mostrar todas as postagens

quinta-feira, 1 de outubro de 2020

Juntando tabelas em uma base de dados relacional com SQL

Photo by Tim Johnson on Unsplash

No primeiro post sobre a linguagem SQL fomos apresentados ao conceito de bancos de dados relacionais e a um aplicativo que nos possibilita armazenar dados em tabelas relacionadas. Nessas tabelas os dados são armazenados em colunas e cada linha dessas colunas guardam os valores de um elemento. Com a linguagem SQL podemos fazer uma junção de linhas de uma tabela com outra tabela.
Com o modelo relacional construirmos tabelas que eliminam dados duplicados, são mais flexíveis na consulta para obter dados especificísticos e fáceis de manter.

Vinculando tabelas usando JOIN

Podemos juntar tabelas durante uma consulta com a declaração JOIN ... ON (Existem outras variações que veremos mais a frente). Usamos essa declaração para vincular uma tabela a outra durante uma consulta. Desse modo usamos valores correspondentes em colunas que especificamos em ambas as tabelas. A sintaxe que vamos usar é essa:

SELECT *
FROM tabela_a JOIN tabela_b
ON tabela_a.coluna_a = tabela_b.coluna_b

Esse exemplo é parecido com a sintaxe básica da declaração SELECT. A diferença é que utilizamos JOIN para fornecer duas tabelas e não somente uma. Depois do ON é onde especificamos as colunas que queremos combinar os valores. O resultado dessa declaração é que realizamos uma consulta nas duas tabelas e retornamos as linhas onde o valor da coluna coluna_a seja igual ao valor da coluna coluna_b.
O uso mais comum da cláusula ON é procurar por colunas com valores iguais, mas também é possível realizar consultas com outras expressões onde o resultado seja verdadeiro ou falso.

Relacionando tabelas com colunas-chave

Vamos imaginar o seguinte cenário: Você é um analista de dados e acabou de ser contratado para analisar os gastos com folha de pagamento por departamento. Você faz o pedido dos dados que vai precisar esperando receber uma tabela parecida com essa:

depart localizacao nome     sobrenome salario
------ ----------- -------- --------- -------
RH     São Paulo   Daniela  Silva     62450
RH     São Paulo   Everton  Oliveira  59300
AD     Fortaleza   Fábio    Feitosa   87654
AD     Fortaleza   Dénis    Reis      87654

Mas não é o que você recebe. Você acaba de receber dois arquivos csv, cada um representando uma tabela. Analisando essas tabelas você percebe que as colunas colaboradores e departamentos se destacam.
Usando o código abaixo vamos criar essas duas tabelas e encontrar o melhor jeito de juntar os dados das tabelas. Se não souber criar uma tabela veja os tutoriais anteriores.

CREATE TABLE departamentos (
	departamento_id BIGINT AUTO_INCREMENT,
	departamento VARCHAR(100),
	cidade VARCHAR(100),
	CONSTRAINT departamento_chave PRIMARY KEY (departamento_id),
	CONSTRAINT depart_cidade_u UNIQUE (departamento, cidade)
);

CREATE TABLE colaboradores (
	colaboradores_id BIGINT AUTO_INCREMENT,
	nome VARCHAR(100),
	sobrenome VARCHAR(100),
	salario INTEGER,
	departamento_id BIGINT REFERENCES departamentos (departamento_id),
	CONSTRAINT colaboradores_chave PRIMARY KEY (colaboradores_id),
	CONSTRAINT colabo_depart_unique UNIQUE (colaboradores_id, departamento_id)
);

INSERT INTO departamentos (departamento, cidade)
VALUES
	('RH', 'São Paulo'),
	('AD', 'Fortaleza');

INSERT INTO colaboradores (nome, sobrenome, salario, departamento_id)
VALUES
	('Erique', 'Silva', 62500, 1),
	('Fabiana', 'Oliveira', 59300, 1),
	('Eveline', 'Reis', 83000, 2),
	('Daniela', 'Ferreira', 95000, 2);

Podemos notar que as duas tabelas que acabamos de criar seguem o modelo proposto por Codd em que cada tabela descreve atributos de uma única entidade, nesse exemplo sobre os colaboradores e os departamentos. Fazendo uma consulta simples vemos que o conteúdo da tabela departamentos é esse:

SELECT * FROM departamentos;
+-----------------+--------------+-----------+
| departamento_id | departamento | cidade    |
+-----------------+--------------+-----------+
|               2 | AD           | Fortaleza |
|               1 | RH           | São Paulo |
+-----------------+--------------+-----------+
2 rows in set (0.003 sec)

A coluna departamento_id é a chave primária da tabela, definimos isso na linha cinco. Isso quer dizer que os valores dessa tabela não podem ser repetidos e não devem ser nulos (deve ser adicionado algum valor). Para não precisarmos adicionar um valor para a coluna departamento_id adicionamos a cláusula AUTO_INCREMENT. Desse modo quando for adicionado uma nova linha a tabela, a coluna departamento_id será acrecida de um valor crescente. Adicionamos a restrição PRIMARY KEY porque cada departamento é único, não existe dois RH numa empresa. Nos próximos tutoriais vamos aprender mais sobre restrições (CONSTRAINT).
Se você realizar uma consulta simples na tabela de colaboradores o conteúdo deve ser esse:

SELECT * FROM colaboradores;
+------------------+----------+-----------+---------+-----------------+
| colaboradores_id | nome     | sobrenome | salario | departamento_id |
+------------------+----------+-----------+---------+-----------------+
|                1 | Erique   | Silva     |   62500 |               1 |
|                2 | Fabiana  | Oliveira  |   59300 |               1 |
|                3 | Eveline  | Reis      |   83000 |               2 |
|                4 | Daniela  | Ferreira  |   95000 |               2 |
+------------------+----------+-----------+---------+-----------------+
8 rows in set (0.003 sec)

A coluna colaboradores_id é utilizada para identificar cada funcionário. Para saber em qual departamento um funcionário trabalha temos a colunas departamento_id. Os valores dessa coluna fazem referência aos valores da coluna departamento_id da tabela departamentos. Essa referência a outra coluna em outra tabela é chamada de chave estrangeira. Uma restrição com chave estrangeira usando referência (REFERENCES) só nos permite adicionar um valor se esse valor já estiver presente na coluna estrangeira, no nosso caso na coluna departamento_id. Isso quer disser que para adicionar o valor 1 na coluna departamento_id da tabela colaboradores esse valor já deve estar presente na coluna departamento_id da tabela departamentos.
Outra restrição é a UNIQUE. Utilizamos UNIQUE para definir que a tabela não pode ter valores repetidos. Agora você deve estar pensando que UNIQUE e PRIMARY KEY são a mesma coisa, mas isso não é verdade. Existem duas diferenças entre as duas. A primeira é que uma tabela só pode ter uma coluna PRIMARY KEY enquanto a mesma tabela pode ter várias colunas UNIQUEs. E a segunda diferença é que uma coluna UNIQUE aceita o valor nulo. Vamos aprender mais sobre essa restrição em outro tutorial.
Nesse momento você deve estar pensando pra que serve essas restrições, além de complicar a sua vida. E a resposta é bem simples: Não permitir a entrada de dados duplicados. Se cada departamento e cidade são únicos porque duplicar esses valores. Se tivéssemos recebidos os dados do jeito que queríamos inicialmente era isso que ia acontecer. Não tem problema ter dados duplicados numa tabela com quatro valores como a nossa, ou quatro mil. Mas agora imagine um banco de dados com milhares de linhas. Agora temos um problema: estamos desperdiçando espaço para armazenar valores duplicados.
Agora que você sabe o básico de como as tabelas podem se relacionar, vamos dar uma olhada em como juntá-los em uma consulta.

Consultando várias tabelas usando JOIN

Quando realizamos uma consulta com JOIN o banco de dados nos retorna uma tabela com as linhas das tabelas lado a lado. Isso para cada linha que a condição passada depois da cláusula ON seja verdadeira. Ainda podemos filtrar os resultados dessa consulta com a cláusula WHERE.
As consultas usando JOIN são parecidas com a sintaxe básica de uma consulta simples com SELECT. A diferença é que usamos JOIN … ON para selecionar as tabelas e as variações de JOIN para definir os critérios da junção.
Vamos começar com um exemplo simples. Para a nossa primeira consulta utilizando JOIN queremos os dados de todas as colunas onde os valores de departamento_id (da tabela colaboradores) e departamento_id (da tabela departamentos) sejam iguais.

SELECT *
FROM colaboradores JOIN departamentos
ON colaboradores.colaboradores_id = departamentos.departamento_id;
+------------------+---------+-----------+---------+-----------------+-----------------+--------------+-----------+
| colaboradores_id | nome    | sobrenome | salario | departamento_id | departamento_id | departamento | cidade    |
+------------------+---------+-----------+---------+-----------------+-----------------+--------------+-----------+
|                2 | Fabiana | Oliveira  |   59300 |               1 |               2 | AD           | Fortaleza |
|                1 | Erique  | Silva     |   62500 |               1 |               1 | RH           | São Paulo |
+------------------+---------+-----------+---------+-----------------+-----------------+--------------+-----------+
2 rows in set (0.002 sec)

Nessa busca foi retornado apenas duas linhas, mesmo fazendo a consulta nas duas tabelas, isso acontece porque definimos uma condição para a busca. E a condição é o valor das colunas colaboradores_id das duas tabelas serem iguais.
É possível fazer uma consulta nas duas colunas sem definir uma condição. Desse modo as tabelas serão apresentadas uma do lado da outra. Para isso use a declaração SELECT * FROM tabela1 JOIN tabela2;.
Utilizando a cláusula ON ou não você vai perceber que a tabela com menos linhas vai se repeti até que as duas tabelas tenham o mesmo número.

JOIN

Utilizamos JOIN ou INNER JOIN quando queremos consultar duas ou mais tabelas que tenham uma tabela em comum. No exemplo anterior, as tabelas colaboradores e departamentos tinham a coluna colaboradores_id em comum. Para os nossos próximos exemplos vamos usar essa tabela:

CREATE TABLE escola_esquerda (id INT, escola_esquerda VARCHAR(50));

CREATE TABLE escola_direita (id INT, escola_direita VARCHAR(50));

INSERT INTO escola_esquerda (id, escola_esquerda)
VALUES
	(1, 'COLEGIO CONTATO MACEIO'),
	(2, 'COLEGIO HARMONIA'),
	(3, 'ESC COLEGIO LATO SENSU'),
	(4, 'COLEGIO OBJETIVO'),
	(5, 'ESC AQUARELA ENSINO E CULTURA');
	
INSERT INTO escola_direita (id, escola_direita)
VALUES
	(1, 'COLEGIO CONTATO MACEIO'),
	(2, 'COLEGIO HARMONIA'),
	(3, 'ESC COLEGIO LATO SENSU'),
	(5, 'ESC AQUARELA ENSINO E CULTURA'),
	(6, 'ESC COLEGIO VITORIA');

Veja um exemplo utilizando JOIN:

SELECT *
FROM escola_esquerda JOIN escola_direita
ON escola_esquerda.id = escola_direita.id;
+------+-------------------------------+------+-------------------------------+
| id   | escola_esquerda               | id   | escola_direita                |
+------+-------------------------------+------+-------------------------------+
|    1 | COLEGIO CONTATO MACEIO        |    1 | COLEGIO CONTATO MACEIO        |
|    2 | COLEGIO HARMONIA              |    2 | COLEGIO HARMONIA              |
|    3 | ESC COLEGIO LATO SENSU        |    3 | ESC COLEGIO LATO SENSU        |
|    5 | ESC AQUARELA ENSINO E CULTURA |    5 | ESC AQUARELA ENSINO E CULTURA |
+------+-------------------------------+------+-------------------------------+
4 rows in set (0.167 sec)

Você deve utilizar o JOIN quando os dados estiverem bem estruturados e uma relação entre as tabelas. Para retornar os valores das duas tabelas use outro tipo de JOIN.

LEFT JOIN e RIGHT JOIN

Utilizamos LEFT JOIN e RIGHT JOIN quando queremos que todos os elementos de uma tabela apareçam na consulta. Por exemplo, você quer que todos os elementos da tabela escola_esquerda apareçam na consulta, assim usamos LEFT JOIN. Os elementos da tabela escola_direita que não tiverem um correspondente na tabela escola_esquerda apareceram em branco (NULL). O mesmo vale para RIGHT JOIN. Veja um exemplo de utilização dos dois JOIN:

SELECT *
FROM escola_esquerda LEFT JOIN escola_direita
ON escola_esquerda.id = escola_direita.id;
+------+-------------------------------+------+-------------------------------+
| id   | escola_esquerda               | id   | escola_direita                |
+------+-------------------------------+------+-------------------------------+
|    1 | COLEGIO CONTATO MACEIO        |    1 | COLEGIO CONTATO MACEIO        |
|    2 | COLEGIO HARMONIA              |    2 | COLEGIO HARMONIA              |
|    3 | ESC COLEGIO LATO SENSU        |    3 | ESC COLEGIO LATO SENSU        |
|    5 | ESC AQUARELA ENSINO E CULTURA |    5 | ESC AQUARELA ENSINO E CULTURA |
|    4 | COLEGIO OBJETIVO              | NULL | NULL                          |
+------+-------------------------------+------+-------------------------------+
5 rows in set (0.004 sec)

SELECT *
FROM escola_esquerda RIGHT JOIN escola_direita
ON escola_esquerda.id = escola_direita.id;
+------+-------------------------------+------+-------------------------------+
| id   | escola_esquerda               | id   | escola_direita                |
+------+-------------------------------+------+-------------------------------+
|    1 | COLEGIO CONTATO MACEIO        |    1 | COLEGIO CONTATO MACEIO        |
|    2 | COLEGIO HARMONIA              |    2 | COLEGIO HARMONIA              |
|    3 | ESC COLEGIO LATO SENSU        |    3 | ESC COLEGIO LATO SENSU        |
|    5 | ESC AQUARELA ENSINO E CULTURA |    5 | ESC AQUARELA ENSINO E CULTURA |
| NULL | NULL                          |    6 | ESC COLEGIO VITORIA           |
+------+-------------------------------+------+-------------------------------+
5 rows in set (0.001 sec)

RIGHT JOIN e LEFT JOIN são usados quando você precisa que todos os elementos de uma tabela apareçam, quando você quer comparar duas tabelas procurando por dados ausentes e quando você precisa saber quais elementos de uma tabela não tem correspondentes na outra tabela.

Usando NULL para encontrar linhas com valores ausentes

Podemos descobrir quais são os valores ausentes numa consulta usando WHERE com NULL. Por exemplo, no exemplo acima a nossa consulta retorna um valor NULL, podemos usar esse valor para descobrir quais são as linhas que não têm correspondentes na outra tabela. Veja como fazer isso:

SELECT *
FROM escola_esquerda LEFT JOIN escola_direita
ON escola_esquerda.id = escola_direita.id
WHERE escola_direita.id IS NULL;
+------+------------------+------+----------------+
| id   | escola_esquerda  | id   | escola_direita |
+------+------------------+------+----------------+
|    4 | COLEGIO OBJETIVO | NULL | NULL           |
+------+------------------+------+----------------+
1 row in set (0.001 sec)

Com esse exemplo descobrimos que o valor 4 da coluna id da tabela escola_esquerda não tem um correspondente na tabela escola_direita.
Obs: Quando for trabalhar com o valor NULL use sempre IS porque NULL = NULL retorna NULL e NULL IS NULL retorna 1.

quinta-feira, 24 de setembro de 2020

Matemática básica e estatística com SQL


Se o seu banco de dados incluir algum tipo de dados do tipo inteiro, decimais ou pontos flutuantes é provável que você vai precisar realizar alguns cálculos com esses dados. Por exemplo, se você precisar saber qual é o valor da soma de todos os elementos de uma coluna, ou você precise adicionar um valor a cada elemento de uma coluna ou linha. Felizmente podemos fazer essas tarefas utilizando a linguagem SQL. Com ela podemos realizar desde operações matemáticas básicas a estatísticas avançadas.
Nesse tutorial, vamos iniciar no básico das operações matemáticas e avançar para as funções matemáticas mais complexas e iniciar em estatística. O dataset que vamos usar pode ser baixado aqui.
Veja abaixo como importar esses dados:

MariaDB [(none)]> create database meu_db;
Query OK, 1 row affected (0.151 sec)

MariaDB [(none)]> use meu_db;
Database changed
MariaDB [meu_db]> create table censu_2015
    -> (CensusTract INT,State VARCHAR(15),County VARCHAR(15),
    -> TotalPop INT,Men INT,Women INT,
    -> Hispanic FLOAT,White FLOAT,Black FLOAT,
    -> Native FLOAT,Asian FLOAT,Pacific FLOAT,
    -> Citizen INT,Income FLOAT,IncomeErr FLOAT,
    -> IncomePerCap FLOAT,IncomePerCapErr FLOAT,Poverty FLOAT,
    -> ChildPoverty FLOAT,Professional FLOAT,Service FLOAT,
    -> Office FLOAT,Construction FLOAT,Production FLOAT,
    -> Drive FLOAT,Carpool FLOAT,Transit FLOAT,
    -> Walk FLOAT,OtherTransp FLOAT,WorkAtHome FLOAT,
    -> MeanCommute FLOAT,Employed INT,PrivateWork FLOAT,
    -> PublicWork FLOAT,SelfEmployed FLOAT,FamilyWork FLOAT,
    -> Unemployment FLOAT);
Query OK, 0 rows affected (0.914 sec)

MariaDB [meu_db]> LOAD DATA LOCAL INFILE
    -> 'C:/Users/user/acs2015_census_tract_data.csv'
    -> INTO TABLE censu_2015
    -> FIELDS TERMINATED BY ','
    -> LINES TERMINATED BY '\n'
    -> IGNORE 1 LINES;
Query OK, 74001 rows affected, 65535 warnings (8.923 sec)
Records: 74001  Deleted: 0  Skipped: 0  Warnings: 97104

Operações matemáticas

Nos primeiros exemplos vamos utilizar as operações básicas que você aprendeu na escola. Na tabela abaixo é mostrado as operações que vamos utilizar com mais frequência.

Operador Operação
+ Adição
- Subtração
* Multiplicação
/ Divisão sem resto
%, MOD(x, y) Modulo ou resto
^ Exponenciação
SQRT(x) Raiz quadrada

Esses operadores podem ser utilizados com números, como numa calculadora, ou com valores em tabelas. Nesse tutorial vamos mostrar os dois.

Tipos de dados e matemática

Quando estiver trabalhando com operações matemáticas é importante saber o tipo de dado onde essas operações serão aplicadas. Não ter conhecimento do tipo de dado pode resultar num erro ou numa operação indesejada.
Aplicando uma operação entre dois números, o resultado retornado segue o padrão abaixo:

  • Dois inteiros retorna um inteiro.
  • Um NUMERIC com outro retorna um NUMERIC.
  • Qualquer operação com um float retorna um float.

Mas com a exponenciação e a raiz quadrada isso não acontece. A operação de raiz quadrada pode retornar um número de ponto flutuante mesmo quando a operação é com um inteiro e a exponenciação pode retornar um inteiro.

Adição, subtração e multiplicação

Até o momento utilizamos a declaração SELECT para recuperar dados de uma tabela. Nesse tutorial vamos utilizá-lo em conjunto com os operadores para realizar operações matemáticas. Vamos começar com as operações de adição, subtração e multiplicação.

MariaDB [(none)]> SELECT 2 + 2;
+-------+
| 2 + 2 |
+-------+
|     4 |
+-------+
1 row in set (0.038 sec)

MariaDB [(none)]> SELECT 9 - 2;
+-------+
| 9 - 2 |
+-------+
|     7 |
+-------+
1 row in set (0.001 sec)

MariaDB [(none)]> SELECT 3 * 4;
+-------+
| 3 * 4 |
+-------+
|    12 |
+-------+
1 row in set (0.007 sec)

Não temos surpresas aqui. Como esperado dois mais dois é quatro, nove menos dois é sete e, como sempre, três vezes quatro é doze. O resultado é mostrado numa coluna, mas não se preocupe, nenhuma tabela está sendo alterada.

Divisão, modulo e raiz quadrada

Na divisão, o resultado sempre será um número de ponto flutuante. Isso porque o operador de divisão faz a divisão exata. Já o operador módulo retorna o resto de uma divisão. Esse operador realiza uma divisão e retorna o resto dessa divisão. Se a divisão for exata o resto é zero, do contrário, o resto será um inteiro. A função de raiz quadrada retorna a raiz quadrada do número passado como parâmetro. Veja um exemplo de utilização:

MariaDB [(none)]> SELECT 9 / 2;
+--------+
| 9 / 2  |
+--------+
| 4.5000 |
+--------+
1 row in set (0.001 sec)

MariaDB [(none)]> SELECT MOD(9,2);
+----------+
| MOD(9,2) |
+----------+
|        1 |
+----------+
1 row in set (0.001 sec)

MariaDB [(none)]> SELECT 9 % 2; -- O mesmo da declaração acima
+-------+
| 9 % 2 |
+-------+
|     1 |
+-------+
1 row in set (0.001 sec)

MariaDB [(none)]> SELECT SQRT(9);
+---------+
| SQRT(9) |
+---------+
|       3 |
+---------+
1 row in set (0.001 sec)

Ordem das operações

Nas expressões matemáticas existe uma ordem em que as operações devem ser feitas. No SQL é a mesma coisa. Por exemplo, qual operação deve ser executada primeiro? A subtração ou a multiplicação? Por isso é importante saber qual operação deve ser aplicada primeiro para atingir o resultado esperado. Essa é a ordem de prioridade dos operadores:

  1. Funções. No caso a função SQRT().
  2. Multiplicação, divisão e módulo.
  3. Adição e subtração.

Seguindo essa ordem as funções serão executadas primeiro, depois a multiplicação, divisão e módulo e, por último, a adição e subtração.
Se em algum momento você precisar a operação de adição ocorra antes da multiplicação, você pode alterar essa ordem de prioridade com parênteses. No exemplo abaixo, o resultado é diferente para cada declaração. Isso porque foi alterada a prioridade das operações.

MariaDB [(none)]> SELECT 5 + 4 * 9;
+-----------+
| 5 + 4 * 9 |
+-----------+
|        41 |
+-----------+
1 row in set (0.003 sec)

MariaDB [(none)]> SELECT (5 + 4) * 9;
+-------------+
| (5 + 4) * 9 |
+-------------+
|          81 |
+-------------+
1 row in set (0.060 sec)

Operações com colunas

Agora que já aprendemos como utilizar os operadores na linguagem SQL vamos aprender a usar esses mesmos operadores com valores em colunas. Quando usamos esses operadores em colunas a operação é realizada em cada linha da tabela.

MariaDB [meu_db]> SELECT State AS 'Estado',
    -> County AS 'Município',
    -> Asian AS 'Asiático',
    -> Hispanic AS 'Hispanico',
    -> Hispanic + Asian AS "Total de Hispânicos e Asiáticos"
    -> FROM censu_2015
    -> WHERE  State = 'Kansas';
+--------+--------------+----------+-----------+---------------------------------+
| Estado | Município    | Asiático | Hispanico | Total de Hispânicos e Asiáticos |
+--------+--------------+----------+-----------+---------------------------------+
| Kansas | Allen        |        0 |         3 |                               3 |
| Kansas | Allen        |      1.5 |         1 |                             2.5 |
| Kansas | Allen        |        0 |       0.1 |             0.10000000149011612 |
| Kansas | Allen        |      1.3 |       6.3 |              7.6000001430511475 |
| Kansas | Allen        |        0 |       5.9 |               5.900000095367432 |
| Kansas | Anderson     |        0 |       0.5 |                             0.5 |
| Kansas | Anderson     |        0 |       0.3 |             0.30000001192092896 |
| Kansas | Wyandotte    |        0 |       7.7 |               7.699999809265137 |
| Kansas | Wyandotte    |        0 |        44 |                              44 |
| Kansas | Wyandotte    |     16.5 |      33.4 |              49.900001525878906 |
| Kansas | Wyandotte    |      2.3 |      28.9 |              31.199999570846558 |
+--------+--------------+----------+-----------+---------------------------------+
770 rows in set (0.130 sec)

Essa não é a saída completa da busca, na sua máquina deve está bem maior. Mas, para o nosso proposito vai servir. Vamos começar explicando o código linha por linha. Na primeira linha selecionamos a coluna “State” e demos um apelido para ela (Estado). Fizemos a mesma coisa na linha dois, três e quatro. Depois pedimos para o gerenciador do banco de dados fazer a soma da coluna Hispanic e Asian e, como nas linhas anteriores, demos um apelido a essa coluna – Lembre-se que cada consulta retorna os dados organizados em colunas. Na linha seis informamos onde esses dados devem ser procurados. E por último fazemos uma filtragem dos dados com WHERE. Com a declaração WHERE estamos dizendo que só queremos os dados das colunas State, County, Asian e Hispanic onde o valor da coluna State seja igual a Kansas.
Com esse exemplo fica fácil perceber como as operações funcionam em tabelas. Como exercício tente realizar as outras operações e mudar o estado.

Porcentagem

Para o nosso próximo exemplo vamos descobrir qual é a porcentagem de homens no estado do Texas. Para isso vamos precisar saber a quantidade total da população e a quantidade total de homens. Nosso banco de dados já tem essas informações.
Veja como descobrir a porcentagem de homens no estado do Texas no exemplo abaixo:

MariaDB [meu_db]> SELECT State AS 'Estado',
    -> SUM(Men) AS 'Total Homens',
    -> SUM(Women) AS 'Total Mulheres',
    -> (SUM(Men) * 100) / (SUM(Men) + SUM(Women)) AS 'Porcentagem de Homens'
    -> FROM censu_2015
    -> WHERE State = 'Texas';
+--------+--------------+----------------+-----------------------+
| Estado | Total Homens | Total Mulheres | Porcentagem de Homens |
+--------+--------------+----------------+-----------------------+
| Texas  |     13171316 |       13367298 |               49.6308 |
+--------+--------------+----------------+-----------------------+
1 row in set (0.316 sec)

Nesse exemplo usamos a função SUM() para somar todos as linhas das colunas Men e Women, lembre-se que estamos somando apenas os valores das linhas que tenham o valor Texas na coluna State. Depois utilizamos as operações de multiplicação, divisão e soma para descobrir a porcentagem de homens no estado do Texas (Regra de três).

Função de soma e médias

As duas funções mais utilizadas na análise de dados são a SUM() e AVG(). Isso porque a função SUM() faz a soma de todas as linhas de uma coluna, como vimos no exemplo anterior. E a função AVG() retorna o valor médio de uma coluna numérica. O que a função AVG() faz é somar todos os valores de uma coluna e depois dividir pelo número de linhas. Veja um exemplo de utilização das duas funções abaixo:

MariaDB [meu_db]> SELECT AVG(TotalPop) FROM censu_2015;
+---------------+
| AVG(TotalPop) |
+---------------+
|     4325.5915 |
+---------------+
1 row in set (1.760 sec)

MariaDB [meu_db]> SELECT SUM(TotalPop) FROM censu_2015;
+---------------+
| SUM(TotalPop) |
+---------------+
|     320098094 |
+---------------+
1 row in set (0.168 sec)

Com a função AVG() descobrimos que a média dos valores da coluna TotalPop é 4325.5915 e com a função SUM() descobrimos que o total da soma da coluna TotalPop é 320098094.

domingo, 9 de agosto de 2020

Banco de dados com pandas

Imagem de CopyrightFreePictures por Pixabay

Já falamos algumas vezes que a biblioteca pandas é ótima para trabalhar com dados estruturados ou tabulares. É comum que grandes empresas usem bancos de dados para guardar dados tabulares ou estruturados. Nesse tutorial, vamos aprender a inserir e ler dados de um banco dados.
Vamos utilizar o SQLite. Este sistema de gerenciamento de banco de dados já está incluído no Python. Por isso não vamos precisar instalar nenhum módulo. Além do SQLite, podemos utilizar python para se conectar com os sistemas de gerenciamentos de banco de dados mais utilizados na atualidade. E podemos utilizar isso com o pandas.

Como utilizar o SQLite do python

Primeiro vamos criar um banco de dados e armazenar informações sobre pessoas aleatórias.

>>> import sqlite3
>>> db = sqlite3.connect('pessoas.db')
>>> cursor = db.cursor()
>>> cursor.execute(
... '''CREATE TABLE pessoas(id INTEGER PRIMARY KEY,
... p_nome TEXT, u_nome TEXT, aniversario INT)'''
... )
<sqlite3.Cursor object at 0x7f7993ce6650>
>>> cursor.execute(
... '''INSERT INTO pessoas VALUES(
... 0, 'Mario', 'Perreira', 1923)'''
... )
<sqlite3.Cursor object at 0x7f7993ce6650>
>>> cursor.execute(
... '''INSERT INTO pessoas VALUES(
... 1, 'Diana', 'Cruz', 1992)'''
... )
<sqlite3.Cursor object at 0x7f7993ce6650>
>>> db.commit()

Agora que já temos o nosso banco de dados vamos passar os dados desse banco de dados para um dataframe pandas. Para ler uma tabela vamos precisar usar o módulo SQLAlchemy. Esse módulo nós ajuda simplificando o processo de obtenção dos dados. O módulo SQLAlchemy não vem instalado com o python mas você pode instalar com o pip: pip install sqlalchemy.

>>> import pandas as pd
>>> import sqlalchemy as sa
>>> engine = sa.create_engine(
... 'sqlite:///pessoas.db', echo=True
... )
>>> conexao_sa = engine.connect()
>>> pessoas = pd.read_sql_table(
... 'pessoas', conexao_sa, index_col='id'
... )
>>> pessoas
   p_nome    u_nome  aniversario
id                              
0   Mario  Perreira         1923
1   Diana      Cruz         1992

Você pode selecionar os dados que quer ler com um consulta SQL. A consulta pode ser feita usando uma conexão SQLite ou SQLAlchemy. Nesse exemplo vamos usar a conexão SQLite do primeiro exemplo:

>>> nome_aniversario = pd.read_sql(sql, db)
>>> nome_aniversario
  p_nome  aniversario
0  Mario         1923
1  Diana         1992

Como funciona...

Nos exemplos desse tutorial, fizemos uso do módulo SQLAlchemy. Essa biblioteca faz a conexão entre o banco de dados SQL. SQLAlchemy pode criar uma conexão com a maioria dos bancos de dados SQL. Com essa conexão podemos criar dataframes a partir de tabelas. E ainda podemos criar um dataframe a partir de uma consulta SQL.

Referência:
Módulo SQLite3
Módulo SQLAlchemy

quinta-feira, 23 de abril de 2020

MySQL em Python

MySQL em Python


Instalação e teste

MySQL é um dos bancos de dados mais utilizados na atualidade. E nos podemos utilizar esse banco de dados nas nossas aplicações em python.

Database MySQL

Para poder utilizar o banco de dados MySQL nas nossas aplicações, primeiro precisamos ter o MySQL instalado no nosso computador.
Caso você não tenha o MySQL instalado você pode baixa-lo gratuitamente aqui.
Se você utiliza uma distribuição Linux tente instalar o pacote mysql-server pelo gerenciador de pacotes da sua distribuição.
Uma alternativa ao MySQL é o MariaDB. O MariaDB é um fork do MySQL e é mais fácil de instalar. Todos os exemplos vão funcionar perfeitamente no MariaDB.

Instalando o driver do MySQL

Para ter acesso ao nosso banco de dados precisamos instalar o drive do MySQL.
Para instalar esse drive vamos utilizar o pip.
Copie e cole o texto abaixo no terminal (Linux ou Mac) ou promtp de comando (Windows).
python -m pip install mysql-connector
Com isso feito estamos prontos para usar o banco de dados MySQL.

Testando a conexão com o banco de dados

Para testar a conexão com o banco de dados é só importar o módulo mysql.connector. Se for apresentado algum erro a instalação do banco de dados ou do drive não foi bem sucedida. E se não for apresentado nada à instalação foi bem sucedida.
Exemplo
import mysql.connector

Criando uma conexão com o banco de dados MySQL

Para criar uma conexão com o banco de dados utilizamos o método connect. O método connect precisa receber os argumentos host, user e passwd. O primeiro argumento é o endereço da maquina (Se for uma maquina remota um ip deve ser fornecido, não é o nosso caso por isso usamos localhost). O segundo argumento é o usuário (vamos utilizar o usuário root. Esse já é criado por padrão). E por último o passwd. Nos exemplos desse tutorial não vamos utilizar senha, mas se você definiu uma senha deve utiliza-la.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd=''
)

print(meubd)
Você deve receber uma resposta parecido com essa:
<mysql.connector.connection.MySQLConnection object at 0x02ED60B8>

Criando um banco de dados

Para criar um banco de dados chamamos o método execute com a seguinte string: CREATE DATABASE nome-do-meu-banco-de-dados.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd=''
)

meucursor = meubd.cursor()
meucursor.execute('CREATE DATABASE meuBD')
O método cursor instancia objetos que podem executar operações como instruções SQL.
Que é exatamente o que o método execute faz.
Se não for apresentado nenhum erro o banco de dados meuBD foi criado.

Verificando se um banco de dados existe

Para verificar se um banco de dados existe vamos utilizar a instrução SQL SHOW DATABASES.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd=''
)

meucursor = meubd.cursor()
meucursor.execute('SHOW DATABASES')

for i in meucursor:
  print(i)
Esse exemplo vai retornar uma lista com os bancos de dados do sistema.
Também podemos definir o banco de dados no momento da conexão.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd='',
  database='meuBD'
)
Se houver algum erro é por que o banco de dados meuBD não existe.

Criando tabelas

Para criar uma tabela usamos a instrução SQL CREATE TABLE nomedatabela.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd='',
  database='meuBD'
)
meucursor = meubd.cursor()

meucursor.execute("CREATE TABLE minhaT (name VARCHAR(255), address VARCHAR(255))")
Se nenhum erro for apresentado a tabela minhaT foi criada.

Verificando se uma tabela existe

Você pode verificar se uma tabela existe no seu banco de dados usando a instrução sql SHOW TABLES. A instrução show tables vai monstra todas as tabelas do seu banco de dados.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd='',
  database='meuBD'
)
meucursor = meubd.cursor()
meucursor.execute('SHOW TABLES')

for i in meucursor:
  print(i)
Quando você criar uma tabela, você também deve criar uma coluna com uma chave exclusiva para cada registro.
Isso pode ser feito definindo uma chave primária.
Usamos a instrução "INT AUTO_INCREMENT PRIMARY KEY" que inserirá um número exclusivo para cada registro. Começando em um e aumentado em um para cada registro.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd='',
  database='meuBD'
)
meucursor = meubd.cursor()
meucursor.execute('CREATE TABLE minhaT (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255), address VARCHAR(255))')
Se a tabela já existir utilizamos ALTER TABLE.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd='',
  database='meuBD'
)
meucursor = meubd.cursor()
meucursor.execute('ALTER TABLE minhaT ADD COLUMN id INT AUTO_INCREMENT PRIMARY KEY')

Inserindo dados na tabela

Para inserir dados numa tabela utilizamos a instrução sql INSERT INTO.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd='',
  database='meuBD'
)
meucursor = meubd.cursor()
instrucaoSQL = "INSERT INTO minhaT (name, address) VALUES (%s, %s)"
dados = ("João", "São Paulo - SP")
meucursor.execute(instrucaoSQL, dados)

meubd.commit()

print(meucursor.rowcount, 'Dados inseridos.')
O método commit salva as alterações feitas no banco de dados.

Inserindo múltiplas linhas

Para inserir múltiplas linhas vamos utilizar o método executemany. O método executemany recebe dois argumentos: a instrução sql e os dados. Os dados devem estar numa lista de tuplas.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd='',
  database='meuBD'
)
meucursor = meubd.cursor()
instrucaoSQL = "INSERT INTO minhaT (name, address) VALUES (%s, %s)"
dados = [
  ('Maria', 'Rio branco - AC'),
  ('Fabiana', 'Tíbau - RN'),
  ('Fábio', 'Rio de janeiro - RJ'),
  ('Michele', 'Fortaleza - CE')
]

meucursor.executemany(instrucaoSQL, dados)

meubd.commit()

print(meucursor.rowcount, 'Dados inseridos.')

ID da última linha inserida

É fácil descobrir o id da última linha inserida na tabela com o atributo lastrowid.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd='',
  database='meuBD'
)
meucursor = meubd.cursor()
instrucaoSQL = "INSERT INTO minhaT (name, address) VALUES (%s, %s)"
dados = ("Naruto", "Konoha")
meucursor.execute(instrucaoSQL, dados)

meubd.commit()

print("Uma linha foi inserida, ID:", meucursor.lastrowid)

Selecionando elementos da tabela

Para selecionar dados de uma tabela utilizamos a instrução sql SELECT.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd='',
  database='meuBD'
)
meucursor = meubd.cursor()
meucursor.execute("SELECT * FROM minhaT")

resultado = meucursor.fetchall()

for i in resultado:
  print(i)
Nesse exemplo estamos selecionando todos os elementos da tabela minhaT.
O método fetchall busca todas as linhas da última instrução executada.

Selecionando colunas

Para selecionar as colunas da nossa tabela é só especificarmos os nomes das colunas.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd='',
  database='meuBD'
)
meucursor = meubd.cursor()
meucursor.execute("SELECT name, address FROM minhaT")

resultado = meucursor.fetchall()

for i in resultado:
  print(i)

Método fetchone

Se você só precisar da primeira linha da tabela use o método fetchone. O método fetchone retorna uma tupla com a primeira linha da tabela.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd='',
  database='meuBD'
)
meucursor = meubd.cursor()
meucursor.execute("SELECT * FROM minhaT")

resultado = meucursor.fetchone()

print(resultado)

Instrução WHERE

Com a instrução where selecionamos com dados com um filtro melhor. Em vez de selecionar uma coluna ou uma linha da nossa tabela podemos selecionar um dado.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd='',
  database='meuBD'
)
meucursor = meubd.cursor()
instrucaoSQL = "SELECT * FROM minhaT WHERE address ='Rio branco - AC'"

meucursor.execute(instrucaoSQL)

resultado = meucursor.fetchall()

for i in resultado:
  print(i)
Com esse exemplo todos os dados da coluna address que o valor seja “Rio branco – AC” vão ser mostrados.

Caracteres coringa

Se você precisar procurar no banco de dados por um dado que você só conhece uma parte, os caracteres coringa podem ajudar. Com eles você só precisar saber uma parte do que você está procurando.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd='',
  database='meuBD'
)
meucursor = meubd.cursor()
instrucaoSQL = "SELECT * FROM minhaT WHERE address LIKE '%RN%'"

meucursor.execute(instrucaoSQL)

resultado = meucursor.fetchall()

for i in resultado:
  print(i)

Ordenando por resultado

Podemos ordenar os nossos resultados de forma crescente ou decrescente usando a instrução SORT BY.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd='',
  database='meuBD'
)
meucursor = meubd.cursor()
instrucaoSQL = "SELECT * FROM minhaT ORDER BY name"

meucursor.execute(instrucaoSQL)

resultado = meucursor.fetchall()

for i in resultado:
  print(i)

Ordem decrescente

Por padrão a instrução ORDER BY ordena os resultados de forma crescente. Para mudarmos esse comportamento usamos o DESC.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd='',
  database='meuBD'
)
meucursor = meubd.cursor()
instrucaoSQL = "SELECT * FROM minhaT ORDER BY name DESC"

meucursor.execute(instrucaoSQL)

resultado = meucursor.fetchall()

for i in resultado:
  print(i)

Apagando dados

Você pode apagar dados de uma tabela com a instrução DELETE FROM.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd='',
  database='meuBD'
)
meucursor = meubd.cursor()
instrucaoSQL = "DELETE FROM minhaT WHERE address = 'Rio branco - AC'"

meucursor.execute(instrucaoSQL)
meubd.commit()

print(meucursor.rowcount, 'Dados apagados.')

Apagando uma tabela

Para apagar uma tabela do nosso banco de dados usamos a instrução DROP TABLE.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd='',
  database='meuBD'
)
meucursor = meubd.cursor()
instrucaoSQL = 'DROP TABLE minhaT'

meucursor.execute(instrucaoSQL)
Com esse exemplo se você tentar apagar uma tabela que não existe um erro vai ser lançado. Para evitar isso podemos usar o IF EXISTS.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd='',
  database='meuBD'
)
meucursor = meubd.cursor()
instrucaoSQL = 'DROP TABLE IF EXISTS minhaT'

meucursor.execute(instrucaoSQL)

Atualizando dados de uma tabela

Para atualizar dados de uma tabela utilizamos a instrução UPDATE.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd='',
  database='meuBD'
)
meucursor = meubd.cursor()
instrucaoSQL = "UPDATE minhaT SET address = 'Campinas' WHERE address = 'Campinas - SP'"

meucursor.execute(instrucaoSQL)

meubd.commit()

print(meucursor.rowcount, 'Dado(s) atualizado(s).')
O primeiro valor (Campinas) é o dado que será alterado.

Limitando os resultados

Com uma tabela pequena não é preciso limitar os resultados numa consulta. Mas em uma tabela com centenas ou milhões de resultados limitar os resultados passa a ser interessante.
Podemos fazer isso com a instrução LIMIT.
Exemplo
import mysql.connector

meubd = mysql.connector.connect(
  host='localhost', # máquina local
  user='root',
  passwd='',
  database='meuBD'
)
meucursor = meubd.cursor()
meucursor.execute("SELECT * FROM minhaT LIMIT 5 OFFSET 2")

resultado = meucursor.fetchall()

for i in resultado:
  print(i)
Esse exemplo retorna cinco resultados começando da terceira linha.