Escreva qual é a relação dos comandos SQL com as expressões da álgebra relacional. Liste todos os outros comandos que não têm correspondência com a álgebra relacional e qual é o objetivo de cada operação.
QL foi fortemente influenciada pelos trabalhos de Codd sobre Álgebra Relacional (AR) e Cálculo Relacional de Tuplas (CRT). Embora elas sejam equivalentes no que diz respeito ao poder de expressar consultas, SQL é mais poderosa devido principalmente aos seus recursos de contagem, ordenação (cláusula order by ) e agrupamento (cláusula group by ). A AR e o CRT podem ambas serem vistas como formas compactas de expressar consultas em SQL. O domínio de uma delas pode ser de grande ajuda no raciocínio lógico por trás das soluções de consultas complexas. É o que faremos através de alguns exemplos da AR vistos em aula.
É importante ressaltar, no entanto, uma diferença conceitual importante entre a AR e SQL: SQL não trata tabelas como conjuntos matemáticos, permitindo a ocorrência de linhas duplicadas. Uma forma de evitar isto é sempre especificar a chave primária ao criar uma tabela. Infelizmente isto não é suficiente, pois tabelas intermediárias produzidas ao se executar um comando SQL podem conter linhas duplicadas se certos cuidados não forem tomados: o exemplo mais simples desse efeito é a operação de projeção (Π) que elimina duplicatas na AR mas a sua tradução natural para SQL não o faz, sendo necessário colocar o qualificado distinct na cláusula select, como veremos nos exemplos. A seguir, como operações da AR são traduzidas para SQL:
Projeção: expressa em SQL na cláusula select do comando select
Exemplo: "Para cada funcionário apresente o seu número e os nomes dos seus dependentes"
AR: Π numf, nomed Dependentes SQL: select numf,nomed from Dependntes Obs: não há repetição porque por convenção, o par numf, nomed é Chave Primária de Dependentes
"Dê uma lista dos funcionários que possuem dependentes"
Π numf Dependentes select numf from Dependentes problema: o funcionário 02 aparecerá duas vezes! É preciso incluir: select distinct numf from Dependentes
Seleção (operador σ): expressa em SQL na clausula where através da comparação do valor de uma coluna da tabela especificada na cláusula from com uma constante:
Exemplo: "Para cada funcionário que possui filhas, obtenha o seu número, o nome e parentesco dos dependentes.
Π numf, nomed, par σ(par='filha')Dependentes select numf, nomed, par from Funcionarios where par= 'filha'
Interseção e diferença: em SQL temos os operadores intersect, except e union (interseção, diferença e união); podemos também expressar a interseção através do operador in seguido de subconsulta e a diferença através do operador not in seguido de subconsulta.
"Dê uma lista das pessoas que são pais e cujos pais aparecem na tabela D(p,f) "
Πp(D) ∩ Πf(D) select p from D intersect select f from D ou select distinct p from D where p in (select f from D)
"Dê uma lista das pessoas que não têm filhos".
Πf(D) - Πp(D) select f from D except select p from D ou, select distinct f from D where f not in (select p frm D)
Produto cartesiano e renomeação de duas ou mais tabelas: expresso em SQL na cláusula from colocando os nomes das tabelas envolvidas separados por ",":
Exemplos: select ... from Funcionarios, Dependentes ou, select .... from D as D1, D as D2, D as D3
Observe também nesse exemplo os operadores de renomeação (alias na terminologia do SQL): as D1, as D2, etc. Usualmente o produto cartesiano será utilizado junto com uma seleção, conforme veremos.
Junção θ e junção natural:
Lembrando que a junção θ e a junção natural (mais precisamente junção de igualdade) são um subconjunto do produto cartesiano, obtido através de uma operação de seleção envolvendo comparação entre colunas, elas podem ser expressas através de uma expressão de comparação na cláusula where envolvendo as colunas escolhidas. Exemplos:
junção natural: "para cada funcionário que possui dependentes apresente o seu nome, os nomes e parentesco dos dependentes":
Πnomef, nomed, par Funcionarios |X| Dependentes ou, Πnomef, nomed, par &sigma(Funcionários.numf=Dependentes.numf)(Funcionarios x Dependentes) select nomef, nomed, par from Funcionarios, Dependentes where Funcionarios.numf = Dependentes.numf
Outro exemplo: tabela de "pais e filhos", D(p,f):
"Obtenha pares de pessoas a1, n1, onde a1 é avô de n1"
ΠD1.p,D2.f D1 |X D1.f=D2.p| D2 ou, usando a definição de junção (preferível): ΠD1.p,D2.f σ(D1.f=D2.p)(D1 x D2) (Obs: aqui há uma renomeação implícita - qual é ela?) SQL: select D1.p, D2.f from D as D1, D as D2 where D1.f= D2.p
Exemplo de junção theta: "obtenha pares de pessoas sem repetição da tabela "Pais e Filhos", D( p, f), que são ou foram cônjuges, isto é, possuem um ou mais filhos em comum"
ρD1(p1,f1) D, ρD2(p2,f2) D Πp1,p2(σp1 < p2 (D1 |Xf1=f2| D2)) ou, Πp1,p2 (σ(p1 < p2 and f1=f2 (D1 x D2)) select distinct D1.p, D2.p from D as D1, D as D2 where D1.f = D2.f and D1.p < D2.p
Exercícios:
(i) Por que distinct é necessário nesta solução e não na do problema anterior?
Re-escreva as expressões da AR acima com a seguinte renomeação, que deixa a expressão em AR mais próxima da sua tradução para SQL: ρD1 D e ρD2 D
Exercícios complementares:
(i) "Para cada funcionário apresente o seu numero e, em ordem decrescente, o número de seus descendentes".
(ii) "Qual o funcionário que possui o maior número de dependentes?"
(iii) "Para cada funcionário apresente o seu nome e, em ordem decrescente, o número de seus descendentes".
Obs AR : não é possivel expressar: a AR não dispõe de recursos de contagem, ordenação e agrupamento.
SQL: relativamente simples usando os recursos de ordenação (order by), contagem ( count()) e de agrupamento (group by). Tente!
Para finalizar vamos resolver a consulta clássica do Modelo Relacional:
(**)"Obtenha uma lista dos fornecedores que fornecem todos os materiais"
F - Πf(F x M - FM) (p. 72 do livro texto) SQL: select f from F except (select f from (select f,m from F,M except select f, m from FM) as Temp) Obs: Postgres requer a nomeação as XXX
Obs: (i) A consulta em SQL é uma tradução literal da expressão da AR cujo significado foi detalhado no livro-texto. Ela seria quase ininteligível sem a explicação formulada via AR, ou seja, a AR é uma ferramenta poderosa para desenvolver o raciocínio lógico requerido para expressar consultas complexas em SQL.
(ii) a operação except (diferença) assim como a união elimina duplicatas mas não a projeção. Se usássemos not in para expressar o primeiro except, as duas primeiras linhas acima ficariam assim:
select distinct f from F where f not in
A consulta clássica para a BD Torneios de Tênis:
Suponha que tenhamos criado uma tabela TGslam contendo apenas a lista dos torneios do Grand Slam:
create table TGslam as (select * from Lista_torneios where cat= 'GS') e agora queremos encontrar: (i) "quais jogadores não venceram algum torneio do Grand Slam?" select distinct numj from jogadores, TGslam -- todas as combinações possiveis (numj,numt), where (numj, numt) not in -- que não se encontram na tabela torneios (select numj,numt from torneios) -- nos dão pares (numj,numt) satisfazendo a consulta e, finalmente, (ii) "Quais jogadores venceram todos os torneios do Grand Slam?" select numj from jogadores where numj not in (select distinct numj from jogadores, TGslam where (numj,numt) not in (select numj,numt from torneios)) O resultado dessa consulta dos dá o jogador 29 - André Agassi, o único a ganhar os 4 torneios do Grand Slam desde 1970 até 2009 quando Roger Federer ganhou o torneio que lhe faltava, Roland Garros (em 1969 Rod Laver, australiano, ganhou os 4 torneios no mesmo ano, fato inédito até hoje). Exercício: modifique de forma trivial a consulta acima de forma a exibir o nome do jogador. Solução usando os recursos de contagem e de agrupamento do SQL: select numj, count(distinct numt) from torneios group by numj having count(distinct numt)= (select count(*) from TGslam) Obs: sem o qualificador distinct na cláusula having a consulta daria resultado incorreto e se omitido na cláusula select daria o número total de torneios de Grand Slam vencidos pelo jogador. Uma modificação simples dessa consulta nos permite responder à seguinte: "Para cada jogador que ganhou torneios do Grand Slam, exiba em ordem decrescente o número de torneios que ganhou e o número do jogador": select count(numt), numj from torneios where numt in (select numt from TGslam) group by numj order by count(numt) desc
Para escrever sua resposta aqui, entre ou crie uma conta
Compartilhar