Sumário 1 Introdução SQL - Perguntas André Restivo Faculdade de Engenharia da Universidade do Porto October 18, 2010 2 3 Operadores de Conjuntos 4 5 Agregações 6 Ordenações e Limites 7 Sub-perguntas 8 Operadores de Texto 9 Outras Considerações André Restivo (FEUP) SQL - Perguntas October 18, 2010 1 / 46 André Restivo (FEUP) SQL - Perguntas October 18, 2010 2 / 46 Modelo Relacional Introdução SELECT + FROM Uma BD relacional é um conjunto de relações. A estrutura de uma relação é definida pelo seu esquema. Uma relação pode ser vista como uma tabela de valores, em que cada coluna representa um atributo da relação e cada linha é um tuplo de valores relacionados. O SELECT e o FROM são as operações base de qualquer pergunta SQL. Permitem-nos seleccionar algumas colunas de uma relação. Podemos também seleccionar todas as colunas de uma relação usando *. SELECT marca, kms FROM autocarro; André Restivo (FEUP) SQL - Perguntas October 18, 2010 3 / 46 André Restivo (FEUP) SQL - Perguntas October 18, 2010 4 / 46
SELECT : SELECT DISTINCT SELECT marca, kms FROM autocarro; marca kms Volvo 5000 Volvo 5000 Renault 12000 Renault 112000 Podemos ainda retirar repetidos usando DISTINCT. SELECT DISTINCT marca, kms FROM autocarro; André Restivo (FEUP) SQL - Perguntas October 18, 2010 5 / 46 André Restivo (FEUP) SQL - Perguntas October 18, 2010 6 / 46 SELECT DISTINCT : WHERE SELECT DISTINCT marca, kms FROM autocarro; marca kms Volvo 5000 Renault 12000 Renault 112000 O comando WHERE permite seleccionar um sub-conjunto de tuplos de uma relação que satisfazem uma determinada condição sobre alguns atributos. A condição pode conter operadores de comparação (<, >, <=, <>,...) e pode ser composta usando AND, OR e NOT. SELECT * FROM autocarro WHERE marca = Volvo OR kms > 100000; SELECT * WHERE salario - descontos > 1000; André Restivo (FEUP) SQL - Perguntas October 18, 2010 7 / 46 André Restivo (FEUP) SQL - Perguntas October 18, 2010 8 / 46
IS NULL WHERE : Se quisermos ficar só com as linhas em que um valor é nulo devemos usar IS NULL. Se quisermos ficar só com as linhas em que um valor não é nulo devemos usar IS NOT NULL. SELECT * FROM autocarro WHERE marca IS NULL; SELECT * FROM autocarro WHERE marca IS NOT NULL; SELECT * FROM autocarro WHERE marca = Volvo OR kms > 100000; André Restivo (FEUP) SQL - Perguntas October 18, 2010 9 / 46 André Restivo (FEUP) SQL - Perguntas October 18, 2010 10 / 46 Renomeação de Colunas e Aritmética Operadores de Conjuntos Reunião, Intersecção e Diferença Podemos ainda renomear atributos. SELECT kms AS quilometros FROM autocarro; Ou efectuar operações aritméticas entre atributos. Neste caso, é recomendado renomear o resultado da operação. SELECT salariobruto - descontos AS salarioliquido ; Duas relações dizem-se compatíveis para a reunião, intersecção ou diferença se tiverem o mesmo número de atributos e o domínio de cada um deles for igual. A reunião entre duas relações Ê ½ e Ê ¾ é a relação que inclui todos os tuplos que estão em Ê ½ ou em Ê ¾. A intersecção entre duas relações Ê ½ e Ê ¾ é a relação que inclui todos os tuplos que estão em Ê ½ e em Ê ¾. A diferença entre duas relações Ê ½ e Ê ¾ é a relação que inclui todos os tuplos que estão em Ê ½ mas não estão em Ê ¾. Os tuplos duplicados são eliminados. A reunião e intersecção são comutativas mas a diferença não. André Restivo (FEUP) SQL - Perguntas October 18, 2010 11 / 46 André Restivo (FEUP) SQL - Perguntas October 18, 2010 12 / 46
Operadores de Conjuntos UNION, INTERSECT e EXCEPT UNION : Operadores de Conjuntos Para efectuar as operações de união, intersecção e diferença, usamos os operadores UNION, INTERSECT e EXCEPT que podem ser colocados entre duas perguntas. Para que o resultado mantenha tuplos repetidos, podemos ainda usar o operador ALL. SELECT * FROM autocarro WHERE marca = Volvo UNION ALL SELECT * FROM autocarro WHERE kms < 10000; SELECT * FROM autocarro1; 12-13-AB Renault PR112 45-38-LH Volvo 8500 FD-91-00 Renault FR1 GTX SELECT * FROM autocarro2; 34-91-FC Volvo 7500 SELECT * FROM autocarro1 UNION SELECT * FROM autocarro2; 12-13-AB Renault PR112 45-38-LH Volvo 8500 FD-91-00 Renault FR1 GTX 34-91-FC Volvo 7500 André Restivo (FEUP) SQL - Perguntas October 18, 2010 13 / 46 André Restivo (FEUP) SQL - Perguntas October 18, 2010 14 / 46 Operadores de Conjuntos INTERSECT : EXCEPT : Operadores de Conjuntos SELECT * FROM autocarro1; 12-13-AB Renault PR112 45-38-LH Volvo 8500 FD-91-00 Renault FR1 GTX SELECT * FROM autocarro2; 34-91-FC Volvo 7500 SELECT * FROM autocarro1 INTERSECT SELECT * FROM autocarro2; SELECT * FROM autocarro1; 12-13-AB Renault PR112 45-38-LH Volvo 8500 FD-91-00 Renault FR1 GTX SELECT * FROM autocarro2; 34-91-FC Volvo 7500 SELECT * FROM autocarro1 EXCEPT SELECT * FROM autocarro2; 12-13-AB Renault PR112 45-38-LH Volvo 8500 FD-91-00 Renault FR1 GTX André Restivo (FEUP) SQL - Perguntas October 18, 2010 15 / 46 André Restivo (FEUP) SQL - Perguntas October 18, 2010 16 / 46
Produto Cartesiano Produto Cartesiano : Permite-nos combinar tuplos de relações diferentes. Basta indicar as várias relações no operador FROM usando vírgulas. Retorna uma relação com os atributos das várias tabelas e todas as combinações possíveis de tuplos. SELECT * FROM autocarro, marca; Se duas tabelas tiverem atributos com o mesmo nome, podemos usar a seguinte notação para desambiguar o atributo pretendido. SELECT empregado.nome, departamento.nome, departamento; André Restivo (FEUP) SQL - Perguntas October 18, 2010 17 / 46 SELECT * FROM autocarro, marca nome pais Volvo Suécia Volvo Suécia Volvo Suécia Volvo Suécia Renault França Renault França Renault França Renault França SELECT * FROM marca; nome pais Volvo Suécia Renault França André Restivo (FEUP) SQL - Perguntas October 18, 2010 18 / 46 usando WHERE Junção usando WHERE : A utilização do produto cartesiano por si só não parece muito interessante. Mas, juntamente com o operador WHERE permite a junção de relações. Este tipo de perguntas permite-nos lidar com as associações entre as relações. SELECT * FROM autocarro, marca WHERE marca = nome; SELECT * FROM marca; nome pais Volvo Suécia Renault França SELECT * FROM autocarro, marca WHERE marca = nome; nome pais Volvo Suécia Volvo Suécia Renault França Renault França André Restivo (FEUP) SQL - Perguntas October 18, 2010 19 / 46 André Restivo (FEUP) SQL - Perguntas October 18, 2010 20 / 46
usando JOIN ON JOIN ON : Em vez de usarmos um produto cartesiano juntamente com uma expressão WHERE para fazer uma junção, podemos usar um comando específico: JOIN ON. Este comando permite especificar simultaneamente as tabelas a juntar e a condição de junção. SELECT * FROM marca; nome pais Volvo Suécia Renault França SELECT * FROM autocarro JOIN marca ON marca = nome; SELECT * FROM autocarro JOIN marca ON marca = nome; pais Suécia Suécia França França André Restivo (FEUP) SQL - Perguntas October 18, 2010 21 / 46 André Restivo (FEUP) SQL - Perguntas October 18, 2010 22 / 46 usando JOIN USING JOIN USING : Se as colunas usadas na junção tiverem o mesmo nome nas duas relações, podemos usar um comando ainda mais simples: JOIN USING. Este comando permite especificar simultaneamente as tabelas a juntar e o nome das colunas de junção. SELECT * FROM marca; marca pais Volvo Suécia Renault França SELECT * FROM autocarro JOIN marca USING (marca); SELECT * FROM autocarro JOIN marca USING(marca); pais Suécia Suécia França França André Restivo (FEUP) SQL - Perguntas October 18, 2010 23 / 46 André Restivo (FEUP) SQL - Perguntas October 18, 2010 24 / 46
usando NATURAL JOIN NATURAL JOIN : Se quisermos fazer uma junção em que os atributos de junção têm todos o mesmo nome nas duas relações, podemos realizar uma junção natural usando o comando NATURAL JOIN. Os atributos repetidos são removidos. Uma junção natural entre duas relações sem atributos comuns equivale a um produto cartesiano porque, após este, não há nenhuma selecção a fazer. SELECT * FROM autocarro NATURAL JOIN marca; SELECT * FROM autocarro NATURAL JOIN marca; pais Suécia Suécia França França SELECT * FROM marca; marca pais Volvo Suécia Renault França André Restivo (FEUP) SQL - Perguntas October 18, 2010 25 / 46 André Restivo (FEUP) SQL - Perguntas October 18, 2010 26 / 46 Renomeação de Tabelas Junção Externa Podemos ainda renomear tabelas. Pode ser útil em casos em que precisamos de aceder à mesma tabela 2 vezes. SELECT empregado.nome, supervisor.nome, empregado AS supervisor WHERE empregado.id_sup = supervisor.id; SELECT empregado.nome, supervisor.nome JOIN empregado AS supervisor ON empregado.id_sup = supervisor.id; Numa junção, os tuplos que não tenham qualquer relação com a outra tabela desaparecem do resultado da pergunta. Uma junção externa inclui esses tuplos deixando as colunas da outra tabela com valor nulo. As junções externas podem ser à esquerda (só os tuplos pendentes da relação da esquerda aparecem no resultado), à direita ou totais (LEFT, RIGHT, FULL). SELECT * FROM autocarro LEFT JOIN marca ON marca = nome; André Restivo (FEUP) SQL - Perguntas October 18, 2010 27 / 46 André Restivo (FEUP) SQL - Perguntas October 18, 2010 28 / 46
Junção Externa : Agregações Agregações SELECT * FROM autocarro FD-91-00 NULL FR1 GTX 112000 2004-03-06 2008-02-22 SELECT * FROM marca FULL NATURAL JOIN autocarro pais Suécia Suécia França FD-91-00 NULL FR1 GTX 112000 2004-03-06 2008-02-22 NULL NULL Scania NULL NULL NULL NULL Suécia SELECT * FROM marca marca pais Volvo Suécia Renault França Scania Suécia André Restivo (FEUP) SQL - Perguntas October 18, 2010 29 / 46 Podemos agregar dados de forma a calcular máximos/mínimos, médias, somas e fazer contagens (MAX/MIN, AVG, SUM e COUNT). Em SQL é obrigatório indicar quais as colunas que estão a ser agregadas usando o operador GROUP BY. Não é obrigatório seleccionar todas as colunas agregadas, mas não se pode seleccionar uma coluna não agregada. O operador HAVING permite fazer uma selecção sobre os resultados agregados. SELECT departamento.nome, AVG(salario) AS media FROM departamento JOIN empregado ON (numdep = num) GROUP BY num, departamento.nome HAVING AVG(salario) > 1800; André Restivo (FEUP) SQL - Perguntas October 18, 2010 30 / 46 Agregação : Agregações Agregação : Agregações SELECT * ; bi nome num departamento salario 1234 João 1 800 2345 Maria 2 900 3456 Carlos 3 1000 4567 Manuel 3 700 5678 Joana 2 400 6789 Marco 2 800 7890 Marta 1 1200 SELECT num, AVG(salario) GROUP BY num num media 1 1000 2 700 3 850 SELECT * ; bi nome num departamento salario 1234 João 1 800 2345 Maria 2 900 3456 Carlos 3 1000 4567 Manuel 3 700 5678 Joana 2 400 6789 Marco 2 800 7890 Marta 1 1200 SELECT num, AVG(salario) GROUP BY num HAVING AVG(salario) > 750 num media 1 1000 3 850 André Restivo (FEUP) SQL - Perguntas October 18, 2010 31 / 46 André Restivo (FEUP) SQL - Perguntas October 18, 2010 32 / 46
Agregação : Contagens Agregações Ordenações Ordenações e Limites O operador de contagem (COUNT), conta o número de valores não nulos no atributo. Um caso especial é o COUNT(*) que conta o número de linhas. SELECT departamento.nome, COUNT(*) AS trabalhadores FROM departamento JOIN empregado ON (numdep = num) GROUP BY num, departamento.nome HAVING COUNT(*) > 2; A resposta a uma pergunta pode ser ordenada segundo uma ou mais colunas. Para proceder à ordenação usa-se o comando ORDER BY seguido das colunas que queremos ordenar. Por omissão as colunas são ordenadas ascendentemente. Podemos mudar a direcção da ordenação usando as partículas ASC e DESC. SELECT nome, salario ORDER BY salario DESC, nome; André Restivo (FEUP) SQL - Perguntas October 18, 2010 33 / 46 André Restivo (FEUP) SQL - Perguntas October 18, 2010 34 / 46 Limites Ordenações e Limites Sub-perguntas Sub-perguntas É possível pedir apenas parte dos resultados de uma pergunta. O comando LIMIT indica quantas linhas queremos no resultado, enquanto o comando OFFSET indica a partir de que linha (começando na linha 0). Desta forma é fácil paginar resultados. SELECT salario ORDER BY salario DESC LIMIT 1 OFFSET 5; É possível usar o resultado de uma query como se fosse uma tabela. Em postgres é obrigatório renomear as subqueries. SELECT nome JOIN (SELECT num FROM departamento WHERE id < 5) AS deps ON (num = id_dep) WHERE salario > 500; André Restivo (FEUP) SQL - Perguntas October 18, 2010 35 / 46 André Restivo (FEUP) SQL - Perguntas October 18, 2010 36 / 46
Operador IN Sub-perguntas Operador ANY/SOME Sub-perguntas O operador IN selecciona as linhas em que os campos indicados antes do operador existam na sub-pergunta. Os campos indicados têm de ser no mesmo número dos campos retornados pela query e têm de ter domínios compatíveis. A partícula NOT permite obter o resultado inverso. SELECT nome WHERE bi NOT IN (SELECT bi_dir FROM departamento) O operador ANY selecciona os resultados cujos campos indicados sejam iguais (=), maiores (>), menores(<) ou diferentes (<>) do que pelo menos uma linha da subquery. Os campos indicados têm de ser no mesmo número dos campos retornados pela sub-pergunta e têm de ter domínios compatíveis. =ANY é o mesmo que IN SOME é o mesmo que ANY SELECT nome WHERE bi =ANY (SELECT bidir FROM departamento) André Restivo (FEUP) SQL - Perguntas October 18, 2010 37 / 46 André Restivo (FEUP) SQL - Perguntas October 18, 2010 38 / 46 Operador ANY/SOME Sub-perguntas Operador LIKE Operadores de Texto O operador ALL selecciona os resultados cujos campos indicados sejam iguais (=), maiores (>), menores(<) ou diferentes(<>) do que todos os tuplos da subquery. Os campos indicados têm de ser no mesmo número dos campos retornados pela query e têm de ter domínios compatíveis. <>ALL é o mesmo que NOT IN SELECT nome WHERE salario >=ALL (SELECT salario JOIN departamento ON (numdep = num)) O operador LIKE permite fazer comparações entre campos de texto usando wildcards. O caractér % significa qualquer número de caractéres. O caractér _ significa 1 qualquer caractér. O operador ILIKE tem a mesma função mas ignora a capitalização dos caractéres. SELECT nome WHERE nome LIKE J% ; André Restivo (FEUP) SQL - Perguntas October 18, 2010 39 / 46 André Restivo (FEUP) SQL - Perguntas October 18, 2010 40 / 46
Ordem de Execução Outras Considerações Outras Considerações s de Perguntas Complexas Podemos pensar na ordem de execução de uma pergunta SQL da seguinte forma: 1 São executadas as sub-perguntas. 2 São executados todos os produtos cartesianos e joins. 3 As tabelas são renomeadas AS. 4 É executado o comando WHERE. 5 É executado o comando GROUP BY. 6 É executado o comando HAVING. 7 São renomeadas as colunas AS. 8 É executado o comando ORDER BY. 9 É executado o comando LIMIT. 10 E só no fim é executado o comando SELECT. Em quantos projectos trabalha cada empregado? Qual a média mais alta dos salários dos departamentos? Qual o departamento com a média de salários mais alta? Que empregados trabalham em todos os projectos? Que empregados trabalham em todos os projectos do seu departamento? Quais os pares de empregados que trabalham nos mesmos projectos? André Restivo (FEUP) SQL - Perguntas October 18, 2010 41 / 46 André Restivo (FEUP) SQL - Perguntas October 18, 2010 42 / 46 Outras Considerações s de Perguntas Complexas Outras Considerações s de Perguntas Complexas Em quantos projectos trabalha cada empregado? SELECT empregado.nome, COUNT(projecto.id) LEFT JOIN trabalha ON empregado.id = trabalha.id_emp LEFT JOIN projecto ON trabalha.id_pro = projecto.id GROUP BY empregado.id, empregado.nome Qual a média mais alta dos salários dos departamentos? SELECT MAX(media) AS maxima_media FROM ( SELECT AVG(salario) AS media GROUP BY id_dep ) AS medias André Restivo (FEUP) SQL - Perguntas October 18, 2010 43 / 46 André Restivo (FEUP) SQL - Perguntas October 18, 2010 44 / 46
Outras Considerações s de Perguntas Complexas Outras Considerações s de Perguntas Complexas Qual o departamento com a média de salários mais alta? SELECT departamento.nome JOIN departamento ON id_dep = departamento.id GROUP BY departamento.id, departamento.nome HAVING AVG(salario) IN ( SELECT MAX(media) FROM ( SELECT AVG(salario) AS media GROUP BY id_dep ) AS medias ) Qual o departamento com a média de salários mais alta? Versão alternativa. SELECT departamento.nome JOIN departamento ON id_dep = departamento.id GROUP BY departamento.id, departamento.nome HAVING AVG(salario) >=ALL ( SELECT AVG(salario) GROUP BY id_dep ) André Restivo (FEUP) SQL - Perguntas October 18, 2010 45 / 46 André Restivo (FEUP) SQL - Perguntas October 18, 2010 46 / 46