Linguagem de Consulta SQL

Definições

Banco de dados relacional é um banco de dados digital baseado no modelo relacional proposto por E. F. Codd em 1970. Sistema de software usados para construir e manter bancos de dados relacionais são chamados Sistema de Gerenciamento de Banco de Dados Relacionais (RDBMS).

SQL, (Structured Query Language) ou Linguagem de Consultas Estruturada é uma linguagem de programação usada para manipular de bancos de dados relacionais. Usando SQL é possível construir o BD, estabelecer relações entre dados nas tabelas, fazer consultas, inserir, apagar ou editar dados.

Um banco de dados consiste em várias tabelas e das relações predefinidas entre elas. Cada tabela contém colunas ou campos, cada uma delas com seu nome exclusivo e tipos de dados definido. Elas podem ter atributos que definem a funcionalidade da coluna (se é uma chave primária, se há um valor default, etc.). As linhas da tabela, ou registros, contêm os dados.

Para que serve a SQL?

Consultas SQL podem ser feitas dentro de diversos aplicativos tais como em suites MS Office, em particular no MS Access, e seus equivalentes open source. Elas também são frequentes em programas de gerenciamento de banco de dados, Business Inteligence e análises de dados tais como Qlikview e MS PowerBI. A maior parte dos sistemas de gerenciamento de conteúdo usados em sites na Internet, como WordPress e Joomla usam bancos de dados controlados por SQL.

As diversas linguagens de programação fornecem interfaces com as diversas variantes de bancos de dados SQL. Finalmente você pode instalar um Sistema Gerenciador de Banco de Dados (DBMS) em seu computador, seja ele um servidor ou sua desktop pessoal. Estes sistemas estão disponíveis em diversos sistemas operacionais. Os DBMS mais populares são: SQLite, MySQL, PostgreSQL, LibreOffice Base (todos eles open source) e Microsoft Access, SQL Server, FileMaker, Oracle (proprietários).

Comandos e instruções do SQL

Uma escola pode manter um banco de dados com informações sobre alunos, professores, funcionários, disciplinas lecionadas, salas de aulas, e a descrição de relacionamentos entre eles. Segue um exemplo simples de uma tabela de em banco de dados contendo o dados (simplificados e fictícios) de alunos. A primeira linha, listada em negrito, contém os nomes das colunas da tabela:

Tabela (1): Alunos
Matricula Nome Sobrenome email Nascimento Fone
734236 João Santos joao@yahoo.com 02-04-1998 61 123455667
789234 George Pereira george@gmail.com 04-04-2000 41 345678987
654987 Paula Torres ptorres@globo.com 25-01-2004 31 987854543
765098 Marcos Melo mamelo@gmail.com 25-10-2004 31 987843231

Nessa tabela Matricula é um campo numérico, Nome, Sobrenome, email e Fone são campos de strings, Nascimento é um campo de datas.

SELECT

A instrução SELECT é usada para recuperar (ler e retornar) dados de uma tabela. Ela tem a seguinte sintaxe geral:

SELECT Coluna1, ..., Colunan FROM Tabela1
SELECT * FROM Tabela1

A primeira linha retorna todos os registros da Tabela1, da Coluna1, …, Colunan, sem qualquer critério de seleção. A segunda retorna todos os campos da Tabela1 (* substitui a lista de todos os campos). A declaração explícita de quais campos se quer usar torna a consulta mais eficiente (rápida).

Por exemplo:

-- Para retornar todos os Nomes e Sobrenomes da tabela
SELECT Nome, Sobrenome FROM Alunos
Tabela (2):
Nome Sobrenome
João Santos
George Pereira
Paula Torres
Marcos Melo

O sinal -- inicia um comentário em SQL, uma parte da instrução que será ignorada. Comandos SQL podem ser em maiúsculas ou minúscula, embora seja costume usar letras maiúsculas.

Cláusula WHERE

A Cláusula WHERE é uma modificação da consulta com SELECT especificando condições de retorno. Ela restringe os dados retornados para apenas aqueles satisfeitos pela cláusula. Por exemplo, supondo que o campo matrícula seja numérico:

SELECT Nome, Sobrenome, email FROM Alunos WHERE Matricula = 654987

retorna

Tabela (3):
Nome Sobrenome email
Paula Torres ptorres@globo.com

Ou

SELECT Matricula, email FROM Alunos WHERE Nome = 'Marcos'

retorna

Tabela (4):
Matricula email
765098 mamelo@gmail.com

