Capítulo 4: SQL Database System Concepts Estrutura básica Operações com conjuntos Funções de agregação Valores nulos Junções Subconsultas embebidas Relações derivadas Vistas Modificação da Base de Dados Embedded SQL Linguagem de Definição de Dados 4.2.1 ©Silberschatz, Korth and Sudarshan (modificado) Funções Analíticas O SGBD Oracle9i possui um conjunto de funções chamadas analíticas que permite o tratamento estatístico de “armazéns de dados” (Data Wharehouses). São funções de agregação que calculam valores baseados num grupo de linhas. Distinguem-se das funções de agregação pelo facto de retornarem mais do que uma linha por grupo. A maioria permite a definição de janelas de avaliação a partir da linha corrente. Aplicam-se depois das funções de agregação, só podendo aparecer na lista da cláusula select ou na cláusula order by. Database System Concepts 4.2.2 ©Silberschatz, Korth and Sudarshan (modificado) Exemplo SELECT manager_id, last_name, hire_date, salary, AVG(salary) OVER (PARTITION BY manager_id ORDER BY hire_date ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS c_mavg FROM employees; Database System Concepts 4.2.3 ©Silberschatz, Korth and Sudarshan (modificado) Valores Nulos Os tuplos podem conter valores nulos, denotado por null, nalguns dos seus atributos. null significa um valor desconhecido ou que não existe. O predicado is null pode ser utilizado para testar a existência de valores nulos. E.g. mostrar todos os números de empréstimos com um valor nulo na coluna amount. select loan_number from loan where amount is null O resultado de uma expressão aritmética com null é null E.g. 5 + null returns null Contudo, as funções de agregação ignoram os nulos A seguir será analisado este assunto mais detalhadamente Database System Concepts 4.2.4 ©Silberschatz, Korth and Sudarshan (modificado) Valores Nulos e Lógica Trivalente Qualquer comparação com null retorna unknown E.g. 5 < null ou null <> null ou null = null Lógica trivalente usando o valor lógico unknown: OR: (unknown or true) = true, (unknown or false) = unknown (unknown or unknown) = unknown AND: (true and unknown) = unknown, (false and unknown) = false, (unknown and unknown) = unknown NOT: (not unknown) = unknown “P is unknown” é verdade se o valor de P é unknown Resultado da condição da cláusula where é tratado como false quando o seu valor é unknown Database System Concepts 4.2.5 ©Silberschatz, Korth and Sudarshan (modificado) Valores Nulos e Agregados Calcule o total de todos os montantes dos empréstimos select sum (amount) from loan A instrução acima ignora montantes nulos Resultado é null se não existir nenhum montante não-nulo Todas as funções de agregação excepto count(*) ignoram tuplos com valores nulos nos atributos agregados. Database System Concepts 4.2.6 ©Silberschatz, Korth and Sudarshan (modificado) Operações de Junção As operações de junção retornam uma relação como resultado da combinação de duas outras relações. Estas operações adicionais são utilizadas habitualmente em subconsultas na cláusula from Condição de junção – define quais os tuplos que são combinados nas duas relações, assim como quais os atributos que aparecem no resultado da junção. Tipo de junção – define como tratar os tuplos que não estão relacionados entre si (basedados na condição de junção). Tipos de Junção Condições de Junção inner join left outer join right outer join full outer join natural on <predicate> using (A1, A2, ..., An) Database System Concepts 4.2.7 ©Silberschatz, Korth and Sudarshan (modificado) Relações de Exemplo Relação loan loan_number branch_name amount L-170 Downtown 3000 L-230 Redwood 4000 L-260 Perryridge 1700 Relação borrower customer_name Database System Concepts loan_number Jones L-170 Smith L-230 Hayes L-155 4.2.8 ©Silberschatz, Korth and Sudarshan (modificado) Exemplos loan inner join borrower on loan.loan_number = borrower.loan_number loan_number branch_name amount customer_name loan_number L-170 Downtown 3000 Jones L-170 L-230 Redwood 4000 Smith L-230 loan left inner join borrower on loan.loan_number = borrower.loan_number loan_number branch_name amount customer_name loan_number L-170 Downtown 3000 Jones L-170 L-230 Redwood 4000 Smith L-230 L-260 Perryridge 1700 null Database System Concepts 4.2.9 null ©Silberschatz, Korth and Sudarshan (modificado) Exemplos loan natural inner join borrower loan_number branch_name amount customer_name L-170 Downtown 3000 Jones L-230 Redwood 4000 Smith loan natural right outer join borrower loan_number Database System Concepts branch_name amount customer_name L-170 Downtown 3000 Jones L-230 Redwood 4000 Smith L-155 null null Hayes 4.2.10 ©Silberschatz, Korth and Sudarshan (modificado) Exemplos loan full outer join borrower using (loan_number) loan_number branch_name amount customer_name L-170 Downtown 3000 Jones L-230 Redwood 4000 Smith L-260 Perryridge 1700 null L-155 null null Hayes Listar todos os clientes que têm uma conta ou um empréstimo no banco (mas não ambos!) select customer_name from depositor natural full outer join borrower where account_number is null or loan_number is null Database System Concepts 4.2.11 ©Silberschatz, Korth and Sudarshan (modificado) Subconsultas imbricadas SQL disponibiliza um mecanismo para imbricar consultas umas dentro de outras. Uma subconsulta é uma expressão select-from-where que se encontra dentro de uma outra (sub)consulta. As subconsultas são utilizadas habitualmente para efectuar testes de pertença a conjuntos, comparações entre conjuntos e calcular a cardinalidade de conjuntos. Database System Concepts 4.2.12 ©Silberschatz, Korth and Sudarshan (modificado) Consulta de exemplo Listar todos os clientes que têm contas e empréstimos no banco. select distinct customer_name from borrower where customer_name in (select customer_name from depositor) Encontrar todos os clientes que têm empréstimos mas não possuem contas no banco select distinct customer_name from borrower where customer_name not in (select customer_name from depositor) Database System Concepts 4.2.13 ©Silberschatz, Korth and Sudarshan (modificado) Consulta de exemplo Listar todos os clientes que têm uma conta e empréstimos na agência de Perryride select distinct customer_name from borrower natural inner join loan where branch_name = “Perryridge” and (branch_name, customer_name) in (select branch_name, customer_name from depositor, natural inner join account) Nota: A consulta acima pode ser escrita de uma maneira muito mais simples. A formulação utilizada serve apenas para ilustrar as possibilidades da linguagem SQL. Database System Concepts 4.2.14 ©Silberschatz, Korth and Sudarshan (modificado) Comparação de conjuntos Apresentar todas as agências que têm activos superiores aos de alguma agência localizada em Brooklyn. select distinct T.branch_name from branch as T, branch as S where T.assets > S.assets and S.branch_city = ‘Brooklyn’ A mesma consulta recorrendo à cláusula > some select branch_name from branch where assets > some (select assets from branch where branch_city = ‘Brooklyn’) Database System Concepts 4.2.15 ©Silberschatz, Korth and Sudarshan (modificado) Definição da cláusula Some F <comp> some r t r : (F <comp> t) em que <comp> pode ser : (5< some 0 5 6 ) = true (ler: 5 menor que algum tuplo na relação ) (5< some 0 5 ) = false (5 = some 0 5 ) = true 0 (5 some 5 ) = true (pois 0 5) (= some) in No entanto, ( some) not in Database System Concepts 4.2.16 ©Silberschatz, Korth and Sudarshan (modificado) Cláusula all Listar os nomes das agências com activos superiores aos de todas as agências localizadas em Brooklyn. select branch_name from branch where assets > all (select assets from branch where branch_city = ‘Brooklyn’) Database System Concepts 4.2.17 ©Silberschatz, Korth and Sudarshan (modificado) Definição da cláusula all F <comp> all r t r : (F <comp> t) (5< all 0 5 6 ) = false (5< all 6 10 ) = true (5 = all 4 5 ) = false 4 (5 all 6 ) = true (dado que 5 4 e 5 6) ( all) not in Contudo, (= all) in Database System Concepts 4.2.18 ©Silberschatz, Korth and Sudarshan (modificado) Teste de Relações Vazias A construção exists devolve o valor true se a subconsulta é não vazia. exists r r Ø not exists r r = Ø Database System Concepts 4.2.19 ©Silberschatz, Korth and Sudarshan (modificado) Consulta de exemplo Listar todos os clientes que têm uma conta em todas as agências de Brooklyn. select distinct S.customer_name from depositor as S where not exists ( (select branch_name from branch where branch_city = ‘Brooklyn’) except (select R.branch_name from depositor as T natural inner join account as R where S.customer_name = T.customer_name) ) Notas: Repare que X – Y = Ø X Y Não se pode escrever esta consulta com combinações de = all ou de suas variantes. Em álgebra relacional esta consulta escrever-se-ia com uma divisão. Database System Concepts 4.2.20 ©Silberschatz, Korth and Sudarshan (modificado) Cláusula contains Listar todos os clientes que têm uma conta em todas as agências de Brooklyn. select distinct S.customer_name from depositor as S where (select branch_name from branch where branch_city = ‘Brooklyn’) contains (select R.branch_name from depositor as T natural inner join account as R where S.customer_name = T.customer_name) Nota: Não existe no Oracle9i, o que não é grave pois: X Y X – Y = Ø Database System Concepts 4.2.21 ©Silberschatz, Korth and Sudarshan (modificado) Testar ausência de tuplos duplicados A construção unique verifica se o resultado de uma subconsulta possui tuplos duplicados. Encontrar todos os clientes que têm só uma conta na agência de Perryridge. select T.customer_name from depositor as T where unique ( select R.customer_name from account natural inner join depositor as R where T.customer_name = R.customer_name and account.branch_name = ‘Perryridge’) Esta construção não está disponível no Oracle9i Database System Concepts 4.2.22 ©Silberschatz, Korth and Sudarshan (modificado) Consulta de exemplo Listar todos os clientes que têm pelo menos duas contas na agência de Perryridge. select distinct T.customer_name from depositor T where not unique ( select R.customer_name from account natural inner join depositor as R where T.customer_name = R.customer_name and account.branch_name = ‘Perryridge’) Database System Concepts 4.2.23 ©Silberschatz, Korth and Sudarshan (modificado) Vistas Mecanismo que permite ocultar (esconder) informação a certos utilizadores. Para criar uma vista utilizamos o comando: create view v as <query expression> em que: <query expression> é qualquer expressão válida O nome da vista é v Em SQL do Oracle pode-se escrever create or replace view v as <query expression> para criar ou substituir uma vista já existente, evitando a utilização do comando drop view. Database System Concepts 4.2.24 ©Silberschatz, Korth and Sudarshan (modificado) Consultas de exemplo Uma vista contendo todas as agências e respectivos clientes create view all_customer as (select branch_name, customer_name from depositor natural inner join account) union (select branch_name, customer_name from borrower natural inner join loan) Listar todos os clientes da agência de Perryridge select customer_name from all_customer where branch_name = ‘Perryridge’ Database System Concepts 4.2.25 ©Silberschatz, Korth and Sudarshan (modificado) Relações Derivadas Determinar o saldo médio das contas em agências cujo saldo médio é superior a $1200. select branch_name, avg_balance from (select branch_name, avg (balance) as avg_balance from account group by branch_name ) where avg_balance > 1200 Repare que neste caso não foi necessário recorrer à cláusula having, dado que é calculada a relação temporária result na cláusula from, e assim os atributos de result pode ser utilizado directamente numa cláusula where. Database System Concepts 4.2.26 ©Silberschatz, Korth and Sudarshan (modificado) Cláusula With A cláusula with permite a definição local de vistas relativas a uma consulta, em vez de globalmente. Análogo a procedimentos de uma linguagem de programação. Encontrar as contas de maior saldo with max_balance(value) as ( select max (balance) from account ) select account_number from account, max_balance where account.balance = max_balance.value Database System Concepts 4.2.27 ©Silberschatz, Korth and Sudarshan (modificado) Consulta complexa com with Listar todas as agências cuja soma de saldos das suas contas é superior à media da soma dos saldos de todas as agências. with branch_total (branch_name, value) as ( select branch_name, sum (balance) from account group by branch_name) with branch_total_avg(value) as ( select avg (value) from branch_total ) select branch_name from branch_total, branch_total_avg where branch_total.value >= branch_total_avg.value Database System Concepts 4.2.28 ©Silberschatz, Korth and Sudarshan (modificado)