Operações Adicionais
Além dos seis operadores básicos, a álgebra relacional é frequentemente estendida com operações adicionais que tornam a escrita de consultas mais prática e expressiva.
Atribuição (\(\leftarrow\))
A operação de atribuição permite nomear subexpressões intermediárias, facilitando a leitura de consultas complexas.
\[x \leftarrow E\]
Atribui à variável temporária \(x\) o resultado da expressão \(E\). A variável pode ser usada nas expressões seguintes como se fosse uma relação, mas não altera o banco de dados.
Para encontrar os professores que são da ESETI ou da ESG, em vez de escrever tudo em uma linha:
\[ESETI \leftarrow \sigma_{id\_escola = 31}(professor)\] \[ESG \leftarrow \sigma_{id\_escola = 11}(professor)\] \[ESETI \cup ESG\]
Isso é equivalente a: \[\sigma_{id\_escola = 31}(professor)\ \cup\ \sigma_{id\_escola = 11}(professor)\]
mas muito mais legível.
Renomeação (\(\rho\))
A operação de renomeação atribui um novo nome a uma relação (ou a seus atributos), o que é necessário, por exemplo, quando se faz o produto cartesiano de uma relação consigo mesma.
\[\rho_x(E)\]
Retorna o resultado da expressão \(E\) sob o nome \(x\).
Forma alternativa com renomeação de atributos:
\[\rho_{x(A_1, A_2, \ldots, A_n)}(E)\]
Retorna o resultado de \(E\) com o nome \(x\) e com os atributos renomeados para \(A_1, A_2, \ldots, A_n\).
Para encontrar pares de professores da mesma escola (autojunção), precisamos de dois “aliases” para professor. Usamos \(p1.id\_prof < p2.id\_prof\) para evitar pares duplicados e auto-pares:
\[P1 \leftarrow \rho_{p1}(professor)\] \[P2 \leftarrow \rho_{p2}(professor)\] \[\Pi_{p1.nome,\ p2.nome,\ p1.id\_escola}(\sigma_{p1.id\_escola = p2.id\_escola\ \wedge\ p1.id\_prof < p2.id\_prof}(P1 \times P2))\]
Usando a tabela professor com 7 tuplas:
| id_prof | nome | id_escola | ch_semanal | salario |
|---|---|---|---|---|
| 21200001 | Eduarda Souza | 21 | 20 | 3200 |
| 21400002 | Felipe Araujo | 21 | 40 | 6400 |
| 31200001 | Gustavo Costa | 31 | 20 | 3300 |
| 31400002 | Helena Carvalho | 31 | 40 | 6700 |
| 31200003 | Igor Melo | 31 | 20 | 3100 |
| 11400001 | Bruno Teixeira | 11 | 40 | 6500 |
| 11400002 | Carla Pinto | 11 | 40 | 6600 |
Resultado:
| p1.nome | p2.nome | id_escola |
|---|---|---|
| Eduarda Souza | Felipe Araujo | 21 |
| Gustavo Costa | Helena Carvalho | 31 |
| Gustavo Costa | Igor Melo | 31 |
| Helena Carvalho | Igor Melo | 31 |
| Bruno Teixeira | Carla Pinto | 11 |
Os pares são únicos e não contêm auto-pares graças à condição \(p1.id\_prof < p2.id\_prof\). A ESETI contribui com 3 pares (3 professores, \(\binom{3}{2} = 3\)), enquanto EEMA e ESG contribuem com 1 par cada.
Funções de Agregação (\(\gamma\))
As funções de agregação operam sobre multiconjuntos de valores de uma coluna e produzem um único valor sumarizado.
Funções disponíveis:
| Função | Descrição |
|---|---|
| \(\text{avg}\) | Média aritmética |
| \(\text{min}\) | Valor mínimo |
| \(\text{max}\) | Valor máximo |
| \(\text{sum}\) | Soma total |
| \(\text{count}\) | Contagem de valores |
A notação geral da operação de agregação é:
\[{}_{G_1, G_2, \ldots, G_n}\ \gamma_{F_1(A_1),\ F_2(A_2),\ \ldots}(r)\]
onde \(G_1, \ldots, G_n\) são os atributos de agrupamento (equivalente ao GROUP BY do SQL) e \(F_i(A_i)\) são as funções de agregação aplicadas aos atributos \(A_i\).
Exemplo 1: Sem Agrupamento
Salário médio de todos os professores:
\[\gamma_{\text{avg}(salario)}(professor)\]
Resultado:
| avg(salario) |
|---|
| 5114.29 |
Exemplo 2: Com Agrupamento
Salário médio por escola (equivalente a GROUP BY id_escola):
\[{}_{id\_escola}\ \gamma_{\text{avg}(salario)}(professor)\]
Resultado:
| id_escola | avg(salario) |
|---|---|
| 21 | 4800.00 |
| 31 | 4366.67 |
| 11 | 6550.00 |
O agrupamento por id_escola faz com que a função avg seja calculada separadamente para cada escola. A ESG (id_escola=11) tem média mais alta pois seus dois professores são de regime de 40h, enquanto a ESETI (id_escola=31) possui três professores — dois de 20h e um de 40h.
Para Praticar
1. Agregação sem grupo. Calcule o valor de \(\gamma_{\text{count}(*)}(prereq)\) e \(\gamma_{\text{count}(*)}(\sigma_{id\_curso = 311}(disciplina))\). O que cada resultado representa?
- \(\gamma_{\text{count}(*)}(prereq)\) = 16 — total de pares de pré-requisito no banco.
- \(\gamma_{\text{count}(*)}(\sigma_{id\_curso = 311}(disciplina))\) = 8 — número de disciplinas do curso ENS.
2. Renomeação necessária. Por que a expressão abaixo é ambígua sem renomeação?
\[\Pi_{nome\_1,\ nome\_2,\ id\_escola}(\sigma_{p1.id\_escola = p2.id\_escola\ \wedge\ p1.id\_prof < p2.id\_prof}(professor \times professor))\]
Quando multiplicamos professor por si mesmo sem renomear, o resultado tem dois atributos chamados nome, dois chamados id_escola, dois chamados id_prof etc. — os nomes ficam ambíguos. A solução é usar renomeação antes: \(\rho_{p1}(professor)\) e \(\rho_{p2}(professor)\), criando atributos qualificados como \(p1.nome\) e \(p2.nome\).
3. HAVING em álgebra. Escreva a expressão de álgebra relacional equivalente a: “escolas com salário médio acima de 5.000”. Use a notação com \(\gamma\) e \(\sigma\).
\[\sigma_{\text{avg\_sal} > 5000}\!\left({}_{id\_escola}\ \gamma_{\text{avg}(salario)\ \text{as}\ \text{avg\_sal}}(professor)\right)\]
O \(\sigma\) externo filtra os grupos produzidos pelo \(\gamma\) — é exatamente o que o SQL faz com HAVING. Apenas ESG (id_escola = 11, média = 6.550) satisfaz a condição.