Os seguintes operadores de comparação podem ser usados com WHERE: = (igual, usado acima), <> (diferente),
> (maior que), >= (maior ou igual), < (menor que), =< (menor ou igual),
LIKE (similar), BETWEEN (define uma faixa).

SELECT Matricula, Nome, Sobrenome FROM Alunos WHERE Matricula > 740000
Tabela (5):
Matricula Nome Sobrenome
789234 George Pereira
765098 Marcos Melo
SELECT Matricula, Nome, Sobrenome FROM Alunos WHERE Nascimento <> '25-01-2004'
Tabela (6):
Matricula Nome Sobrenome
734236 João Santos
789234 George Pereira

O mesmo procedimento é usado para os demais operadores.

O Operador LIKE pode ser usado junto com %, um wildcard ou coringa que representa qualquer string (um ou mais caracteres). Ele pode ser posto em qualquer lugar, quantas vezes for necessário.

SELECT * FROM Alunos WHERE Nome LIKE 'PA%'
-- Nomes que começam com 'PA'
Tabela (7):
Matricula Nome Sobrenome email Nascimento Fone
654987 Paula Torres ptorres@globo.com 25-01-2004 31 987854543

O Operador BETWEEN possui sintaxe um pouco diferente para cada RDBMS. Em geral é algo do tipo:

SELECT * FROM Alunos WHERE Nascimento BETWEEN '01-01-2002' AND '01-01-2005'
-- Nascidos no intervalo
Tabela (8):
Matricula Nome Sobrenome email Nascimento Fone
654987 Paula Torres ptorres@globo.com 25-01-2004 31 987854543
765098 Marcos Melo mamelo@gmail.com 25-01-2004 31 987843231

O coringa _ representa um único caracter e [] uma faixa de valores. Por exemplo, a consulta seguinte retorna todos os registros onde Fone começa com 3, 4, 5 ou 6 e tem qualquer segundo dígito. No caso de nossa tabela Alunos seriam todos os registros.

SELECT * FROM Alunos WHERE Fone LIKE '[3-6]_%'

SELECT DISTINCT

Se você quiser obter valores únicos de uma tabela, sem repetições, use a cláusula DISTINCT.

SELECT DISTINCT Nascimento FROM Alunos 
Tabela (9):
Nascimento
02-04-1998
04-04-2000
25-01-2004

ORDER BY

A cláusula ORDER BY é usada junto com SELECT para ordenar os resultados de uma consulta. Ela tem a seguinte sintaxe geral:

SELECT campo1, ..., campon FROM Tabela1 ORDER BY (lista de campos)

Por exemplo:

-- Para retornar todos os Nomes e Sobrenomes da tabela, em ordem de Nome
SELECT Nome, Sobrenome FROM Alunos ORDER BY Nome
Tabela (10):
Nome Sobrenome
George Pereira
João Santos
Marcos Melo
Paula Torres

ORDER BY pode ser usada com os modificadores ASC ou DESC, para produzir a lista em ordem crescente ou descendente. ASC é o default e não precisa ser especificado. Para obter a mesma lista anterior em ordem descendente no sobrenome:

-- Para retornar todos os Nomes e Sobrenomes da tabela, em ordem de Nome
SELECT Nome, Sobrenome FROM Alunos ORDER BY Sobrenome DESC
Tabela (11):
Nome Sobrenome
Paula Torres
João Santos
George Pereira
Marcos Melo

TOP

A cláusula TOP é usada junto com SELECT e, geralmente com ORDER BY para selecionar apenas um número fixo de resultados retornados por uma consulta. Ela tem a seguinte sintaxe geral:

SELECT TOP número| % campo1, ..., campon FROM Tabela1 ORDER BY (lista de campos)

Por exemplo:

-- Para retornar os dois últimos Nomes da tabela, em ordem de Nome
SELECT TOP 2 Nome, Sobrenome FROM Alunos ORDER BY Nome DESC
Tabela (12):
Nome Sobrenome
Paula Torres
Marcos Melo

Para ver 10% dos primeiros registros de uma lista podemos usar:

SELECT TOP 10% * FROM Tabela ORDER BY campo

Operadores lógicos AND e OR

Mais de uma condição podem ser anexadas à cláusula WHERE usando os operadores AND e OR.

SELECT * FROM Alunos WHERE Matricula > 700000 AND Fone LIKE '31%'
Tabela (13):
Matricula Nome Sobrenome email Nascimento Fone
765098 Marcos Melo mamelo@gmail.com 25-10-2004 31 987843231
SELECT * FROM Alunos WHERE Matricula > 700000 OR Sobrenome = 'Torres'

