Professional Documents
Culture Documents
2010
BANCO DE DADOS
Aplicação da Structure Query Language
Este e-book visa, através de exemplos práticos, aplicar os conceitos da
Structure Query Language (SQL) na manipulação de Banco de Dados
relacionais.
PARTES 1 AO 7
Ricardo R. Barcelar
http://www.ricardobarcelar.com.br
ricardobarcelar@email.com.br
APRESENTAÇÃO
APRESENTAÇÃO
Ricardo R. Barcelar
PROJETO FÍSICO DE BANCO DE DADOS
1
Parte
primeira etapa a fazer ao começa a trabalhar com banco de dados é estudar as técnicas
3
PROJETO FÍSICO DE BANCO DE DADOS
4
PROJETO FÍSICO DE BANCO DE DADOS
5
PROJETO FÍSICO DE BANCO DE DADOS
6
PROJETO FÍSICO DE BANCO DE DADOS
7
PROJETO FÍSICO DE BANCO DE DADOS
8
PROJETO FÍSICO DE BANCO DE DADOS
Sintaxe: Exemplo:
CREATE TABLE nome_da_tabela CREATE departamento
(coluna1 tipo_de_dado constraint, (dep_id INTEGER NOT NULL,
coluna2 tipo_de_dado constraint, dep_nome VARCHAR(100),
coluna3 tipo_de_dado constraint dep_atividade VARCHAR(100),
empr_id INTEGER NOT NULL);
9
PROJETO FÍSICO DE BANCO DE DADOS
Exemplo1:
...
FOREING KEY nome_chave (coluna)
REFERENCES (tabela)
ON UPDATE ação
ON DELETE ação
Ação: Determina qual ação o banco de dados deve tomar quando for excluída ou alterada uma
linha da tabela que contém referência a esta chave. Pode ser:
- SET NULL: Altera o conteúdo da coluna para nulo, perdendo a referência, sem deixar
valores inconsistentes.
- SET DEFAULT: Altera o conteúdo da coluna pra um valor especificado na cláusula
DEFAULT, se houver.
- CASCATE: Exclui ou altera todos os registros que se relacionam com a ele.
- NO ACTION: Em caso de alteração, não modifica os valores que se relacionam a eles.
- RESTRICT: Não permite a exclusão da PK.
Exemplo2:
Exemplo:
...
prod_quantidade INTEGER DEFAULT 1,
...
d) NOT NULL: Indica que o conteúdo de uma coluna não poderá ser Nulo. Lembre-se,
em banco de dados SQL, colunas sem valor atribuído possuem conteúdo Nulo.
10
PROJETO FÍSICO DE BANCO DE DADOS
Exemplo:
...
cliente_nome VARCHAR(50) NOT NULL,
...
e) UNIQUE: Indica que não pode haver repetição no conteúdo da coluna. Não é a
mesma coisa que chave primária. A chave primária, além de não permitir repetição, não pode
conter valores nulos, dentre outras característica não existentes nesta restrição.
Exemplo:
...
cliente_CPF NUMERIC(11) UNIQUE,
...
11
PROJETO FÍSICO DE BANCO DE DADOS
Sintaxe: Exemplo:
ALTER TABLE nome_da_tabela ALTER TABLE departamento
ADD (constraint) ADD PRIMARY KEY (dep_id)
12
PROJETO FÍSICO DE BANCO DE DADOS
Sintaxe: Exemplo:
DROP TABLE nome_da_tabela DROP TABLE departamento
5. EXERCÍCIOS
Usando a Linguagem SQL crie o Schema de banco de dados para o seguinte modelo lógico:
13
ÍNDICE
2
Parte
íNDICE
uando criamos a estrutura de um banco de dados temos que usar artifícios que
Exemplo:
Temos uma tabela de pessoas e normalmente queremos fazer buscas em ordem
alfabética. O nome, não é uma boa chave primária para a tabela por ser alfanumérica, o que
deixa as pesquisas mais lentas e também pela repetição de nomes. Dessa forma, cria-se um
índice para o nome da pessoa. Assim, garante-se um acesso mais rápido aos nomes, visto que
os dados buscados estariam fora de seqüência.
Os valores indexados são armazenados em um objeto do banco de dados em ordem, o
que permite ao Sistema Gerenciador de Banco de Dados pesquisar primeiro no índice, para
depois buscar na tabela. É importante ressaltar que alguns bancos de dados necessitam de
índices constantemente atualizados, pois eventualmente estes perdem a referência ao dado.
O índice quando criado com critérios bem definidos traz uma enorme vantagem, mas
por outro lado pode trazer enormes problemas, visto que todo trabalho de um Sistema
Gerenciador de Banco de Dados envolve um custo. Não é conveniente sair criando índices
para cada um dos campos da tabela sem que haja uma razão para isto.
Quando um índice é criado uma das tarefas do Sistema Gerenciador de Banco de
Dados é mantê-lo atualizado a cada nova inclusão, exclusão e alteração nos dados. Além do
14
ÍNDICE
mais, o índice também ocupa espaço no banco de dados, pois é criado um novo objeto que
manterá informações indexadas e armazenará a referência à linha física da tabela.
NOTA:
Se são criados muitos índices, pode-se prejudicar o desempenho do banco de dados
Se são criados poucos índices, pode-se prejudicar o desempenho da aplicação.
NOTA:
Sempre que uma consulta estiver muito lenta, verifique a possibilidade de criar índice
para facilitar a busca.
Sintaxe: Exemplo:
Sintaxe: Exemplo:
Não é possível modificar índices. Para alterar um índice, elimine-o e, depois, recrie-o.
NOTA:
Ao eliminar uma tabela, os índices e as constraints são eliminados automaticamente.
15
ÍNDICE
16
ÍNDICE
A maioria dos bancos de dados está armazenada sob maneira permanente (ou
persistente) sob a forma de armazenamento secundário.
Geralmente, o Sistema Gerenciador de Banco de Dados possui diversas opções
disponíveis para organizar os dados, e o processo relativo ao projeto de banco de dados físico
envolve escolher entre as opções, as técnicas de organização de dados.
Os dados armazenados em disco são organizados na forma de arquivos de registros.
Cada qual é uma coleção de valores de dados que podem ser interpretados como fatos sobre
entidades, seus atributos e seus relacionamentos.
Para acessar uma informação no banco de dados considera-se o tipo de requisição e a
estrutura utilizada para organização e acesso às chamadas páginas de dados.
- Arquivos Heap ou pile (aglomerado): Melhor opção quando o acesso típico é uma
busca seqüencial, sem ordem, recuperando todos os registros. Os registros são posicionados
no arquivo pela ordem na qual foram incluídos. São utilizados pelos índices secundários e
utilizados para coletar e armazenar registros de dados para utilização futura.
Exemplo: um simples arquivo de registros de dados.
- Arquivos Hashed: Melhor para seleções de igualdade. Uma função hash é aplicada
ao valor do campo de um registro e retorna o endereço do bloco do disco no qual o registro
está armazenado. Para a maioria dos registros, precisamos somente do acesso a um único
bloco para recuperar aquele registro. Não é adequado para acesso seqüencial ordenado.
1.3 INDEXAÇÃO
Como visto, os índices são estrutura de dados que recebem como entrada uma
propriedade de registro (por exemplo, um valor de um ou mais campos) e os encontra com
essa propriedade rapidamente. Um índice permite localizar um registro sem ter que examinar
mais que uma pequena fração dos registros possíveis. Assim sendo, podemos concluir que os
campos cujos valores o índice se baseia formam a chave de pesquisa.
NOTA
Índices são estruturas de dados auxiliares cujo único propósito é tornar mais rápido o
acesso a registros baseado em certos campos, chamados campos de indexação.
17
ÍNDICE
18
ÍNDICE
Ponteiros
Figura 5 - Índice esparso sobre um arquivo de dados seqüenciais
É o índice associado a uma chave primária. Nada mais é do que um arquivo ordenado,
cujos registros são de tamanho fixo com dois tampos. O primeiro, do mesmo tipo do campo
chave de ordenação (chave primária) e o segundo é um ponteiro para um bloco do disco ou
arquivo de dados.
Utiliza índice esparço.
19
ÍNDICE
20
ÍNDICE
21
ÍNDICE
É possível que mais de um registro tenha o valor da chave. Isso ocorre, por exemplo,
quando a chave de pesquisa não é a chave primária;
Um índice secundário é um índice denso, normalmente com duplicatas. O índice
consiste em pares de chaves-ponteiro. Neste caso, sempre que são permitidas chaves de
pesquisas duplicadas.
Segue-se o ponteiro da entrada. Se for encontrado pelo menos um registro com a chave
de pesquisa K, então a busca continua em blocos adicionais, até encontrar todos os registros
com a chave de pesquisa K.
22
ÍNDICE
Usa o índice esparso indicando a nova chave de pesquisa mais baixa em cada bloco.
ORGANIZANDO AS IDÉIAS:
Denso ou
Tipo de Índice Número de Entradas
Esparço
Primário Nº de blocos no arq. de dados Esparço
Nº de valores distintos do campo de Esparço
Agrupamento
indexação
Secundário (chave) Nº de reg. no arq. de dados Denso
Secundário (não Nº de reg. no arq. de dados Denso
chave) Nº de valores distintos de indexação Esparço
Uma pesquisa binária é aplicada ao índice para localizar ponteiros para um bloco do
disco ou para um registro no arquivo que possui um valor de campo índice específico.
Se o arquivo de índices se torna muito grande para ser armazenado em bloco de disco,
é interessante indexá-lo em mais de um nível.A vantagem é que um índice pequeno pode ser
mantido em memória e o tempo de busca é mais baixo; por outro lado, muitos níveis de índices
podem aumentar a complexidade do sistema, sendo mais recomendado a utilização de outra
estrutura como a que veremos mais a frente: árvore-B.
23
ÍNDICE
NOTA
Um índice multinível é um “índice de índice”.
- Primeiro nível: arquivo ordenado pela chave de indexação, valores distintos, entradas
de tamanho fixo.
- Demais níveis: índice primário sobre o índice do nível anterior e assim
sucessivamente até que no último nível o índice ocupe apenas um bloco.
- Número de acessos a bloco: um a cada nível de índice, mais um ao bloco do arquivo
de dados.
A figura acima exemplifica um índice primário de dois níveis que se parece com a
organização ISAM (Indexed Sequential Acess Method - Método de Acesso Seqüencial
Indexado).
O problema dos índices multiníveis são arquivos fisicamente ordenados, portanto,
ineficientes na inserção e remoção. Para solucionar este problema podem-se adotar as
seguintes soluções:
- Deixar algum espaço em cada um dos blocos para inserção de novas entradas.
- Estruturas de dados: Árvores B e suas variações.
Os arquivos seqüenciais apresentam problemas com o tempo, visto que um bloco não é
mais suficiente para armazenar o conteúdo que era antes armazenado. Para contornar esse
problema é possível adotar as seguintes soluções:
24
ÍNDICE
- Criar blocos de estouro (overflow). Blocos de estouro não têm entradas em um índice
esparso;
- Inserir novos blocos na ordem seqüencial;
- Se não houver lugar para inserir informação em um bloco, alguma informação poderá ser
transferida para outro bloco. De igual forma, blocos vazios poderão ser combinados.
1.3.1.5 ÁRVORE B
a) Árvore de Pesquisa
Uma árvore de pesquisa é um tipo especial de árvore que se utilizada para guiar a
pesquisa por um registro, dado o valor de um dos campos do registro.
A árvore de busca é projetada com dois objetivos:
- Manter a árvore balanceada; e
- Evitar o desperdício de espaço dentro de um nó, à custa de maior complexidade nos
algoritmos de inserção e remoção.
Regras:
- Os nós da sub-árvore esquerda contém valores menores que a raiz;
- Os nós da sub-árvore direita contém valores maiores ou iguais a raiz;
- As sub-árvores são árvores binárias de pesquisa.
25
ÍNDICE
b) Árvore B
Em computação, Árvore B ou B-Tree é uma estrutura de dados árvores que são muito
utilizadas em banco de dados e sistema de arquivos.
Para inserir ou remover variáveis de um nó, o nó não poderá ultrapassar sua ordem e nem ser
menor que sua ordem dividida por dois. Árvores B não precisam ser rebalanceadas como são
freqüentemente as árvores de busca binária com Árvore AVL. Árvores B têm vantagens
substanciais em relação a outros tipos de implementações quanto ao tempo de acesso e
pesquisa aos nós.
Uma árvore B de ordem "m" (máximo de filhos para cada nó) é uma árvore que atende
as seguintes propriedades:
- Cada nó tem no máximo "m" filhos
- Cada nó (exceto a raiz e as folhas) tem pelo menos "m/2" filhos
- A raiz tem pelo menos dois filhos se a mesma não for uma folha
- Todas as folhas aparecem no mesmo nível e não carregam informação
- Um nó não-folha com "k" filhos deve ter k-1 chaves
Algoritmos
Inserção
1. Primeiro pesquise a chave, para ter a certeza de que esta não existe na árvore.
2. Busque a posição onde esta será inserida. Teste para ver se o nó está cheio.
3. Se nó estiver vazio, insira o valor dentro dele, senão execute uma subdivisão do nó da
seguinte forma:
3.1. Verifique se o nó-pai está vazio, se sim execute
3.1.1. Passe o elemento do meio do nó para seu pai.
3.1.2. Divida o nó em dois nós iguais.
26
ÍNDICE
3.2. Se o nó pai estiver cheio, repita as duas linhas acima recursivamente. (Caso todos os
nós-pai estiverem cheios, inclusive a raiz, deve ser criada uma nova raiz aumentando assim a
altura da árvore.
3.3. Somente após satisfazer todas divisões necessárias, insira nova chave.
Exclusão
1. Primeiro pesquise a chave para ter a certeza de que esta existe na árvore.
2. Se existir, verifique se está em folha, e faça a exclusão.
3. Se existir e não estiver em folha, substitua esta chave pela menor chave do filho a direita.
3.1. Se o número de chave no nó, for maior do que (Ordem/2 - 1), então termine a rotina.
3.2. Senão redistribua as chaves entre os nós vizinhos.
Busca
1. Indique a chave que será procurada.
2. Pesquise desde a raiz até encontrá-la, e então retorne o nó e a posição desta.
3. Se a chave não for encontrada, continue o laço até encontrar um nil das folhas.
Exemplo:
1.3.1.5 HASHING
São particularmente adequados para pesquisas por igualdade. A idéia principal é usar
uma função de hashing. Esta função mapeia um valor da chave de pesquisa (atributo de uma
tabela) em um registro ou balde (bucket) de registros.
27
ÍNDICE
Figura 15 - Hashing
A balde é uma unidade de armazenamento que contém um ou mais registros (um balde
é tipicamente um bloco do disco). Numa organização de ficheiro em hashing, obtemos o balde
de um registro a partir do valor da sua chave de pesquisa. Mais concretamente, o balde é
obtido através do cálculo da função de hash para aquela chave de pesquisa.
A função de hash h é uma função do conjunto de todos os valores da chave K para o
conjunto dos endereços de todos os baldes B. A função de hash é usada para localizar
registros para as operações de acesso, inserção, bem como eliminação. Observe os exemplos
de busca, inserção e exclusão.
A desvantagem do hashing estático pode conduzir a longas cadeias de transbordo.
Busca Inserção
Exclusão
28
ÍNDICE
a) Hashing Estático
O hashing estático escolhe a função hash com base no tamanho do arquivo atual, ou
com base no tamanho antecipado do arquivo com base em um ponto no futuro. Esta técnica
reorganiza periodicamente a estrutura de hash.
b) Hashing Dinâmico
c) Hashing Extensível
29
DATA MANIPULATION LANGUAGE - DML
3
Parte
U Para isso utilizam-se os comandos da DML (Data Manipulation Language). Nesta seara
encontramos comandos como Insert, Update, Delete, Commit e Rollback.
O Índice é um arquivo auxiliar associado a uma Tabela. Sua função é acelerar o tempo de
acesso às linhas de uma Tabela, cria ponteiros para os dados armazenados em colunas
especificas. O Banco de dados usa o Índice de maneira semelhante ao índice remissivo de um
livro, verifica um determinado assunto no Índice e depois localiza a sua posição em uma
determinada página.
3.1 INSERT
Comando responsável por adicionar um ou mais registros na tabela de Banco de
Dados. Os campos que forem omitidos recebem valores NULOS (“NULL”).
Sintaxe:
INSERT [TRANSACTION transaction] INTO <object> [(col [, col …])]
{VALUES (<val> [, <val> …]) | <select_expr>};
<object> = tablename | viewname
<val> = {:variable | <constant> | <expr>
| <function> | udf ([<val> [, <val> …]])
| NULL | USER | RDB$DB_KEY | ?
}
Exemplo:
INSERT INTO clientes (id, nome) VALUES (1, ‘Nome do Cliente’);
30
DATA MANIPULATION LANGUAGE - DML
NOTE BEM:
A lista de colunas é opcional no comando Insert;
Caso não seja definida, assume-se a seqüência da criação da tabela;
Para maior clareza do código e evitar erros em caso de reestruturação da tabela
recomenda-se utilizar a lista de colunas.
Valores alfanuméricos devem ser especificados entre aspas simples „exemplo‟;
Valores numéricos não devem conter esse separador.
Valores do tipo data devem ser tratados de acordo com as especificações do SGBD;
Ao incluir uma linha no Banco de Dados, o gerenciador checará as restrições de
integridade (Constraints). Assim chaves primárias, estrangeiras, domínios, etc são checadas no
momento da inclusão.
Caso alguma restrição for violada, a linha não será incluída e uma mensagem será
emitida pelo SGBD.
As colunas que não tiverem valores atribuídos terão conteúdo NULL ou default, caso
não haja a restrição NOT NULL.
Para inserir um valor nulo deve informar NULL no lugar correspondente a coluna.
Para incluir diversas linhas em uma tabela, utiliza-se o comando INSERT em conjunto
com o comando SELECT. Isso irá copiar as linhas de uma tabela para outra; A lista de colunas
do SELECT deve corresponder a totalidade de colunas da tabela.
Exemplo:
INSERT INTO vendas_old SELECT * FROM vendas WHERE data_venda =
CURRENTE DATE;
Outra forma é usando o comando INSERT por várias vezes consecutivas acompanhado
do finalizador ponto-e-virgula . Ou também após o comando VALUES colocando os dados
entre parênteses separados por vírgula.
Exemplo:
INSERT INTO vendas_old (prod_id, prov_valor) VALUES (1, 2.00),
(2, 3.00), (3, 5.00), (4, 10.00);
3.1.2 Laboratório
31
DATA MANIPULATION LANGUAGE - DML
3.1.3 Exercícios
ATENÇÃO:
Observe a sequência de inserção dos dados.
3.2 UPDATE
Sintaxe:
UPDATE [TRANSACTION transaction] {table | view}
SET col = <val> [, col = <val> …]
[WHERE <search_condition> | WHERE CURRENT OF cursor];
Exemplo:
UPDATE CLIENTE SET DATA_INCLUSAO = CURRENT DATE;
32
DATA MANIPULATION LANGUAGE - DML
3.2.1 Where
Comando responsável por especificar qual registro da tabela será alterado quando
usado em conjunto com a cláusula UPDATE.
NOTE BEM:
O conteúdo a ser atualizado deve respeitar o tipo de dado da coluna.
A condição expressa no comando servirá para definir quais linhas devem ser
atualizadas.
Caso a cláusula WHERE contenha a chave primária somente uma linha da será
atualizada.
Todas as restrições de integridade (Constraints) serão avaliadas pelo SGBD.
3.2.2 Laboratório
Exemplo:
UPDATE cd SET cd_preco = 21,00 WHERE cd_id = 1;
Se o aumento for para todos os cds de uma determinada gravadora, utilizaremos como
filtro da cláusula WHERE grav_id:
Exemplo:
UPDATE cd SET cd_preco = 22,00 WHERE grav_id = 1;
Imagine que ocorra um aumento de preço generalizado para todos os CDs em 5%.
Assim multiplica-se o próprio preço do CD por 1,05.
Exemplo:
UPDATE cd SET cd_preco = cd_preco * 1,05;
Outros Exemplos:
UPDATE cd SET cd_preco = 15 WHERE cd_id = 1;
UPDATE autor SET aut_nome = ‘B. Manilow’ WHERE aut_id = 2;
UPDATE cd SET cd_preco = cd_preco * 1,10 WHERE grav_id = 3;
UPDATE gravadora SET grav_nome = ‘E.M.I’, grav_tel = ‘2144332211’
WHERE grav_id = 1;
3.3 DELETE
33
DATA MANIPULATION LANGUAGE - DML
Sintaxe:
DELETE [TRANSACTION transaciona] FROM table
{[WHERE <search_condition>] | WHERE CURRENT OF cursor};
Exemplo:
DELETE FROM VENDAS WHERE DATA_VENDA <= ‘1-JAN-1999’;
3.3.1 Where
Comando responsável por especificar qual registro da tabela será excluído quando
usado em conjunto com a cláusula DELETE.
NOTE BEM:
O comando DELETE pode, da mesma forma que o comando UPDATE, afetar uma ou
mais linhas de uma tabela. Desta forma o escopo da exclusão será definido pela cláusula
WHERE.
Se for especificado na cláusula WHERE a chave primária, somente uma linha será
excluída.
Antes de uma exclusão, o gerenciador sempre fará uma checagem na integridade
referencial.
3.5 LABORATÓRIO
Neste primeiro exemplo, apenas o autor com código 1 será excluído (desde que não
haja relacionamentos com outras tabelas):
Exemplo:
DELETE FROM autor WHERE aut_id = 1;
Exemplo:
DELETE FROM cd WHERE grav_id = 2;
34
PESQUISA BÁSICA EM T ABELAS
4
Parte
gora que já sabemos criar, incluir, alterar e excluir informações nas tabelas, veja como
4.1 SELECT
É o comando utilizado para realizar buscas/pesquisas no banco de dados. Atrás dele há
uma extensão de possibilidades que vão desde a simples extração do conteúdo de todas as
linhas e colunas de uma tabela até a união de diversas tabelas, cálculos, agrupamentos,
ordenações e filtragem de linhas e colunas.
Sintaxe:
SELECT [DISTINCT | ALL] {* | Coluna [, coluna, ...]}
FROM tabela
Onde:
DISTINCT: Não mostra eventuais valores repetidos;
ALL: Mostra todos os valores (Propriedade Default do comando select);
*: Mostra todas as colunas da tabela;
NOTE BEM:
Para execução dos exemplos utilizaremos estrutura criada na aula 3 – DML.
Exemplos:
O exemplo mais simples de uma consulta é extrair todas as informações de uma tabela:
35
PESQUISA BÁSICA EM T ABELAS
Em muitas situações a ordem mostrada nem sempre é a que esperamos. Para que os
dados sejam mostrados da maneira que melhor nos atende usa-se a cláusula ORDER BY
seguida pela coluna que desejamos que seja ordenada:
Exemplo:
SELECT aut_id, aut_nome FROM autor
ORDER BY aut_nome;
Exemplo:
SELECT grav_id, cd_nome FROM cd
ORDER BY grav_id, cd_nome;
Para filtrar linhas em uma pesquisa, utilizamos a cláusula WHERE. Assim, é definido
uma expressão lógica (condição) que será validada e mostrará apenas as linhas que
atenderem ao critério estabelecido.
Sintaxe:
SELECT [DISTINCT | ALL] {* | Coluna [, coluna, ...]}
FROM tabela
WHERE condição
Estes operadores devem ser usados na definição das condições. Podemos testar
igualdade, diferença, maior, menor, maior ou igual, menor ou igual. Os operadores devem ser
colocados entre os argumentos que estão sendo comparados.
36
PESQUISA BÁSICA EM T ABELAS
Exemplo:
SELECT cd_nome, cd_preco FROM cd
WHERE cd_preco > 12;
NOTE BEM:
Da mesma forma que podemos comparar uma coluna com um valor, podemos
comparar com outra coluna.
Sempre quando fazemos esse tipo de comparação, devemos obedecer ao tipo de dado
que estamos comparando.
Muitas vezes, apenas uma condição não é suficiente para determinarmos o critério de
busca. Sempre que isso ocorrer, podemos utilizar operadores lógicos.
AND
Indica que as duas condições devem ser verdadeiras para que seja mostrada a linha.
Exemplo:
SELECT cd_nome, cd_preco, grav_id FROM cd
WHERE cd_preco > 10 AND grav_id = 2;
OR
Utilizamos o operador OR sempre que quisermos que o resultado final seja verdadeiro.
Exemplo:
SELECT cd_nome, cd_preco, grav_id FROM cd
WHERE cd_preco > 11 OR grav_id = 2
NOTE BEM
Não há limitação no uso e na combinação de condições usando OR e AND.
É conveniente utilizar parênteses para determinar o que se quer comparar.
37
PESQUISA BÁSICA EM T ABELAS
Exemplo:
SELECT cd_nome, grav_id, cd_preco FROM cd
WHERE (grav_id = 2 OR grav_id = 3) AND (cd_preco >= 17.50)
NOT ou !
É utilizado para inverter o resultado de uma expressão lógica, negando o resultado da
condição. Caso a condição seja verdadeira, será retornado falso e vice-versa.
Exemplo:
SELECT cd_nome, cd_preco FROM cd
WHERE NOT (cd_preco > 15);
Existem alguns operadores que são utilizados para determinar melhor as linhas que
queremos filtrar. São eles: IS NULL, IS NOT NULL, BETWEEN, LIKE e IN .
IS NULL
Sabemos que nem todas as colunas têm valores inicializados. Logo esse comando é
utilizado para saber os campos que não foram inicializados:
Exemplo:
SELECT * FROM GRAVADORA
WHERE grav_tel IS NULL
IS NOT NULL
Compara a negação do comando anterior. Somente aqueles que tiverem conteúdo
serão mostrados:
Exemplo:
SELECT * FROM GRAVADORA
WHERE grav_tel IS NOT NULL
BETWEEN
Esse operador serve para determinar um intervalo de busca. Quando desejarmos um
intervalo entre números, datas, etc utilizaremos o BETWEEN para simplificar a forma de
escrevermos o comando. Normalmente é utilizado em conjunto com o AND.
Exemplo:
SELECT cd_nome, cd_dt_lancamento FROM CD
WHERE cd.cd_dt_lancamento BETWEEN '01.01.1979' AND '31.12.2000';
38
PESQUISA BÁSICA EM T ABELAS
LIKE
Com esse operador podemos comparar cadeias de caracteres utilizando padrões de
comparação para um ou mais caracteres. O caractere percentual (%) substitui zero, um ou
mais caracteres e sublinha (_) substitui um caractere.
EXPRESSÃO APLICAÇÃO
LIKE ‘A%’ Todas a palavras que iniciem com a letra A
LIKE ’%A’ Todas a palavras que terminem com a letra A
LIKE ’%A%’ Todas a palavras que tenham a letra A em qualquer posição
LIKE ’A_’ String de dois caracteres que tenha a primeira letra A
LIKE ’_A’ String de dois caracteres que tenha o último caractere letra A
LIKE ’_A_’ String de três caracteres cuja segunda letra seja A
LIKE ’%A_’ Todas as palavras que tenham a letra A na penúltima posição
LIKE ’_A%’ Todas as palavras que tenha a letra A na segunda posição
Exemplos:
SELECT * FROM autor
WHERE aut_nome LIKE 'R%';
Um problema que pode surgir quando queremos fazer buscas utilizando os caracteres
de substituição é tê-los na cadeia de caracteres que está sendo pesquisada. Neste caso
devemos usar um caractere especial denominado ESCAPE.
Exemplo:
SELECT * FROM cd
WHERE cd_nome LIKE '%\_%'ESCAPE '\';
IN
Permite comparar o valor de uma coluna com um conjunto de valores. Utilizamos para
substituir uma série de comparações seguidas da cláusula OR.
Exemplo:
SELECT * FROM I
WHERE aut_id IN (1, 3) ;
4.2. EXERCÍCIOS
39
PESQUISA BÁSICA EM T ABELAS
b) Liste todas as linhas dos campos CD_ID, CD_NOME, CD_PRECO da tabela CD;
c) Liste todas as linhas dos campos AUT_ID, AUT_NOME da tabela AUTOR em ordem
alfabética;
f) Liste as colunas CD_NOME, CD_PRECO dos CD‟s cujos preços de venda sejam
inferiores a 20,00 e sejam da GRAVADORA 3;
40
CÁLCULOS E FUNÇÕES USUAIS
5
Parte
U
Exemplo:
totalizações de valores unitários. Podemos realizar cálculos quando realizamos buscas
no banco de dados simplesmente aplicando um dos operadores aritméticos a coluna.
5.1 OPERADORES
Estes são os operadores utilizados no SQL:
OPERADOR SIGNIFICADO
+ Soma
- Subtração
* Multiplicação
/ Divisão
Exemplo:
15 / 5 * 3, Resultado = 9
15 / (5 * 3), Resultado = 1
41
CÁLCULOS E FUNÇÕES USUAIS
Retorna o número de caracteres contidos em uma cadeia de caracteres. Esta função não
existe em todos os SGBD, como acontece no Firebird.
Exemplo:
SELECT CHARACTER_LENGTH (‘Renato Russo’);
5.1.2. Alfanuméricos
Exemplo:
SELECT grav_id || ' - ' || grav_contato
FROM gravadora;
Ao realizar buscas alfanuméricas no banco de dados notamos que os parâmetros são case
sensitive’s. Assim sendo, é possível usar os comandos UPPER E LOWER para transformar a
cadeia de caracteres para maiúsculo e/ou minúsculo.
Exemplo:
SELECT * FROM autor
WHERE UPPER(aut_nome) = ‘RENATO RUSSO’;
5.1.4. SUBSTRING
Essa função é requisito para SQL-92 ao nível intermediário. Retorna uma parte da cadeia de
caracteres.
Exemplo:
SELECT SUBSTRING(aut_nome from 1 FOR 3), aut_nome
FROM autor;
Em colunas do tipo data podemos realizar uma série de cálculos e operações cronológicas,
como calcular o número de dias entre duas datas, somar, subtrair dias, meses etc.
O padrão especifica 04 (quatro) tipos de dados relacionados data e hora:
42
CÁLCULOS E FUNÇÕES USUAIS
Tipo Descrição
Date Apenas data
Time Apenas Hora
Timestamp Data/Hora
Interval Intervalo entre dois tipos
Exemplos:
SELECT * FROM cd
WHERE cd_dt_lancamento = CURRENT_DATE;
5.1.6. EXTRACT
Essa função extrai e retorna um valor de um campo do tipo data. É possível extrair apenas o
dia, o mês, o ano, a hora, etc.
Exemplo:
SELECT cd_dt_lancamento, EXTRACT(MONTH FROM cd_dt_lancamento)
FROM cd;
Caso seja necessário realizar a concatenação de dados do tipo DATE é necessário utilizar o
comando CAST para converter o tipo do dado para um tipo STRING.
43
CÁLCULOS E FUNÇÕES USUAIS
5.2. EXERCÍCIOS
b. Escreva uma busca que mostre CD_NOME, CD_PRECO e CD_PRECO com 20% de
aumento.
c. Escreva uma busca igual à anterior, porém acrescente uma coluna mostrando a diferença
entre o CD_PRECO e CD_PRECO com 20% de aumento.
d. Escreva uma busca que mostre GRAV_NOME, GRAV_CONTATO em uma única coluna
separados por um hífen.
e. Escreva uma busca que mostre todos os autores que tenham a letra A no nome.
g. Escreva uma busca que mostre o CD_NOME e o número de dias entre a data atual e a data
de lançamento.
h. Escreva uma busca semelhante à anterior que mostre uma coluna com 15 dias após a
CD_DT_LANCAMENTO.
j. Escreva uma consulta que retorne os 05 primeiro caracteres de MUS_NOME e outra coluna
com MUS_NOME.
44
PESQUISA EM MÚLTIPLAS T ABELAS
6
Parte
N
os capítulos anteriores as pesquisas foram realizadas em apenas uma tabela. No
entanto, observamos no modelo criado, assim como acontece sempre, que uma tabela
está relacionada à outra, sendo necessário extrair informações de duas ou mais tabelas
relacionadas ao mesmo tempo. Esta tarefa recebe o nome de união ou junção de tabelas.
Isso se dá por meio das chaves primárias e chaves estrangeiras, que são no modelo
físico as colunas que as tabelas têm em comum.
Para os exemplos utilizados nesta aula é fundamental fazer uso do Modelo Lógico para
melhor visualizar os relacionamentos.
45
PESQUISA EM MÚLTIPLAS T ABELAS
6.1. ALIAS
Sintaxe:
SELECT tabela.coluna
FROM tabela;
Sintaxe:
SELECT t.coluna
FROM tabela t;
É ainda possível usar alias em nome de colunas, fazendo uso da cláusula AS;
Sintaxe:
SELECT coluna AS nome_desejado
FROM tabela;
Para realizar a união de tabelas basta acrescentar após a cláusula FROM do comando
SELECT as tabelas que queremos unir utilizando após a cláusula WHERE a condição de união
entre elas (Chave Primária e Chave Estrangeira).
Sintaxe:
SELECT [tabela1.]coluna [, [tabela2.]coluna, ...]
FROM tabela1, tabela2 [, ...]
WHERE tabela1.PK = tabela2.FK
Uma prática recomendável é utilizar o mesmo nome nos campos de chave primária e
chave estrangeira, pois dessa forma facilita a identificação dos campos ao realizar a união das
tabelas.
É possível colocar diversas tabelas na cláusula FROM. Não devemos esquecer, porém,
que é necessário especificar as chaves primárias e chaves estrangeiras de cada
relacionamento.
Em caso de dúvidas, consulte o Modelo de Dados para estabelecer quais são as
colunas comuns entre as tabelas. Daí a importância de se ter um bom projeto de Banco de
Dados claro e preciso.
A cláusula WHERE deve conter todo canal de relacionamento entre as tabelas listadas
na cláusula FROM sob pena de ocorrer o Produto Cartesiano.
46
PESQUISA EM MÚLTIPLAS T ABELAS
Exemplo:
SELECT cd.cd_id, cd.cd_nome, gravadora.grav_nome
FROM gravadora, cd
Exemplo:
SELECT cd.cd_id, cd.cd_nome, gravadora.grav_nome
FROM gravadora, cd
WHERE cd.grav_id = gravadora.grav_id
Usando alias:
Denomina-se união regular as uniões que têm a cláusula WHERE unindo chave
primária e chave estrangeira como visto anteriormente.
O padrão determina uma sintaxe alternativa para esse comando. Quando a chave
primária e a chave estrangeira têm o mesmo nome em ambas as tabelas é possível
simplificar o comando usando o comando NATURAL JOIN.
Exemplo:
SELECT cd.cd_id, cd.cd_nome, gravadora.grav_nome
FROM cd
NATURAL JOIN gravadora;
Outras duas maneiras definidas no padrão SQL é determinar qual(is) coluna(s) utilizar
na união usando a cláusula USING e caso o nome das colunas não sejam iguais, determinar
quais são as colunas com a cláusula ON. Ambas produzindo o mesmo efeito.
47
PESQUISA EM MÚLTIPLAS T ABELAS
Exemplo:
SELECT cd.cd_id, cd.cd_nome, gravadora.grav_nome
FROM cd JOIN gravadora USING (grav_id);
Freqüentemente é necessário unir mais de duas tabelas para obter uma informação
consistente.
Suponha que queira saber o nome da música, a faixa e o nome do CD em que está a
música. No modelo de dados observamos a necessidade de se consultar três tabelas no Banco
de Dados.
Exemplo:
SELECT c.cd_nome, f.fai_numero, m.mus_nome
FROM cd c, faixa f, musica m
WHERE c.cd_id = f.cd_id AND
m.mus_id = f.mus_id
Observe que é possível realizar a união de tantas tabelas quanto forem necessárias.
SELECT a.aut_nome, g.grav_nome
FROM autor a, cd c, gravadora g, faixa f, musica_autor ma, musica
m
WHERE a.aut_id = ma.aut_id AND
m.mus_id = ma.mus_id AND
m.mus_id = f.mus_id AND
c.cd_id = f.mus_id AND
g.grav_id = c.grav_id
Observa-se na união entre tabelas que quando uma linha não satisfaz a condição de
união entre as tabelas, ela não será mostrada no resultado da busca. Isto acontece porque o
banco de dados, não podendo estabelecer a relação entre as colunas que estão sendo unidas
na busca, coloca NULL onde o dado não existe.
48
PESQUISA EM MÚLTIPLAS T ABELAS
Exemplo:
SELECT cd.cd_id, cd.cd_nome, gravadora.grav_nome
FROM gravadora, cd
WHERE cd.grav_id = gravadora.grav_id
Como o nome diz, a união pela esquerda incluirá todas as linhas da primeira tabela na
expressão, ou seja a tabela da esquerda será a tabela base para a união.
Observe esse comando e depois inverta a posição das tabelas GRAVADORA e CD.
Exemplo:
SELECT cd.cd_id, cd.cd_nome, gravadora.grav_nome
FROM gravadora
LEFT OUTER JOIN cd ON (gravadora.grav_id = cd.grav_id)
Neste caso, todas as gravadoras são mostradas independente de haver ou não dados
relacionados na tabela CD.
Ao contrário da anterior, a união é realizada pela direita, pois incluirá todas as linhas da
tabela da direita na expressão da união, ou seja a tabela da direita será a tabela base para a
união.
Exemplo:
SELECT cd.cd_id, cd.cd_nome, gravadora.grav_nome
FROM gravadora
RIGHT OUTER JOIN cd ON (gravadora.grav_id = cd.grav_id)
NOTA:
Se a tabela da referência (direita ou esquerda) for a que contém a chave estrangeira,
ocorrerá uma união regular entre as tabelas.
49
PESQUISA EM MÚLTIPLAS T ABELAS
Exemplo:
SELECT cd.cd_id, cd.cd_nome, gravadora.grav_nome
FROM gravadora
FULL OUTER JOIN cd ON (gravadora.grav_id = cd.grav_id)
Neste caso a consulta age como uma união externa a direita ou a esquerda por não
haver campos nulos na coluna de chave estrangeira de CD.
6.7. EXERCÍCIOS
a. Faça uma busca que mostre todos os CD‟s e o nome de suas respectivas
gravadoras.
b. Faça uma pesquisa que mostre o produto cartesiano das tabelas MUSICA e CD.
c. Realize uma consulta se utilizando da sintaxe JOIN que mostre todas MUSICAS e o
nome de seus respectivos CD‟s.
d. Crie uma pesquisa que retorne como resultado todas as gravadoras e seus
respectivos CD‟s mesmo que estes não possuam CD‟s associados.
e. Crie uma pesquisa que mostre o AUTOR e suas MUSICAS ordenadas por AUTOR.
g. Crie uma pesquisa que mostre em quais gravadoras os autores tem realizado suas
gravações.
50
FUNÇÕES DE GRUPO E AGRUPAMENTO
7
Parte
A
té agora trabalhamos com funções que tratavam apenas de uma linha. Contudo, em
diversas situações é necessário trabalhar com várias linhas da consulta. Dessa forma, é
necessário conhecer funções especiais denominadas funções de grupo e agrupamento.
Funções de grupo operam conjuntos de linhas visando a fornecer um resultado para o grupo.
Estes grupos podem ser constituídos desde toda a tabela até subgrupos da tabela. Existem
diversas funções de grupo que são implementadas pelo padrão SQL.
As principais funções são:
FUNÇÃO DESCRIÇÃO
COUNT Retorna número de linhas afetadas pelo comando.
SUM Retorna o somatório do valor das colunas especificadas
AVG Retorna a média aritmética dos valores das colunas
MIN Retorna o menor valor da coluna de um grupo de linhas
MAX Retorna o maior valor da coluna de um grupo de linhas
STDDEV Retorna o desvio-padrão da coluna
VARIANCE Retorna a variância da coluna
7.1.1. COUNT
Diferente das outras funções de grupo, o COUNT retorna o número de linhas que
atende a uma determinada condição.
Podemos utilizá-lo com um asterisco entre parênteses, para indicar que queremos saber
a quantidade total de linhas independente de haver linhas com colunas nulas ou não.
Exemplos:
SELECT COUNT(*)
FROM gravadora;
SELECT COUNT(grav_contato)
FROM gravadora;
51
FUNÇÕES DE GRUPO E AGRUPAMENTO
Exemplos:
SELECT COUNT(grav_contato)
FROM gravadora
WHERE grav_contato IS NOT NULL;
Diferente de:
SELECT COUNT(*)
FROM gravadora
WHERE grav_contato IS NULL;
Exemplos:
SELECT COUNT(DISTINCT aut_id)
FROM musica_autor;
SELECT COUNT(aut_id)
FROM musica_autor;
7.1.2. SUM
Assim se quisermos saber o total do preço de venda dos CD‟s, utilizamos o comando:
Exemplo:
SELECT SUM(cd_preco)
FROM cd;
Exemplo:
SELECT SUM(cd_preco) * 1.2
FROM cd;
7.1.3. AVG
Para saber o preço médio dos CD‟s da loja execute o seguinte comando:
Exemplo:
SELECT AVG(cd_preco)
FROM cd;
52
FUNÇÕES DE GRUPO E AGRUPAMENTO
7.1.4. MIN
Exemplos:
SELECT MIN(cd_preco)
FROM cd;
SELECT MIN(cd_dt_lancamento)
FROM cd;
SELECT MIN(cd_nome)
FROM cd;
7.1.5. MAX
Exemplos:
SELECT MAX(cd_preco)
FROM cd;
SELECT MAX(cd_dt_lancamento)
FROM cd;
SELECT MAX(cd_nome)
FROM cd;
Exemplo:
SELECT STDDEV(cd_preco)
FROM cd;
53
FUNÇÕES DE GRUPO E AGRUPAMENTO
Para saber a variância do preço de venda dos CD‟s da loja execute o seguinte
comando:
Exemplo:
SELECT VARIANCE(cd_preco)
FROM cd;
7.2.1. GROUP BY
O comando GROUP BY deve vir antes da cláusula ORDER BY e depois do WHERE (se
houver necessidade de utilizá-lo). É utilizado com uma função de grupo (COUNT, SUM, AVG,
MIN ou MAX).
Exemplo:
SELECT cd_id, COUNT(*)
FROM faixa
GROUP BY cd_id;
Exemplo:
SELECT grav_id, AVG(cd_preco)
FROM cd
GROUP BY grav_id;
É possível realizar mais de uma função de grupo dentro de um mesmo SELECT. Neste
exemplo, além do preço de venda, temos a quantidade de CD‟s de cada gravadora:
Exemplo:
SELECT grav_id, AVG(cd_preco), COUNT(*)
FROM cd
GROUP BY grav_id;
54
FUNÇÕES DE GRUPO E AGRUPAMENTO
Exemplo:
SELECT c.grav_id, g.grav_nome, AVG(c.cd_preco)
FROM cd c, gravadora g
WHERE c. grav_id = g.grav_id
GROUP BY c.grav_id, g.grav_nome
NOTA
É necessário colocar todas as colunas que fazem parte do comando SELECT na cláusula
GROUP BY.
Caso se deseje ordenar o resultado, basta acrescentar o comando ORDER BY no final do
comando após o comando GROUP BY:
Exemplo:
SELECT c.grav_id, g.grav_nome, AVG(c.cd_preco)
FROM cd c, gravadora g
WHERE c. grav_id = g.grav_id
GROUP BY c.grav_id, g.grav_nome
ORDER BY g.grav_nome desc
Exemplo:
SELECT mus_id, COUNT(*)
FROM musica_autor
WHERE mus_id < 3
GROUP BY mus_id;
ou
SELECT mus_id, COUNT(*)
FROM musica_autor
GROUP BY mus_id
HAVING mus_id < 3;
NOTE BEM
55
FUNÇÕES DE GRUPO E AGRUPAMENTO
Exemplos:
SELECT GRAV_ID, AVG(cd_preco) FROM cd
WHERE AVG(cd_preco) > 12
GROUP BY grav_id
7.5. EXERCÍCIOS
b. Verifique a diferença entre o maior e menor valor dos preços de venda dos CD‟s.
c. Verifique a quantidade de dias compreendidos entre a data mais atual e a data mais
antiga das datas de lançamento dos CD‟s;
e. Mostre através de uma consulta a média de duração das músicas cujo nome comece
com a letra A;
g. Faça uma consulta que retorne a o nome do CD e a média de duração das músicas
em cada CD, desde que esta média não seja superior a 4.
h. Faça uma consulta que retorne os autores que são autores de mais de uma música.
56
SUBCONSULTAS
8
Parte
SUBCONSULTAS – SUBQUERIES
N
as sessões anteriores exploramos largamente o comando SELECT utilizando-o em
conjunto com uma gama de funções. Ainda neste contexto, é possível incluir
subconsultas dentro das consultas principais.
8.1. SUBQUERY
Sintaxe:
SELECT colunas
FROM tabela
WHERE expressão operador (SELECT colunas FROM tabela
WHERE ...)
Neste caso, primeiro é realizada a busca em uma tabela e, com base no resultado,
pesquisada a outra tabela.
Exemplo:
SELECT cd_nome, cd_preco FROM cd
WHERE cd_preco > (SELECT AVG(cd_preco) FROM cd)
Acima é utilizada uma subquery para verificar a média de preço dos CD‟s e, com base
nesse resultado, é extraído o resultado da busca do primeiro SELECT.
57
SUBCONSULTAS
Exemplo:
SELECT grav_id, cd_nome, cd_preco FROM cd c
WHERE cd_preco > (SELECT AVG(cd_preco) FROM cd
WHERE grav_id = c.grav_id)
Acima são buscados apenas os CD‟s que tenham preço de venda superior a média da
própria gravadora.
Muito cuidado ao usar essa construção, porque ele tende a consumir muito recurso do
banco de dados, pois a cada linha do primeiro SELECT será extraído a média no segundo
SELECT.
Assim é necessário saber qual a gravadora do primeiro SELECT, para poder calcular o
segundo SELECT.
NOTA
- Coloque as subqueries entre parênteses.
- Coloque a subquery à direita do operador.
- Não use a cláusula ORDER BY em uma subquery. Se for necessário ordenar faça-o
no SELECT principal.
- Use operadores de grupo apenas em buscas que potencialmente retornem mais de
uma linha.
- Use operadores de linha apenas em buscas que retornem uma única linha.
Exemplo:
SELECT grav_id, cd_nome, cd_preco FROM cd
WHERE grav_id = (SELECT grav_id FROM cd WHERE cd_id = 2) AND
cd_preco > (SELECT cd_preco FROM cd WHERE cd_id = 5);
Exemplos:
SELECT grav_id, MIN(cd_preco) FROM cd
GROUP BY grav_id
HAVING MIN(cd_preco) > (SELECT cd_preco FROM cd
WHERE cd_id = 2)
58
SUBCONSULTAS
Verifica o número de linhas retornadas pela subquery. Caso contenha uma ou mais
linhas, então o resultado será mostrado.
Exemplo:
Note que quando se está utilizando esse operador, não importa o que o comando
SELECT interno irá buscar. Interessa apenas se ele retorna ou não linhas, Por esse motivo é
usado o * em vez de uma coluna em especial.
Neste caso o SELECT interno retorna mais de uma linha. Não é possível utilizar
operadores simples como igualdade, diferença, maior ou menor.
Utilizam-se operadores de grupo para realizar a comparação, como:
- ANY
- ALL
- IN
8.1.2.1. IN
Imagine que queremos saber quais CD‟s têm o preço igual ao menor preço de cada
gravadora. Inicialmente devemos saber qual o menor preço de cada gravadora.
59
SUBCONSULTAS
Esse operador permite comparar operadores simples (=,<,>,!=) com um grupo de linhas.
Imagine que desejamos saber quais CD‟s têm preço inferior a qualquer outro da gravadora com
código 2, mas que não sejam da gravadora 2.
Inicialmente é preciso saber qual é o preço de venda de cada CD que não seja da
gravadora 2:
Depois precisamos saber quais os preços dos CD‟s da gravadora 2 com o comando da
seguinte forma:
8.1.2.3. ALL
Esse operador é usado em combinação com operadores simples (<,>) para que os
valores retornados de todas as linhas do SELECT interno sejam comparados com o SELECT
externo.
Imagine que queiramos saber quais CD‟s têm o preço de venda menor que a média de
preço de venda de todas as gravadoras.
Inicialmente é necessário saber a média de preços por gravadora:
Depois verificamos quais são os CD‟s com preço inferior a todos anteriores.
60
SUBCONSULTAS
Exemplo:
SELECT grav_id || cast(MIN(cd_indicado) as varchar)
FROM cd
GROUP BY grav_id
Exemplo:
SELECT cd_id, cd_nome, grav_id, cd_indicado FROM cd
WHERE (grav_id, cd_indicado) IN
(SELECT grav_id, MIN(cd_indicado) FROM cd
GROUP BY grav_id)
NOTA:
Quando um SELECT interno contiver valores nulos, não deve ser utilizado NOT IN
como operador de comparação. Isso porque qualquer comparação com nulo retorna nulo.
61
SUBCONSULTAS
Exemplo:
SELECT a.cd_nome, a.cd_preco, b.preco_medio
FROM cd a, (SELECT grav_id, AVG(cd_preco) as preco_medio FROM cd
GROUP BY grav_id) b
WHERE a.grav_id = b.grav_id
AND a.cd_preco > b.preco_medio
Veja que foi substituída a segunda tabela por um comando SELECT e que a tabela
recebeu o apelido de b.
8.2. EXERCÍCIOS
a) Faça uma lista de CD‟s usando subquery que foram gravados pela gravadora 2.
b) Faça uma lista que mostre os CD‟s que custam mais que a média de preço dos CD‟s
gravados pela gravadora 1.
c) Faça uma consulta usando a cláusula HAVING que retorne o CD mais barato que a
média de preço dos CD‟s.
d) Faça uma lista que mostre os CD‟s cujas músicas tem duração maior que 00:02:00.
e) Faça uma lista que mostre quais CD‟s tem preços superiores a qualquer CD da
gravadora 1 excluindo os da própria gravadora 1.
62
VISÕES/VIEW
9
Parte
VISÕES/VIEW
A
nteriormente aprendemos a criar consultas em bancos de dados com a linguagem SQL
usando uma série de funções que permitem a extração dos dados de diversas formas.
Nesta sessão veremos a utilização de visões (Views), também chamadas de tabelas
virtuais em sistemas de bancos de dados.
As views são um modo especial de enxergar dados de uma ou várias tabelas. É um
objeto de banco de dados criado a partir de um comando SELECT.
É importante saber que ela é armazenada no dicionário de dados e possui a mesma
estrutura de uma tabela.
As views permitem restringir o acesso aos dados, por exemplo, utilizando o comando
SELECT podemos filtrar linhas e coluna que não devam ser mostradas a todos os usuários.
As buscas complexas tornam-se simples, pois ao DBA é possível criar consultas
complexas em forma de visões e ao usuário realizar as buscas necessárias nessa visão.
Outro aspecto é a independência de dados: as visões podem ser criadas visando
atender necessidades genéricas e não apenas às relacionadas a pessoa ou programas.
Podemos buscar dados em diversas tabelas.
A eliminação de códigos é outra razão: normalmente os códigos não devem ser
mostrados aos usuários, pois são utilizados apenas para estabelecer relacionamento entre as
tabelas. Dessa forma facilita a compreensão dos dados pelo usuário.
9.1. CLASSIFICAÇÃO
a) Simples:
- Os dados são extraídos de uma única tabela;
- Não contém funções.
- Não possuem dados agrupados.
- Podem utilizar comandos DML para manipular os dados.
b) Complexas:
- Os dados são extraídos de várias tabelas.
- Podem conter funções.
- Podem conter dados agrupados.
- Não podem utilizar comandos DML para manipulação de dados, exceto no Oracle,
pois possui recursos específicos para isso.
63
VISÕES/VIEW
Sintaxe:
CREATE VIEW nome
AS query/subquery
Exemplo:
CREATE VIEW vCD AS
SELECT cd_id, cd_nome, cd_preco FROM cd;
Exemplos:
CREATE VIEW vPRECO_CD AS
SELECT grav_id, cd_nome, cd_preco FROM cd
WHERE grav_id = (SELECT grav_id FROM cd
WHERE cd_preco > 10.00)
Exemplo:
SELECT * FROM vCD;
SELECT * FROM vCD_FAIXA;
64
VISÕES/VIEW
Exemplo:
SELECT * FROM VPRECO_CD
WHERE cd_preco > 8;
Somente em visões simples é possível utilizar comandos DDL. O padrão SQL determina
as condições em que uma visão pode ser atualizada:
- Deve ser criada em uma única tabela;
- Deve conter apenas um SELECT;
- Se foi criada com base em outra visão, a primeira visão dever ser passível de
atualização;
- O comando SELECT não pode conter colunas calculadas;
- Não deve utilizar GROUP BY;
- Não deve conter a cláusula DISTINCT;
- Pode conter uma subquery, desde que o SELECT interno tenha como base a mesma
tabela do SELECT externo;
- Inclusões só podem ser feitas caso a visão contenha a chave primária da tabela base.
- Exclusões e alterações em visões sem a chave primária da tabela base são
permitidas, porém desaconselháveis, pois não se sabe ao certo o resultado que pode aparecer.
Isso é chamado de Materialização de Views.
Sintaxe:
DROP VIEW nome;
Exemplo:
DROP VIEW vCD;
9.6. EXERCÍCIOS
a) Crie uma visão que mostre uma lista de CD‟s que foram gravados pela gravadora 2.
d) Construa uma visão que mostre as músicas sua duração e a que CD pertence.
65
PROCEDIMENTOS ARMAZENADOS/STORED PROCEDURES
10
Parte
PROCEDIMENTOS ARMAZENADOS
E de se utilizar recursos como loop, estruturas de decisão, etc. Para isso, utiliza-se os
procedimentos armazenados o qual definimos como um programa escrito em uma
linguagem própria que é armazenado como parte do banco de dados.
Em outras palavras Procedimento Armazenado ou Stored Procedure é uma
coleção de comandos em SQL disponíveis em Banco de dados. Encapsula tarefas repetitivas,
aceita parâmetros de entrada e retorna um valor de status (para indicar aceitação ou falha na
execução). O procedimento armazenado pode reduzir o tráfego na rede, melhorar a
performance, criar mecanismos de segurança, etc. (Wikipédia, a enciclopédia livre, 2009).
66
PROCEDIMENTOS ARMAZENADOS/STORED PROCEDURES
Sintaxe:
CREATE [OR REPLACE] FUNCTION nome ([tipo_do_parametro1],[...])
RETURNS tipo_retornado AS '
Implementação_da_função;
'
LANGUAGE 'SQL';
67
PROCEDIMENTOS ARMAZENADOS/STORED PROCEDURES
Exemplo:
CREATE FUNCTION soma(INTEGER, INTEGER)
RETURNS INTEGER AS '
SELECT $1 + $2;
'
LANGUAGE 'SQL';
O fato de que as funções utilizando SQL sempre retornam valor faz com que seja
sempre necessário que a última linha de comando da função utilize o comando SELECT.
Exemplo:
CREATE FUNCTION cubo(INTEGER)
RETURNS FLOAT AS '
SELECT $1 ^ 3;
'
LANGUAGE 'SQL';
Também é possível criar funções que fazem interação entre uma determinada consulta
e parâmetros utilizados na função. Na função abaixo se obtém o total de CD‟s gravados por
determinada gravadora, passando como parâmetro o id da gravadora (grav_id):
Exemplos:
CREATE FUNCTION cdGravados(INTEGER)
RETURNS INTEGER AS '
SELECT COUNT(cd_id) FROM cd WHERE grav_id = $1; '
LANGUAGE 'SQL';
NOTA:
Dependendo da configuração escolhida na instalação do PostgreSQL será necessário
ajustar o tipo do retorno fazendo uso da função CAST.
Exemplo:
CAST(COUNT(cd_id) as INTEGER)
68
PROCEDIMENTOS ARMAZENADOS/STORED PROCEDURES
Exemplo:
SELECT cdGravados(4);
Como mencionado, também é possível retornar várias linhas de uma consulta em uma
função. Para isso, utilizamos o tipo de retorno SETOF. No próximo exemplo é criada uma
função em que retorna todos os CD‟s mais caros que determinado valor passado por
parâmetro.
Exemplo:
CREATE OR REPLACE FUNCTION precoMaior(NUMERIC(10,2))
RETURNS SETOF cd AS'
SELECT * FROM cd WHERE cd_preco > $1;
'
LANGUAGE 'SQL';
Quando as funções possuem o seu retorno referenciado em uma tabela ou uma View,
ou seja, quando a função retorna um resultset, devemos utilizar a função da seguinte maneira:
Exemplo:
SELECT * FROM precoMaior(5.2);
A exclusão de uma função se faz através do comando DROP, como visto na DDL.
Sintaxe:
DROP FUNCTION nome_da_funcao();
Quando a função, na sua assinatura contiver parâmetros não será possível sua
exclusão através do comando DROP FUNCTION nome_da_funcao(), ou seja, para excluir uma
função é necessário passar toda a sua assinatura.
Exemplo:
DROP FUNCTION precoMaior(NUMERIC(10,2));
Ainda existe o fato que no momento da exclusão poder excluir a função passando mais
um parâmetro, como no exemplo a seguir:
Exemplo:
DROP FUNCTION cd_grav (psql INTEGER) RESTRICT;
DROP FUNCTION cd_grav (psql INTEGER) CASCADE;
69
PROCEDIMENTOS ARMAZENADOS/STORED PROCEDURES
Nota:
Se a função for removida e recriada, a nova função não é mais a mesma entidade que
era antes. Ficarão inválidas as regras, visões, gatilhos, etc. existentes que fazem referência à
antiga função. Use o comando CREATE OR REPLACE FUNCTION para mudar a definição de
uma função, sem invalidar os objetos que fazem referência à função.
10.4.1. PL/pgSQL
A PL/pgSQL é uma linguagem estrutural estendida da SQL que tem por objetivo auxiliar
as tarefas de programação no PostgreSQL. Ela incorpora à SQL características procedurais,
como os benefícios e facilidades de controle de fluxo de programas que as melhores
linguagens possuem como loops estruturados (for, while) e controle de decisão (if, then, else).
Dessa forma, programar em PL/pgSQL significa ter a disposição um ambiente procedural
totalmente desenvolvido para aplicações de bancos de dados, beneficiando-se do controle
transacional inerente das aplicações deste tipo.
Sintaxe:
[<<label>>]
[DECLARE
declarações]
BEGIN
conteúdo 1;
conteúdo 2;
conteúdo n;
END;
70
PROCEDIMENTOS ARMAZENADOS/STORED PROCEDURES
Exemplo:
CREATE OR REPLACE FUNCTION mostra_valor(valor INT)
RETURNS INTEGER AS
$$ DECLARE
valor INTEGER := $1;
BEGIN
RAISE NOTICE 'O valor da variável aqui é %', Valor;
RETURN valor;
END; $$
LANGUAGE 'PLPGSQL';
Executando a função:
SELECT mostra_valor(12);
Exemplo:
CREATE OR REPLACE FUNCTION formatarCPF(cpf VARCHAR(11))
RETURNS VARCHAR(14) AS $$
BEGIN
IF char_length(cpf) != 11 THEN
RAISE NOTICE 'Formato inválido: %', $1;
RETURN 'ERRO';
END IF;
RETURN SUBSTRING(cpf FROM 1 FOR 3) || '.' || SUBSTRING(cpf
FROM 4 FOR 3) || '.' || SUBSTRING(cpf FROM 7 FOR 3) || '-' ||
SUBSTRING(cpf FROM 10 FOR 2);
END;
$$
LANGUAGE PLPGSQL;
SELECT formatarCPF('11111111111');
71
PROCEDIMENTOS ARMAZENADOS/STORED PROCEDURES
Exemplo:
CREATE OR REPLACE FUNCTION alteraPreco(id INTEGER, preco
NUMERIC(10,4))
RETURNS VARCHAR(50) AS $$
DECLARE
valorMax NUMERIC(10,4) := 100;
valorMin NUMERIC(10,4) := 1;
BEGIN
IF $2 >= valorMin and $2 <= valorMax THEN
UPDATE CD SET cd_preco = $2 WHERE cd_id = $1;
RETURN 'Preço alterado com sucesso';
ELSE
RETURN 'O valor inserido está fora da faixa delimitada
para preços de CDs';
END IF;
END;
$$
LANGUAGE PLPGSQL;
Exemplo:
CREATE OR REPLACE FUNCTION cd_grav (psql integer)
RETURNS SETOF RECORD AS $$
BEGIN
RETURN QUERY SELECT cd_nome, grav_nome FROM cd, gravadora WHERE
cd.grav_id = gravadora.grav_id AND gravadora.grav_id = $1; -- Consulta
RETURN; -- Retorna as linhas
END;
$$ LANGUAGE plpgsql;
Exemplo:
SELECT * FROM cd_grav(2) AS ( c1 VARCHAR(50), c2 VARCHAR(50) );
72
PROCEDIMENTOS ARMAZENADOS/STORED PROCEDURES
10.4. EXERCÍCIOS
a) Crie uma Stored Procedure no PostgreSQL que faça inserções na tabela de música.
b) Crie uma Stored Procedure no PostgreSQL que retorne quais música foram gravadas
em determinado CD passando como parâmetro o id do CD (cd_id).
73
TRIGGERS (G ATILHOS OU AUTOMATISMOS)
11
Parte
D
esenvolver uma aplicação para gerenciar os dados significa criar uma aplicação que
faça o controle sobre todo ambiente desde a interface, passando pela manutenção dos
dados e as regras de negócios do sistema.
Assim, é o sistema que deve controlar e tomar as decisões sobre o que fazer em
determinadas situações. Em um programa para controlar os produtos de uma empresa, quando
a quantidade de um produto atingir certa quantidade o sistema deverá avisar o
operador/usuário para providenciar a reposição do mesmo.
Ao trabalhar com base de dados Cliente/Servidor como SQL Server, Oracle, Informix,
PostgreSQL dentre outras, é possível usar um recurso muito poderoso chamado Trigger.
Triggers são rotinas armazenadas no banco de dados e utilizadas quando um comando
Insert, Update ou Delete é executado em uma tabela ou até mesmo uma visão (view).
Trigger significa gatilho e é disparada quando os comandos da DML são disparados.
São executadas automaticamente sem a interferência do usuário, ou seja, são procedimentos
armazenados que são acionados por algum evento e em determinado momento.
As principais aplicações das triggers estão relacionadas às validações, restrições de
acesso, rotinas de segurança e consistência de dados.
Triggers são iguais a stored procedures com as seguintes exceções:
- São chamadas automaticamente;
- Não tem parâmetros;
- Não retornam valores.
O gatilho fica associado com uma tabela e executa uma função especifica. Na maioria
dos bancos de dados estes eventos podem ser inserções (INSERT), atualizações (UPDATE) e
exclusões (DELETE), e podem ser executadas em dois momentos:
- Antes da execução do evento (BEFORE);
- Depois da execução do evento (AFTER).
74
TRIGGERS (G ATILHOS OU AUTOMATISMOS)
Uma trigger deve ser disparada antes de o registro ser atualizado caso queira alterar o
valor de uma ou mais colunas antes que a linha seja atualizada, ou queira bloquear a alteração
da linha gerando uma exceção, como por exemplo: usar uma trigger BEFORE UPDATE para
evitar que o usuário apague o registro de um cliente que tenha comprado nos últimos dois
anos.
Triggers do tipo AFTER quando se deseja garantir que a atualização que disparou a
trigger seja completada com sucesso antes de executar outras ações, como por exemplo:
inserir uma linha em uma tabela de salario_historico sempre que o salário de um funcionário for
alterado.
No corpo de uma trigger é possível usar tanto os valores antigos ou novos de qualquer
registro. Para isso basta utilizar os comandos OLD e NEW.
Exemplo:
old.aut_nome
new.aut_nome
A trigger-por-linha é disparada uma vez para cada registro afetado pela instrução que
disparou a trigger.
A trigger-por-instrução é disparada somente uma vez quando a instrução é
executada.
75
TRIGGERS (G ATILHOS OU AUTOMATISMOS)
Funções de triggers são funções que não recebem nenhum parâmetro e retornam o tipo
trigger. Essas funções recebem uma estrutura chamada TriggerData, e esta é passada
internamente para a função pelo PostgreSQL.
O PostgreSQL disponibiliza duas variáveis importantes para serem usadas em conjunto
com as triggers-por-linha: NEW e OLD.
A variável NEW, no caso do INSERT, armazena o registro que está sendo inserido. No
caso do UPDATE, armazena a nova versão do registro depois da atualização.
A variável OLD, no caso do DELETE, armazena o registro que está sendo excluído. No
caso do UPDATE, armazena a antiga versão do registro depois da atualização.
As funções de triggers devem ser escritas em alguma linguagem procedural disponível
no banco de dados1.
Cada linguagem, que suporta triggers, possui o seu próprio método para tornar os
dados de entrada da trigger disponíveis para a função. Estes dados de entrada incluem o tipo
de evento da trigger, assim como as opções informadas na criação da trigger. Para uma trigger
no nível de linha, os dados de entrada também incluem as linhas NEW para as triggers de
INSERT e UPDATE, e a linha OLD para os triggers de UPDATE e DELETE.
Sintaxe:
CREATE TRIGGER nome { BEFORE | AFTER } { evento [OR ...] }
ON tabela FOR EACH { ROW | STATEMENT }
EXECUTE PROCEDURE função ( argumentos )
Onde:
Nome: O nome da Trigger.
Tabela: O nome da tabela na qual a trigger estará vinculada.
Evento: INSERT, DELETE ou UPDATE.
Função: Pode-se usar, neste caso, uma stored procedure para execução de
determinada tarefa.
row|statement: especifica se a trigger deve ser disparada uma vez para cada linha
afetada pelo evento ou apenas uma vez por comando SQL. Se não for especificado nenhum
dos dois, o padrão é FOR EACH STATEMENT.
Exemplo:
Para este primeiro exemplo é necessário alterar nosso banco de dados:
ALTER TABLE autor
ADD aut_cpf CHAR(14);
Próximo passo é criar a função que faz a inserção de determinado valor nesta tabela:
1
Essas linguagens podem ser várias, como Ruby, Perl, Python, entre outras. Atualmente existem quatro linguagens
procedurais disponíveis na distribuição padrão do PostgreSQL: PL/pgSQL, PL/Tcl, PL/Perl e PL/Python. Mas é
possível que o usuário defina outras linguagens. Para instalar novas linguagens no PostgreSQL, consulte a
documentação oficial do PostgreSQL, que pode ser obtida no seguinte endereço: http://pgdocptbr.sourceforge.net/.
76
TRIGGERS (G ATILHOS OU AUTOMATISMOS)
Exemplo:
CREATE OR REPLACE FUNCTION ftFormataCPF()
RETURNS trigger AS
$$
BEGIN
IF char_length(new.aut_cpf) = 11 THEN
new.aut_cpf := SUBSTRING(new.aut_cpf FROM 1 FOR 3) ||
'.' || SUBSTRING(new.aut_cpf FROM 4 FOR 3) || '.' ||
SUBSTRING(new.aut_cpf FROM 7 FOR 3) || '-' || SUBSTRING(new.aut_cpf
FROM 10 FOR 2);
RETURN new;
END IF;
END;
$$
LANGUAGE plpgsql;
Exemplo:
CREATE TRIGGER tFormataCpf BEFORE INSERT
ON autor FOR EACH ROW
EXECUTE PROCEDURE ftFormataCPF ();
Dentre as funções que foram apresentadas para triggers é possível utilizar uma grande
quantidade de argumentos com a finalidade de criar controles e métodos de auditoria nos
bancos de dados PostgreSQL. Todas elas são facilmente encontradas no manual do
PostgreSQL.
Desses, um dos argumentos mais importantes é o TG_OP que permite identificar qual
operação está sendo realizada: INSERT, UPDATE e DELETE. Muito útil para criar mecanismos
de auditoria nos dados contidos em determinada tabela.
Acompanhe atentamente o exemplo abaixo:
Exemplo:
Primeiramente vamos criar uma tabela de histórico:
77
TRIGGERS (G ATILHOS OU AUTOMATISMOS)
Se uma função de trigger executar comandos SQL, estes comandos podem disparar
triggers novamente. Isto é conhecido como cascatear triggers. Não existe limitação direta do
número de níveis de cascateamento. É possível que o cascateamento cause chamadas
recursivas da mesma trigger; por exemplo, um trigger para INSERT pode executar um
78
TRIGGERS (G ATILHOS OU AUTOMATISMOS)
comando que insere uma linha adicional na mesma tabela, fazendo com que a trigger para
INSERT seja disparada novamente. É responsabilidade de o programador evitar recursões
infinitas nestes casos.
Sintaxe:
ALTER TRIGGER nome ON tabela RENAME TO novo_nome;
Sintaxe:
DROP TRIGGER nome ON tabela [ CASCADE | RESTRICT ]
Onde:
Nome: é o nome da trigger a ser removida.
Tabela é o nome da tabela para a qual a trigger está definida.
[ CASCADE | RESTRICT ]: indica que ao remover a trigger vamos remover também
todos os objetos que dependem dela (CASCADE) ou recusaremos sua exclusão (RESTRICT).
Sintaxe:
ALTER TABLE nome_tabela [DISABLE|ENABLE] TRIGGER nome_trigger;
Sintaxe:
ALTER TABLE nome_tabela [DISABLE|ENABLE] TRIGGER ALL;
11.4. EXERCÍCIO
a) Crie uma trigger responsável por verificar, no momento da inserção na tabela de CD,
se o preço do CD é maior de 1,00 e inferior a 100,00.
79
SEGURANÇA DE BANCO DE DADOS
12
Parte
P
odemos dizer que segurança em banco de dados garante que os usuários tenham
permissão para fazer o que realmente precisam fazer. Para tanto, os Sistemas
Gerenciadores de Banco de Dados precisam de certas limitações, na qual os usuários
não poderão violar. Estas especificações são criadas pelo DBA (Administrador de Banco de
Dados).
Todas as decisões acerca dos direitos que devem ser concedidos a determinado
usuário são decisões políticas e não técnicas. Assim sendo, tais competências fogem a alçada
dos Sistemas Gerenciadores de Banco de Dados.
80
SEGURANÇA DE BANCO DE DADOS
Sintaxe:
CREATE USER|ROLE nome [ [ WITH ] opção [ ... ] ]
Onde, opção pode ser:
SYSID id_do_usuário
| CREATEDB | NOCREATEDB
| CREATEUSER | NOCREATEUSER
| IN GROUP nome_do_grupo [, ...]
| [ ENCRYPTED | UNENCRYPTED ] PASSWORD 'senha'
| VALID UNTIL 'data_e_hora'
Parâmetros:
81
SEGURANÇA DE BANCO DE DADOS
Deve ser usado o comando ALTER USER para mudar os atributos de um usuário, e
DROP USER para remover um usuário. Deve se usado ALTER GROUP para adicionar ou
remover usuários de grupos de forma semelhante como acontece com a criação do usuário.
O PostgreSQL inclui o programa createuser que possui a mesma funcionalidade do
CREATE USER (na verdade, chama este comando), mas pode ser executado a partir da linha
de comando.
82
SEGURANÇA DE BANCO DE DADOS
Exemplos:
Criar um usuário sem senha:
CREATE USER Jonas;
CREATE ROLE Jonas;
Criar um usuário com uma senha válida até o fim de 2009. Após o primeiro segundo de
2010 a senha não será mais válida:
CREATE ROLE miriam WITH PASSWORD 'jw8s0F4' VALID UNTIL '2010-01-
01';
Para alterar determinado usuário, basta utilizar o comando ALTER ROLE de maneira
semelhante como ocorre com o comando CREATE ROLE:
Exemplo:
Conceder permissão para o usuário criar outro usuários e bancos dedados:
ALTER ROLE miriam CREATEROLE CREATEDB;
Para saber quais usuário estão cadastrados no PostgreSQL basta fazer uma consulta
na tabela do sistema pg_user:
SELECT username FROM pg_user;
Sintaxe:
CREATE GROUP nomedogrupo;
Exemplos:
CREATE GROUP adm;
83
SEGURANÇA DE BANCO DE DADOS
Exemplo:
ALTER GROUP adm ADD USER miriam, administrador;
ALTER GROUP adm DROP USER miriam;
Para excluir um grupo, basta usar o comando padrão para exclusão de objetos no
banco de dados, DROP. Lembrando que o comando DROP remove apenas o grupo e não os
usuários do grupo.
Exemplo:
DROP GROUP adm;
Nesta etapa é importante lembrar que o superusuário tem o direito de fazer o que bem
entender nos bancos de dados existentes. Outro aspecto é relativo ao proprietário de um objeto
no banco de dados. Sendo ele o dono do objeto ele também tem todas as permissões para
fazer o que bem entender com esse objeto.
São vários os privilégios que um usuário pode receber, dentre eles:
- SELECT - INSERT - UPDATE
- DELETE - RULE - REFERENCES
- TRIGGER - CREATE - TEMPORARY
- EXECUTE - USAGE - LOGIN
- CONNECT
Sintaxe:
GRANT privilégio ON objeto TO usuário;
REVOKE privilégio ON objeto FROM usuário;
Exemplos:
GRANT SELECT, INSERT, UPDATE ON cliente TO miriam;
84
SEGURANÇA DE BANCO DE DADOS
85
REFERÊNCIAS
REFERÊNCIAS
86