Na última consulta todos os registros serial retornados.

Condições mais complexas podem ser expressas usando-se parênteses.

SELECT Matricula, Nome, Sobrenome FROM Alunos
   WHERE (Nome = 'George' OR Nome = 'Paula') AND Sobrenome = 'Pereira'
Tabela (14):
Matricula Nome Sobrenome
789234 George Pereira

Operador lógico IN

O operador IN é usado junto com WHERE para selecionar um campo com valor dentro de um conjunto de valores discretos. A sintaxe é

SELECT campo1, ..., campon
   FROM Tabela
   WHERE campo1 IN (valor1, ..., valorr)
SELECT * FROM Alunos WHERE Matricula IN (654987, 765098)
Tabela (15):
Matricula Nome Sobrenome
654987 Paula Torres
765098 Marcos Melo

SELECT INTO

A instrução SELECT INTO é usada para selecionar registros e campos de uma tabela e copiar o resultado retornado em uma nova tabela.

SELECT Coluna1, ..., Colunan INTO Tabela2 FROM Tabela1	WHERE <condições>

A Tabela2 será criada com os mesmos campos e relacionamentos da tabela inicial. Alguns casos são listados a seguir:

-- Faça uma cópia backup de Alunos
SELECT * INTO AlunosBackup FROM ALunos;

-- Faça uma cópia backup de Alunos cujo nome começa com 'Pa'
SELECT * INTO AlunosBackup FROM ALunos WHERE Nome LIKE 'PA%';

-- Faça uma cópia backup de Alunos em outro banco de dados (BDCopia)
SELECT * INTO AlunosBackup IN 'BDCopia' FROM ALunos;

-- Cria tabela vazia novoAlunos com estrutura idêntica a de Alunos
SELECT * INTO novoAlunos FROM Alunos WHERE 1 = 0;

INSERT INTO

A instrução INSERT INTO é usada para inserir novos registros em uma tabela. Ele pode ser usado em dois formatos:

INSERT INTO Tabela1 VALUES (valor1, ..., valorn)
-- ou
INSERT INTO Tabela1 (campo1, ..., campon)  VALUES (valor1, ..., valorn)

No primeiro caso \(n\), o número de valores inseridos deve ser igual ao número de campos da tabela e devem estar na ordem default. No segundo caso a ordem pode ser alterada mas campon) deve corresponder à valorn. Em ambos os casos o tipo de dado do campo deve ser respeitado. Por exemplo: as seguintes instruções aplicadas sobre a tabela Alunos:

-- Inserindo todos os campos
INSERT INTO Alunos VALUES (854254, 'João', 'Alves', 'jalves@yahoo.com', '15-03-2004', '31 885466112')
-- Inserindo alguns campos
INSERT INTO Alunos (Matricula, Nome, Sobrenome) VALUES (785294, 'Marta', 'Soares')

alteraria a tabela para

Tabela (16):
Matricula Nome Sobrenome email Nascimento Fone
734236 João Santos joao@yahoo.com 02-04-1998 61 123455667
789234 George Pereira george@gmail.com 04-04-2000 41 345678987
654987 Paula Torres ptorres@globo.com 25-01-2004 31 987854543
765098 Marcos Melo mamelo@gmail.com 25-01-2004 31 987843231
854254 João Alves jalves@yahoo.com 15-03-2004 31 885466112
785294 Marta Soares

Os valores de campos não fornecidos na última instrução ficam nulos (null, inexistência de valor) ou assumem um valor default definido na construção da estrutura da tabela.

UPDATE

A instrução UPDATE é usada para alterar registros já inseridos em uma tabela. Ela tem a sintax geral:

UPDATE Tabela1
   SET campo1 = valor1, ..., campon = valorn
   WHERE <condições>

O formato acima mostra que podemos quebrar as linhas de uma instrução SQL para torná-la mais legível. A cláusula WHERE <condições> limita quais os registros serão alterados. Sem ela todos os registros (todas as linhas da tabela) seriam alterados.

Por exemplo, podemos completar o registro relativo à aluna Marta em nossa tabela:

UPDATE Alunos
   SET Sobrenome = 'Alves', email = 'marta123@yahoo.com', Nascimento = '14-03-2001', fone = '21 956855441'
   WHERE Matricula = 785294
-- Para ver o resultado (os demais registros ficam inalterados)
SELECT * FROM Alunos WHERE Matricula = 785294

O resultado seria a tabela:

Tabela (17):
Matricula Nome Sobrenome email Nascimento Fone
785294 Marta Alves marta123@yahoo.com 14-03-2001 21 956855441

Novamente, se não tivéssemos especificado a condição Matricula = 785294 todos os registros, de todos os alunos seriam alterados.

Suponha que, por algum motivo, a escola tenha decido alterar o padrão de numeração das matrículas acrescentando o dígito 1 à esquerda de todas as matrículas. Isso seria o mesmo que somar 1000000 à todas as matrículas. Podemos conseguir isso com a seguinte operação:

UPDATE Alunos SET Matricula = Matricula + 1000000
-- Para ver o resultado (os demais campos ficam inalterados)
SELECT Matricula FROM Alunos
Tabela (18):
Matricula
1734236
1789234
1654987
1765098
1854254
1785294

DELETE

A instrução DELETE permite o apagamento de registros em uma tabela. Ela tem a sintax geral:

DELETE FROM Tabela1 WHERE <condições>

O formato acima mostra que podemos quebrar as linhas de uma instrução SQL para torná-la mais legível. A cláusula WHERE <condição> limita quais os registros serão apagados. Sem ela todos os registros (todas as linhas da tabela) seriam apagadas.

Por exemplo, podemos apagar os registros relativos aos alunos com sobrenome “Alves” de nossa nossa tabela:

DELETE FROM Alunos WHERE Sobrenome = 'Alves'

Dois alunos seriam removidos da tabela que ficaria assim:

Tabela (19):
Matricula Nome Sobrenome email Nascimento Fone
1734236 João Santos joao@yahoo.com 02-04-1998 61 123455667
1789234 George Pereira george@gmail.com 04-04-2000 41 345678987
1654987 Paula Torres ptorres@globo.com 25-01-2004 31 987854543
1765098 Marcos Melo mamelo@gmail.com 25-01-2004 31 987843231

Se não tivéssemos especificado uma condição para o apagamento todos os registros seriam apagados. A linha abaixo apagaria todos os registros da tabela Alunos:

DELETE FROM Alunos

A tabela e sua estrutura continuaria existindo.

Aliases

Aliases (nomes alternativos) são usados para simplificar uma consulta. Nossa tabela de exemplo é uma tabela pequena e simples. Na prática os bancos de dados e tabelas podem conter muitos campos. A possibilidade de renomear tabelas e campos pode ser muito útil, principalmente quando a consulta envolve mais de uma tabela e a consulta se refere às tabelas e campos mais de uma vez.

Por exemplo considerando que nossa tabela está no estado da Tabela (19) a consulta

SELECT Matricula, Nome + ', ' + Sobrenome AS NomeCompleto FROM Alunos

resulta em

Tabela (20):
Matricula NomeCompleto
1734236 João Santos
1789234 George Pereira
1654987 Paula Torres
1765098 Marcos Melo

Aqui foi feita uma concatenação das strings Nome + Sobrenome e o resultado renomeado como NomeCompleto.

Quando usamos várias tabelas de um banco de dados pode ocorrer que mais de uma delas tenha um campo com o mesmo nome. Nesse caso é obrigatória descriminar a que tabela nos referimos. A mesma consulta acima pode ser colocada na seguinte forma, com o mesmo resultado:

SELECT a.Matricula, a.Nome + ', ' + a.Sobrenome AS NomeCompleto FROM Alunos a

Aqui a tabela Alunos ganhou o alias a. a.Matricula se refere ao campo Matricula da tabela Alunos.

Agrupamentos e funções de grupos

Vamos acrescentar novas tabelas para considerar os agrupamentos. Suponha que a escola possui 4 funcionários identificados por um id único (um número de indentificação). Uma tabela armazena a relação entre id e nome (nome do funcionário). Outras tabela contém o número de horas trabalhadas por dia, para cada funcionário.

Tabela (21): Horas_trabalhadas
id dia horas
36 ’01-03-2019′ 6
41 ’01-03-2019′ 8
48 ’01-03-2019′ 2
58 ’01-03-2019′ 8
36 ’02-03-2019′ 5
41 ’02-03-2019′ 8
48 ’02-03-2019′ 1
58 ’02-03-2019′ 4
Tabela (22): Funcionarios
id Nome
36 Mariana Goulart
41 Tânia Ferreira
48 Humberto Torres
58 Francisco Pedroso

Diversas operações são permitidas sobre as linhas de uma tabela. Em particular

Instrução Efeito
GROUP BY Agrupa registros por valores do campo
Função Efeito
COUNT Conta o número de ocorrências do campo
MAX Fornece o valor máximo do campo
MIN Fornece o valor mínimo do campo
AVG Fornece a média dos valores do campo
SUM Fornece a soma dos valores do campo

Por exemplo, para calcular o número de horas trabalhadas por todos os funcionários podemos usar a consulta

SELECT SUM(horas) as soma FROM Horas_trabalhadas

que resulta em um único registro para um único campo:

Tabela (23):
soma
42

Para calcular o número de horas trabalhadas por cada funcionário fazemos a soma das horas com os campos de horas agrupados por cada funcionário.

SELECT id, SUM(horas) as soma
   FROM Horas_trabalhadas
   GROUP BY id
Tabela (24): Horas_trabalhadas
id horas
36 11
41 16
48 3
58 12

A consulta a seguir mostra o cálculo da média de horas trabalhadas por funcionário e de quantos dias cada um trabalhou.

SELECT id, AVG(horas) as media, COUNT(id) as numDias
   FROM Horas_trabalhadas
   GROUP BY id
Tabela (25): Média e número de dias trabalhados
id media numDias
36 5.5 2
41 8 2
48 1.5 2
58 6 2

Cláusula HAVING

A cláusula HAVING é usada para se estabelecer critérios sobre valores obtidos em funções agregadas. No SQL não é permitido usar WHERE para restringir resultados de uma consulta agregada. A consulta seguinte resultaria em erro:

SELECT id, SUM (horas)
   FROM Horas_trabalhadas
   WHERE SUM (horas) > 11   -- Isso geraria um erro
   GROUP BY id

Para esse efeito usamos HAVING, uma forma de se especificar condições sobre o resultado de uma função agregada.

SELECT id, SUM (horas) as soma
   FROM Horas_trabalhadas
   GROUP BY id
   HAVING soma > 11

Essa consulta gera a seguinte tabela, que é uma modificação da Tabela (24), satisfeita a condição soma > 11:

 

Tabela (24): Horas_trabalhadas
id soma
41 16
58 12

Instrução JOIN

É claro que a última tabela ficaria mais fácil de interpretar se, ao invés de conter apenas ids, ela contivesse também os nomes dos funcionários. Essa informação está contida na Tabela (22): Funcionarios. A instrução JOIN serve para ler dados relacionados, gravados em mais de uma tabela. Sua forma geral é:

SELECT tabela1.campo11, tabela1.campo12, tabela2.campo21, tabela2.campo22, ...
   FROM tabela1 INNER JOIN tabela2 ON tabela1.id1 = tabela2.id2

Esse comando seleciona todos os campo11 e campo12 da tabela1, campo21, campo22, … da tabela2, relacionados pela condição tabela1.id1 = tabela2.id2. OS campos id1 e id2 podem ter ou não os mesmos nomes. Usando aliáses essa consulta pode ser deixada mais clara (e isso se torna mais importante para consultas mais longas envolvendos muitos campos e tabelas):

SELECT t1.campo11, t1.campo12, t2.campo21, t2.campo22, ...
   FROM tabela1 t1 INNER JOIN tabela2 t2 ON t1.id1 = t2.id2

Por exemplo, se quisermos uma tabela com os mesmos resultados da tabela (24) mas incluindo nomes dos funcionários fazemos

SELECT ht.id, f.Nome, SUM(horas) as soma
   FROM Horas_trabalhadas ht
   INNER JOIN Funcionarios f ON ht.id = f.id
   GROUP BY ht.id HAVING soma > 11

Com o resultado:

Tabela (25): Horas trabalhadas por funcionário
id Nome soma
41 Tânia Ferreira 16
58 Francisco Pedroso 12

Existem outros tipos de junções ou JOINs no SQL:

  • (INNER) JOIN: Retorna registros com valores correspondentes nas duas tabelas.
  • LEFT (OUTER) JOIN: Retorna registros da tabela esquerda (a primeira na query) e os correspondentes na tabela direita.
  • RIGHT (OUTER) JOIN: Retorna registros da tabela direita e os registros correspondentes da tabela esquerda.
  • FULL (OUTER) JOIN: Retorna registros quando houver correspondência em qualquer uma das tabelas.
Variantes do operador JOIN

Sugestões de Leitura

  • Faroult, Stéphane; Robson, Peter: The Art of SQL, O’Reilly Media, Sebastopol, CA, 2006.
  • Taylor,Allen: SQL For Dummies, 9th Edition John Wiley & Sons, New Jersey, 2019.

Um comentário sobre “Linguagem de Consulta SQL

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *