You are on page 1of 86

INTRODUÇÃO A SISTEMAS DE BANCO DE DADOS

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

objetivo deste material é apresentar a Structure Query Language como linguagem

O padrão para manipulação de bancos de dados relacionais, norteando o estudo de


banco de dados através de exemplos práticos aplicados a um Sistema Gerenciador de
Banco de Dados amplamente conhecido e utilizado, o PostgreSQL.
CELSO HENRIQUE PODEROSO DE OLIVEIRA, NAVATE e ELMASRI são referências
para os estudos traçados neste material. Dessa forma, o conteúdo apresentado certamente
poderá ser utilizado como referência na vida prática do profissional de computação que lida
diariamente com Banco de Dados.

Ricardo R. Barcelar
PROJETO FÍSICO DE BANCO DE DADOS

1
Parte

PROJETO FÍSICO DE BANCO DE DADOS

primeira etapa a fazer ao começa a trabalhar com banco de dados é estudar as técnicas

A utilizadas para se criar um projeto de banco de dados: Modelo Entidade-


Relacionamento, Modelo Lógico usando ferramenta Case, Normalização, Estratégias de
Projeto de Banco de Dados, etc.
Conhecedores dos conceitos de Codd, Chen, e outros autores que definiram o padrão
relacional para banco de dados, podem avançar mais um passo: implementar o banco de
dados em uma ferramenta apropriada. Mas antes, ainda é necessário conhecer alguns
conceitos do Projeto Físico e dos Sistemas Gerenciadores de Banco de Dados
especificamente.
O Modelo Físico de Dados é a especificação em SQL - Structure Query Language –
Linguagem de Consulta Estruturada - do esquema relacional para o Sistemas Gerenciadores
de Banco de Dados escolhido. Nesta fase, as estruturas de armazenamento e de recuperação
de informações, bem como os mecanismos de acesso devem ser escolhidos, visando sempre
o aprimoramento da performance dos aplicativos de Banco de Dados.
Nesta fase devem ser especificados não apenas as tabelas criadas, mas também os
índices necessários, as restrições de integridade (checks e triggers), algumas operações de
inclusão, exclusão e atualização de dados para cada tabela, bem como as consultas que a
aplicação deve realizar.

1.1 FATORES QUE INFLUENCIAM O PROJETO FÍSICO DE BANCO DE DADOS


Esta fase do projeto de BD objetiva não só propor uma apropriada estruturação de
dados, mas fazê-lo de maneira que garanta um bom desempenho. Sendo assim, não é
possível tomar decisões significativas sobre projetos físicos e análises de desempenho, até
que conheçamos as consultas, as transações e as aplicações que devem ser executadas no
banco de dados.
Dessa forma, vamos discutir alguns fatores:
a. Analisar as consultas e transações do Banco de Dados
É importante ter uma idéia das intenções de uso do banco de dados, definindo as
consultas e transações que esperamos que sejam realizadas em alto nível, especificando o
seguinte:
- Os arquivos que serão acessados pela consulta;

3
PROJETO FÍSICO DE BANCO DE DADOS

- Os atributos nos quais quaisquer condições de seleção para a consulta estejam


especificados;
- Os atributos nos quais quaisquer condições de junção ou condições para ligar
múltiplas tabelas ou objetos para a consulta estejam especificadas;
- Os atributos cujos valores serão trazidos através da consulta.
Para cada operação ou transação de atualização, devemos especificar o seguinte:
- Os arquivos que serão atualizados;
- O tipo de operação em cada arquivo (insert, update, delete)
- Os atributos nos quais condições de seleção para uma exclusão ou atualização
estejam especificados.
- Os atributos cujos valores serão alterados através de uma operação de atualização.
b. Analisar a freqüência esperada de solicitação (execução) de consultas e transações
É necessário considerar as taxas de solicitação (execução), usadas de forma estatísticas em
situações práticas para grandes volumes de processamento.
c. Analisar as restrições de tempo de consulta e transações
Neste caso, algumas consultas e transações podem ter rigorosas restrições de
desempenho. Por exemplo, uma transação que deve ser interrompida se não for concluída em
20 segundos
d. Analisar as freqüências esperadas de operações de atualização
Um número mínimo de caminhos de acesso aos dados deve ser especificado para um
arquivo que seja freqüentemente atualizado, uma vez que atualizar os próprios caminhos de
acesso desacelera as operações de atualização.
e. Analisar as restrições de Unicidade em Atributos
Caminhos de acesso aos dados devem ser especificados em todos os atributos
candidatos a chave ou chave primária. A existência de um índice facilita a pesquisa nos
arquivos de dados, pois este define um caminho de dados.
Realizadas as análises iniciais, outra decisão importante é definir qual Sistema
Gerenciador de Banco de Dados usar. É relevante levar em consideração vários fatores, como:
- O modelo físico, visto que determinará qual a carga de trabalho que será exigida pelo
SGBD, isso já eliminará algumas opções.
- O custo. Uma locadora, por exemplo, irá adquirir uma licença Oracle ou SQL Server?
- Plataforma de Sistema Operacional
Contudo, esta é uma decisão que não será analisada neste momento.

4
PROJETO FÍSICO DE BANCO DE DADOS

1.2 SQL - STRUCTURE QUERY LANGUAGE - LINGUAGEM ESTRUTURADA DE


CONSULTA
Como visto no módulo passado, é muito simples criar um script SQL através de uma
ferramenta Case. No entanto, este não será o foco desta sessão. Aqui aprenderemos a criar,
sem auxílio de ferramentas case, a gerar nosso script do Banco de Dados. Para tanto é
necessário conhecermos a linguagem SQL.
Apesar do nome, fazer consultas a bancos de dados não é a única função de SQL. Ela
é utilizada para criar tabelas, inserir, excluir e alterar dados do banco de dados, além de
outras utilizações.
A SQL foi desenvolvida na década de 70 pela IBM em uma das primeiras tentativas de
desenvolver um banco de dados relacional. Tornou-se padrão de fato depois de 1986, quando
a ANSI (American National Standards Institute) endossou como linguagem padrão para
Banco de Dados relacionais e desde então, o já sofreu três atualizações oficiais: em 1989,
1992 e 1999. Nesta última, algumas das mudanças mais significativas estão relacionadas com
a definição dos padrões para Banco de Dados Objeto-Relacionais.
Devido ao sucesso da forma de consultar e manipular dados da SQL, dentro de um
ambiente de banco de dados, a utilização da SQL foi se tornando ainda maior. Cabe ressaltar
que cada implementação de SQL possui uma adaptação da sintaxe para resolver determinados
problemas, portanto, qualquer comando mostrado pode ser usado de forma diferente em um
determinado Sistema Gerenciador de Banco de Dados.
Recomenda-se a leitura do manual do fabricante para maiores informações sobre o uso
da linguagem SQL em Sistema Gerenciador de Banco de Dados comerciais.
Atualmente, a linguagem SQL assume um papel muito importante nos sistemas de
gerenciamento de banco de dados, podendo ter muitos enfoques. Através de comandos SQL,
é possível montar consultas poderosas sem a necessidade da criação de um programa, ou
utilizar comandos SQL embutidos em programas de aplicação que acessam os dados
armazenados.
Devido ao fato de possuir várias aplicações, a linguagem SQL provê suporte a várias
funções. Que consiste em:
- DDL (Linguagem de definição de dados), onde os dados a serem armazenados são
definidos e estruturados; (Create, Alter e Drop).
- DML (Linguagem de manipulação de dados), que permite a inclusão, remoção,
seleção ou atualização de dados armazenados no banco de dados; Controle de acesso,
permitindo proteção dos dados de manipulações não autorizadas; (Select, Insert, UpDate,
Delete, Commit e Rollback).
- DCL (Linguagem de controle de dados) uma subclasse da DML responsável pelas
permissões de acesso ao banco; (Grant e Revoke).
Restrições de Integridade, que auxiliam no processo de definição da integridade dos dados,
protegendo contra corrupções, inconsistências e falhas do sistema de computação.
Além dessas características principais, ainda podemos citar:
- Visões, onde são especificadas as consultas disponíveis através de tabelas virtuais
(Views).

5
PROJETO FÍSICO DE BANCO DE DADOS

- Gatilhos a fim de automatizar processos no banco (Triggers).


Outra característica é a capacidade de cancelar uma série de atualizações ou gravar
depois de concluir uma série de atualizações.

1.3 CRIANDO UM BANCO DE DADOS


Esta etapa trata da Data Definition Language (DDL). O processo básico consiste
simplesmente em atribuir tipos de dado e tamanho para cada um dos atributos que foram
identificados.
Observação:
- Cada SGBD adota um terminador de comando. O mais comum é o ponto e vírgula (;)
- Quanto aos comandos apresentados, os SGBD não são sensíveis a letras maiúsculas
ou minúsculas. Contudo, o conteúdo das colunas normalmente é sensível, portanto muito
cuidado.

1.3.1 Desnormalização de dados


Em uma análise mais profunda, é muitas vezes conveniente avaliar a necessidade
alguns campos redundantes na tabela. Esse processo é chamado de desnormalização de
dados. Ocorre que quando idealizamos o modelo de dados, utilizamos o conceito de
processador perfeito, em que as informações são transmitidas sem custo instantaneamente.
Mesmo bancos de dados avançados possuem limitações.
Esta técnica pode ser exemplificada pelo caso dos campos calculados que são
eliminados na 3ª Forma normal. Quando se tem um grande banco de dados que trata de Notas
Fiscais, por questões de performance costuma-se “driblar” um pouco a regra e coloca-se o
valor total da nota como um campo na tabela. Isso pode ser feito quando o banco de dados
possui mecanismo de controle de transações, em que uma eventual gravação no banco de
dados implique necessariamente a gravação na outra ponta. Esta operação deve ser feita por
meio de gatilhos (triggers) para garantir a integridade das informações.
1.3.2 Definição de dados
Antes de criar as tabelas no nosso banco de dados, temos que definir quais são as
características de cada um dos campos. As características que o SQL exige são o tipo do dado
e o tamanho de cada campo. As informações aqui apresentadas são utilizadas pela maioria
dos bancos de dados. Eventuais mudanças devem ser consultadas na documentação do
Banco de dados adotado.
TIPO DE DADO DESCRIÇÃO
Número positivo ou negativo inteiro. O número de bytes utilizado varia de
Integer ou Int
acordo com o banco de dados utilizado.
Smallint Mesma função do Inteiro, mas ocupa cerca da metade do espaço
Número positivo ou negativo de ponto flutuante. Deve-se informar
Numeric
tamanho do campo e a quantidade de casas decimais.

6
PROJETO FÍSICO DE BANCO DE DADOS

Semelhante ao Numeric, mas, em alguns bancos de dados, poderá ter


Decimal
uma maior precisão após a vírgula.
Número de ponto flutuante de simples precisão. A diferença básica é que
Real os valores serão armazenados em representação exponencial, portanto
será arredondado para o nível mais próximo de precisão.
Número de ponto flutuante de dupla precisão. Comporta-se como o Real,
Double Precision
mas permite maior aproximação de resultados.
Número de ponto flutuante em que você define o nível de precisão
Float
(número de dígitos significativos)
Armazenamento de um número fixo de bits. O número de bits deve ser
Bit
indicado, do contrário o padrão será 1.
Igual ao Bit, permitindo armazenar valores maiores. Normalmente, utiliza-
Bit Varying
se para armazenar imagens.
Date Permite armazenar datas
Time Permite armazenar horários
Timestamp Permite armazenar uma combinação de data e hora
Permite armazenar cadeias de caracteres (letras, símbolos e números). O
Character ou char tamanho informado é fixo e indica o tamanho máximo da cadeia de
caracteres.
Permite armazenar cadeias de caracteres, mas com tamanho variável.
Character Varying Neste caso, especifica-se o tamanho máximo da coluna. Se for utilizado
ou Varchar menos espaço que o máximo definido, o espaço restante não será
ocupado.
Interval Intervalo de data ou hora

1.3.3 Adaptando o modelo de dados


Com base nas informações acima, adaptaremos nosso modelo de dados. Para nossos
estudos usaremos o modelo lógico abaixo:

7
PROJETO FÍSICO DE BANCO DE DADOS

Figura 1- Modelo de dados

Notação dos relacionamentos

1:n – FK obrigatória. Parte da chave primária

1:n – FK não obrigatória

n:m – Muitos para muitos (cria-se a tabela associativa)

1.3.4 Criação de Tabelas


Tabelas são as estruturas mais importantes de um banco de dados. Nas tabelas estará
o conteúdo que representa cada objeto do mundo real.
As próprias tabelas criadas no banco de dados ficam armazenadas em tabelas internas
do gerenciador de banco de dados. É o chamado Dicionário 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);

1.3.5 Constraints – Integridade Referencial – Restrição de Integridade (RI)


Constraints são regras agregadas a colunas ou tabelas. Assim, pode-se definir um
campo como obrigatório ou não, ou aceitar apenas alguns valores predefinidos. No caso de
regras aplicadas a tabelas, tem-se a definição de chaves primárias (PK) e estrangeiras (FK).
Um bom Sistema Gerenciador de Banco de Dados deve evitar a entrada de informação
incorreta ou inconsistente em sua base de dados, garantindo, com isso, a qualidade da
informação inserida. Uma restrição de integridade (RI) é uma condição especificada no
esquema da base de dados para restringir a informação a ser armazenada.
As RI são especificadas e conferidas em dois momentos diferentes:
- Na especificação da RI: se dá na definição do esquema da base de dados pelo
usuário ou pelo administrador da base de dados (DBA);
- Na conferência da RI: é feita pelo banco de dados toda vez que uma relação é
modificada por uma aplicação sendo executada.

1.3.5.1 TIPOS DE CONSTRAINTS MAIS COMUNS


As constraints variam muito de um banco para outro.
a) Chave Primária: é a coluna identificadora de um registro na tabela. Para representá-
la basta acrescentar a palavra chave PRIMARY KEY seguida do nome da coluna.
Exemplo:
...
PRIMARY KEY (cliente_id),
...

b) Chave Estrangeira: é o campo que estabelece o relacionamento entre duas tabelas.


Dessa forma, deve-se especificar na tabela que contém a chave estrangeira quais são essas
colunas e a qual tabela está relacionada.
Ao determinar este tipo de relacionamento, fica garantida a integridade das
informações. Os valores presentes na coluna definida com chave estrangeira devem ter um
correspondente na outra tabela.

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:

CREATE TABLE funcionario (fun_id INTEGER, fun_nome VARCHAR(50),


fun_admissao DATE, dept_id INTEGER,
PRIMARY KEY (fun_id),
FOREIGN KEY (dept_id) REFERENCES departamento ON DELETE CASCADE ON
UPDATE NO ACTION

c) DEFAULT: Atribui um conteúdo padrão a uma coluna da tabela.

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,
...

f) CHECK: Definição de domínio: Um domínio é uma expressão de valores possíveis


para o conteúdo de uma coluna.
Exemplo:
...
sexo CHAR(1) CHECK (UPPER(sexo) = ‘M’ OR UPPER(sexo) = ‘F’),

1.3.6 Alteração da estrutura da tabela


Para alterar a estrutura de uma tabela, utilizamos o comando ALTER TABLE.

1.3.6.1 ACRESCENTAR NOVAS COLUNAS


O comando utilizado para acrescentar novas colunas é muito semelhante ao da criação
de colunas em uma tabela:
Sintaxe: Exemplo:
ALTER TABLE nome_da_tabela ADD ALTER TABLE departamento ADD
coluna1 tipo_de_dado constraint, dep_ramal NUMBER(4) UNIQUE
coluna2 tipo_de_dado constraint,
...

1.3.6.2 ACRESCENTAR NOVAS CONSTRAINTS


O comando utilizado para acrescentar novas constraints é muito semelhante ao da
criação de constraints em uma tabela:

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)

1.3.6.3 MODIFICAR COLUNAS


O comando utilizado para modificar qualquer característica de uma coluna.
Sintaxe: Exemplo:
ALTER TABLE nome_da_tabela ALTER TABLE departamento
MODIFY (nome-coluna tipo_dado MODIDY dep_ramal INTEGER NOT NULL
constraint)

Não é necessário repetir o que não estamos modificando.

1.3.6.4 EXCLUINDO ELEMENTOS


Pelo padrão SQL, deveria ser possível excluir colunas ou constraints de uma tabela.
Alguns bancos de dados não permitem a exclusão de colunas.
Sintaxe: Exemplo:
ALTER TABLE nome_da_tabela ALTER TABLE departamento
DELETE elemento DELETE dep_ramal

ALTER TABLE departamento


DELETE PRIMARY KEY

Abaixo um exemplo onde várias alterações estão sendo realizadas em um só comando:


ALTER TABLE fornecedores
ADD cgc NUMBER(14),
DROP tipofornecedor,
ADD CONSTRAINT ck_email CHECK (e_mail CONTAINING ‘@’ OR e_mail IS
NULL)

1.3.7 Eliminando uma Tabela


Para eliminar uma tabela do banco de dados, utilizamos o comando DROP TABLE
seguido do nome da tabela. Alguns bancos somente permitirão esta operação se esta não
estiver relacionada à outra tabela.

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

Q melhorem a performance na recuperação dos dados que lá serão armazenados.


Dentre várias técnicas existentes para melhorar a esta performance existe a criação de
índices.
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.

1.1 CRIAÇÃO DE ÍNDICE


O índice serve para prover um acesso rápido a linhas das tabelas. Por meio dele é
possível unir uma ou mais colunas por onde o acesso é mais freqüente.

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.

1.1.1 Quando Criar um Índice

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.

Quando criar índices?

a) Chaves Primárias: se o banco de dados não criá-las automaticamente, é necessário


fazê-lo manualmente.
b) Chave Estrangeira: é sempre recomendável criar, principalmente quando a tabela
que faz referência é muito grande.
c) Colunas utilizadas freqüentemente na cláusula WHERE ou JOIN do comando
SELECT.

Quando não criar índices?

a) Colunas com muitos valores iguais.


b) Colunas com muito conteúdo NULO (não inicializados).
c) Tabelas muito pequenas.

NOTA:
Sempre que uma consulta estiver muito lenta, verifique a possibilidade de criar índice
para facilitar a busca.

Para criar um índice, utilize a seguinte sintaxe:

Sintaxe: Exemplo:

CREATE INDEX nome_index CREATE INDEX idx_dep_nome


ON nome_tabela (coluna [ASC|DESC]) ON departamento(dep_nome)

CREATE INDEX idx_dep_varios


ON departamento(dep_nome,dep_ramal)

Para excluir um índice, utilize a seguinte sintaxe:

Sintaxe: Exemplo:

DROP INDEX nome_index DROP INDEX idx_dep_varios

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

1.2 ACESSO A DADOS EM UM SISTEMA GERENCIADOR DE BANCO DE DADOS


Para compreender melhor a utilização de índices é importante conhecer a estrutura de
acesso a dados em um Sistema Gerenciador de Banco de Dados.

Figura 2 - Organização de um SGBD

Neste contexto, observamos que os bancos de dados são armazenados fisicamente


como arquivos de registros, que são geralmente armazenados em discos magnéticos. Assim,
os meios de armazenamento formam uma hierarquia de armazenamento que inclui duas
categorias principais:
- Armazenamento Principal: Operados diretamente pela CPU, como a Memória
Principal e Memória Cache.
- Armazenamento Secundário: Inclui os discos magnéticos, óticos e fitas. Geralmente
possuem uma capacidade maior, porém são mais lentos e não podem ser acessados
diretamente pela CPU.

Figura 3 - Estrutura de armazenamento

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.

1.2.1 Organização dos dados em Memória Secundária

- 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 Ordenados: Melhor opção se os registros devem ser recuperados em


alguma ordem, ou quando somente uma porção contígua dos registros ordenados é
necessária.
Exemplo: Arquivo de dados, possivelmente ordenado, além de vários índices.

- 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.

Existem outras maneiras ou possibilidades para organizar arquivos, como árvores-B e


arquivos de registro mistos, que implementam relacionamentos entre registros de diferentes
tipos fisicamente como parte da estrutura de armazenamento.

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

1.3.1. Tipos de Índices

- Índices primários - baseado na chave de ordenação;


- Índices de agrupamentos (clustering) - baseado no campo de ordenação não-chave de
um arquivo;
- Índices secundários - baseado em qualquer campo não ordenado de um arquivo;
- Índices multiníveis;
- Árvores B e B+;
- Tabelas Hash;

Um dos mais antigos esquemas de índice utilizados em sistema de banco de dados é


chamado de arquivo indexado seqüencialmente, que são projetados para aplicações que
requerem tanto o processamento seqüencial de um arquivo inteiro quanto o acesso aleatório a
registros individuais.

Estes índices podem ser:

- Densos: É quando o número de entradas do índice é igual ao número de registros no


arquivo de dados. Cada registro no arquivo de índice contém o endereço de um registro no
arquivo de dados.
Ponteiros

Figura 4 - Índice denso sobre um arquivo de dados seqüenciais

- Esparços: Usa-se menos espaço de armazenamento que o índice denso ao custo de


um tempo um pouco maior para localizar um registro dada a sua chave. É quando o número de
entradas do índice é igual ao número de blocos do arquivo de dados. Apenas alguns
registros de dados são representados no arquivo de índices. Em geral, aponta para o 1º
registro de bloco.

18
ÍNDICE

Ponteiros
Figura 5 - Índice esparso sobre um arquivo de dados seqüenciais

1.3.1.1 ÍNDICE PRIMÁRIO

É 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

Figura 6 - Índice Primário

1.3.1.2 ÍNDICE DE AGRUPAMENTO (CLUSTERING)

Se os registros de um arquivo estiverem ordenados fisicamente por um campo que não


seja chave, ou seja, que não possui um valor distinto, esse campo é chamado de campo
clustering. Semelhante ao índice primário possui dois campos de ordenação, no entanto o
primeiro campo é do mesmo tipo do campo clustering e o segundo é um ponteiro para o bloco.
Neste sentido sempre há a reserva de um bloco inteiro para cada valor de campo clustering,
melhorando operações de inclusão e exclusão. Em simples palavras é um índice associado a
um campo não chave.
Utiliza índice esparço.

20
ÍNDICE

Figura 7 - Índice de Agrupamento

1.3.1.3 ÍNDICE SECUNDÁRIO

No índice secundário o campo de indexação é um campo não ordenado do arquivo de


dados. Pode haver muitos índices secundários para um mesmo arquivo.
Dois casos:
- O campo de indexação é um campo chave (às vezes chamado de chave secundária).
- O campo de indexação não é chave.

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.

Figura 8 - Índice Secundário

Outra possibilidade para índices secundários é a entrada de índice para um bloco de


dados onde a menor chave de pesquisa é nova, isto é, a chave não apareceu em um bloco
anterior;
Se não há chave de pesquisa nova no bloco, então sua entrada de índice contém a
única chave de pesquisa encontrada nesse bloco;
Pode-se encontrar os registros de uma chave de pesquisa K examinando-se o índice
para a primeira entrada cuja chave é:
- Igual a K
- Menor que K, mas a próxima chave é maior que K

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.

Figura 9 - Índice Secundário

22
ÍNDICE

Usa o índice esparso indicando a nova chave de pesquisa mais baixa em cada bloco.

ORGANIZANDO AS IDÉIAS:

Campos ordenados Campos não ordenados


Campo chave Índice primário Índice Secundário (chave)
Campo não chave Índice de agrupamento Índice Secundário (não
chave)

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

1.3.1.4 ÍNDICES MULTINÍVEIS

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.

Figura 10 - Índices Multiníveis

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.

Figura 11 - Índice Primário de dois Níveis

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.

a) Gerenciamento de Índices nas Modificações de Dados

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

Árvores B e B+ são casos especiais de estruturas de dados bastantes conhecidas do


tipo árvore. Uma árvore é formada por nós, e cada nó na árvore, exceto um nó especial
denominado raiz, possui um nó pai e diversos nós filhos. Um nó que não possui filhos é
chamado de nó folha.
Um modo de implementar uma árvore é possuir tantos ponteiros em cada nó quantos
forem os nós filhos daquele nó. E para percorrer todos os nós, da árvore e da sub-árvore é
necessário fazer uso da recursividade.

Figura 12 - Árvore de Grau 3

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

Figura 13 - Distribuição nos nós

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

As vantagens da árvore B são:


- Melhor desempenho por ter um número menor de nós do que uma árvore binária. Por
exemplo: Menos nós significa menos altura que resulta em menos acessos ao disco.
- Por garantir poucos ponteiros entre os nós, há uma economia de espaço.
- Maior rapidez em buscas pela utilização de chaves primárias.
- Sua estrutura é dinâmica, ajustando automaticamente o balanceamento da árvore, a
cada inclusão/exclusão.
- Permite um tempo de acesso de dados menor, em uma busca aleatória, por causa de
suas ramificações.

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:

Figura 14 - Operações na árvore

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

Longas cadeias de transbordo podem desenvolver-se e degradar o desempenho.

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

Diferente do hashing estático a função hash é modificada dinamicamente para


acomodar o crescimento ou encolhimento do banco de dados, usando o hashing extensível.

c) Hashing Extensível

Divide e une os buckets enquanto o banco de dados cresce e encurta. A Eficiência do


espaço é mantida e a função hash gera valores por intervalos relativamente grandes. Outra
característica é que os buckets são criados por demanda.

29
DATA MANIPULATION LANGUAGE - DML

3
Parte

DATA MANIPULATION LANGUAGE - DML

ma vez criada a estrutura física do banco de dados é necessário popular as tabelas.

U Para isso utilizam-se os comandos da DML (Data Manipulation Language). Nesta seara
encontramos comandos como Insert, Update, Delete, Commit e Rollback.

DML(Linguagem de Manipulação de Dados):


Permite a inclusão, remoção, seleção ou atualização de dados armazenados no banco
de dados; Controle de acesso, permitindo proteção dos dados de manipulações não
autorizadas;

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.

3.1.1 Inserindo Várias Linhas

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

INSERT INTO autor (aut_id, aut_nome) VALUES (1, ‘Renato Russo’);


INSERT INTO autor (aut_id, aut_nome) VALUES (2, ‘Ton Jobim’);
INSERT INTO musica (mus_id, mus_nome, mus_duracao) VALUES (1,
‘sera’, ‘00:02:28’);
INSERT INTO musica (mus_id, mus_nome, mus_duracao) VALUES (2, ‘Ainda
é Cedo’, ‘00:03:55’);
INSERT INTO gravadora (grav_id, grav_nome, grav_tel, grav_contato)
VALUES (1, ‘EMI’, ‘1122334455’, ‘José Vitor’);
INSERT INTO cd(cd_id, cd_nome, cd_preco, dt_lancamento, grav_id)
VALUES (1, ‘Mais do Mesmo’, 20.50, ’21.12.1998’, 1);

31
DATA MANIPULATION LANGUAGE - DML

3.1.3 Exercícios

a) Popule as tabelas do banco de dados conforme representado abaixo:

ATENÇÃO:
Observe a sequência de inserção dos dados.

3.2 UPDATE

Comando responsável alteração de ou um mais registros na tabela de Banco de Dados.

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

Se quisermos alterar o preço de um CD, podemos utilizar o seguinte comando filtrando


na cláusula WHERE a chave primária da tabela CD:

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

Comando responsável pela exclusão de ou um mais registros na tabela de Banco de


Dados.

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.4 CONTROLE BÁSICO DE TRANSAÇÕES

Uma vez realizadas as operações de inclusão, alteração e exclusão, a modificação


realizada não estará ainda no banco de dados. Ela é visível apenas na seção atual.
Para que os comandos de Insert, Update e Delete sejam enviados para o banco é
necessário utilizar os comandos COMMIT ou descartados pelo comando ROLLBACK.

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;

Neste caso todos os CD‟s da gravadora 2 serão excluídos:

Exemplo:
DELETE FROM cd WHERE grav_id = 2;

34
PESQUISA BÁSICA EM T ABELAS

4
Parte

PESQUISA BÁSICA EM TABELAS

gora que já sabemos criar, incluir, alterar e excluir informações nas tabelas, veja como

A podemos extrair informações do banco de dados. Para tanto o comando utilizado é o


SELECT. Junto dele há uma imensa possibilidade de comandos como veremos a
seguir.

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:

SELECT * FROM cd;

O exemplo a seguir demonstra como filtrar apenas algumas colunas da tabela:

SELECT cd_id, cd_nome FROM cd;


SELECT grav_id, grav_nome, grav_tel FROM gravadora;

35
PESQUISA BÁSICA EM T ABELAS

4.1.1 Ordenando o resultado

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;

SELECT cd_id, cd_nome FROM cd


ORDER BY cd_id;

Se forem especificadas mais de uma coluna a ser ordenada o gerenciador primeiro


ordenara pela primeira coluna e em seguida pelas demais:

Exemplo:
SELECT grav_id, cd_nome FROM cd
ORDER BY grav_id, cd_nome;

4.1.2. Filtrando linhas

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

Para um resultado satisfatório devemos saber exatamente como construir condições


que satisfaçam às nossas necessidades de busca para atingir nossos objetivos. Sempre que a
condição especificada for verdadeira o resultado será mostrado. Para tanto é necessário
utilizar-se de alguns operadores como veremos a seguir.

4.1.2.1 OPERADORES RELACIONAIS

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.

OPERADOR SIGNIFICADO EXEMPLO


= Igual aut_id = 2
< Menos que cd_preco < 10
<= Menor ou igual a cd_preco <= 10

36
PESQUISA BÁSICA EM T ABELAS

> Maior que cd_preco > 10


>= Maior ou igual a cd_preco <= 10
!= ou <> Diferente aut_id != 2 ou aut_id <> 2

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.

4.1.2.2 OPERADORES LÓGICOS

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.

OPERADOR SIGNIFICADO EXEMPLO


AND e Condição-1 AND Condição-2
OR ou Condição-1 OR Condição-2
NOT ou ! não/negação NOT Condição

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);

4.1.2.3 OPERADORES ESPECIAIS

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%';

SELECT * FROM gravadora


WHERE grav_nome LIKE '_o%';

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) ;

Sua maior utilização são em subquerys (será visto posteriormente).

4.2. EXERCÍCIOS

a) Liste todos os campos e linhas da tabela GRAVADORA;

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;

d) Repita o comando anterior em ordem alfabética decrescente;

e) Liste todos os CDs da gravadora 3;

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;

g) Liste as colunas da tabela gravadora cujo GRAV_CONTATO seja nulo;

h) Repita o comando anterior desta vez listando GRAV_CONTADO não nulo;

i) Liste os CD‟s cujos CD_PRECO esteja entre 15,00 e 30,00;

j) Liste todos os CD‟s cuja CD_DT_LANCAMENTO seja posterior ao ano 01/01/2000;

k) Liste as MUSICAS cujo nome comece com A da tabela MUSICA;

l) Liste os CD‟s cuja segunda letra do CD_NOME seja a letra E;

m) Liste os CD‟s que possuam a letra O em qualquer posição do CD_NOME;

n) Liste os CD‟s que possuam CD_PRECO inferior a 30,00 em ordem decrescente de


CD_DT_LANCAMENTO;

o) Liste as músicas cuja MUS_ID seja 1, 3, 5;

40
CÁLCULOS E FUNÇÕES USUAIS

5
Parte

CÁLCULOS E FUNÇÕES USUAIS

m recurso bastante útil e importante de SQL é a possibilidade de se realizar cálculos e

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.

Um aumento de 5% em todos os CD‟s:

SELECT cd_id, cd_nome, cd_preco, preco_venda * 1.05


FROM cd;

Em alguns Sistemas Gerenciadores de Banco de Dados existem outras funções além


das aritméticas, como a função POWER do Oracle e Sysbase que permite calcular
exponenciação.

5.1 OPERADORES
Estes são os operadores utilizados no SQL:

OPERADOR SIGNIFICADO

+ Soma
- Subtração

* Multiplicação

/ Divisão

A precedência é igual a da matemática, ou seja, a multiplicação e a divisão têm prioridade


sobre a soma e subtração.
Para alterar a prioridade deve-se utilizar parênteses (Operação).

Exemplo:
15 / 5 * 3, Resultado = 9
15 / (5 * 3), Resultado = 1

SELECT cd_id, cd_nome, cd_preco - (cd_preco * 0.10)


FROM cd

41
CÁLCULOS E FUNÇÕES USUAIS

5.1.1. CHARACTER_LENGTH / LENGTH

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’);

SELECT CHARACTER_LENGTH (cd_nome)


FROM cd
WHERE cd_id = 10;

5.1.2. Alfanuméricos

Em SQL é possível concatenar alfanuméricos e existem algumas funções para manipulá-los.


Para concatenar caracteres, utiliza-se dois pipes ( || ).

Exemplo:
SELECT grav_id || ' - ' || grav_contato
FROM gravadora;

5.1.3. UPPER e LOWER

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’;

SELECT UPPER(aut_nome) FROM autor;

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;

5.1.5. Manipulação de Datas

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

O padrão SQL definiu algumas funções acrescentando CURRENT_:


- CURRENT_DATE
- CURRENT_TIME
- CURRENT_TIMESTAMP

Exemplos:
SELECT * FROM cd
WHERE cd_dt_lancamento = CURRENT_DATE;

Para saber a quantidade de dias que já se passaram depois do lançamento do CD usaríamos o


comando:

SELECT CURRENT_DATE, cd_dt_lancamento, (CURRENT_DATE –


cd_dt_lancamento) FROM cd

Adicionar dias em uma data:

SELECT cd_dt_lancamento + 7 FROM cd;

SELECT cd_dt_lancamento + INTERVAL ‘7 DAY’


FROM cd;

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;

SELECT cd_dt_lancamento, EXTRACT(DAY 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.

SELECT cd_dt_lancamento, CAST(EXTRACT(MONTH FROM

43
CÁLCULOS E FUNÇÕES USUAIS

cd_dt_lancamento) AS VARCHAR) ||'/'||


CAST(EXTRACT(DAY FROM cd_dt_lancamento) AS VARCHAR) FROM cd;

5.2. EXERCÍCIOS

a. Monte uma pesquisa que mostre a data atual.

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.

f. Escreva uma busca que mostre a primeira letra da MUS_NOME e a MUS_DURACAO da


tabela música.

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.

i. Escreva uma busca que retorne o ano de lançamento do CD_ID = 1, 2 e 3;

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

PESQUISA EM MÚLTIPLAS TABELAS

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.

Figura 16 - Modelo Lógico de Dados

45
PESQUISA EM MÚLTIPLAS T ABELAS

6.1. ALIAS

Ao realizar pesquisa em diversas tabelas são referenciadas colunas pertencentes às


tabelas da relação. Dessa forma, é necessário distinguir a qual tabela pertence à dada coluna.
Podemos fazer isso de duas formas:
a) Colocando o nome da tabela na frente do nome da coluna.

Sintaxe:
SELECT tabela.coluna
FROM tabela;

b) Utilizando um alias ou apelido para a tabela e colocando-o na frente da coluna.

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;

6.2. UNIÃO DE TABELAS

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

6.3. PRODUTO CARTESIANO

Ocorrerá um produto cartesiano sempre que:


- A condição de união entre as tabelas for omitida (não houver cláusula WHERE);
- Condição de união entre as tabelas for inválida (cláusula WHERE incorreta);
- Todas as linhas da primeira tabela estiverem unidas a todas as linhas da segunda
tabela.
- Nesta situação, as linhas da primeira tabela serão combinadas com as linhas da
segunda, demonstrando um resultado na maior parte das vezes indesejado.
- Esse procedimento é muito utilizado para efetuar testes de performance no banco
devido a grande quantidade dedados.

Exemplo:
SELECT cd.cd_id, cd.cd_nome, gravadora.grav_nome
FROM gravadora, cd

Ao invés de se mostrar todos os dados, deseja-se visualizar os CD‟s e suas respectivas


gravadoras. Emprega-se então, a União entre tabelas.

Exemplo:
SELECT cd.cd_id, cd.cd_nome, gravadora.grav_nome
FROM gravadora, cd
WHERE cd.grav_id = gravadora.grav_id

Usando alias:

SELECT c.cd_id, c.cd_nome, g.grav_nome


FROM gravadora g, cd c
WHERE c.grav_id = g.grav_id

6.4. UNIÃO REGULAR (INNER JOIN OU EQUI-JOIN)

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);

SELECT cd.cd_id, cd.cd_nome, gravadora.grav_nome


FROM cd JOIN gravadora ON gravadora.grav_id = cd.grav_id;

6.5. UNIÃO DE M AIS DE DUAS TABELAS

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

O código abaixo produziria o mesmo efeito:


SELECT c.cd_nome, f.fai_numero, m.mus_nome
FROM faixa f
INNER JOIN cd c ON c.cd_id = f.cd_id
INNER JOIN musica m ON 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

6.6. UNIÕES EXTERNAS (OUTER-JOIN)

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

No resultado observamos que alguns dados de gravadora são omitidos.


Define-se União Externa como aquela que inclui linhas no resultado da busca mesmo
que não haja relação entre as duas tabelas.
Para que os dados omitidos sejam mostrados utilizaremos o comando SELECT
utilizando União Externa.

6.6.1. União Externa à Esquerda (Left Outer-Join)

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.

6.6.2. União Externa à Direita (Right Outer-join)

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.

6.6.3. União Externa Total (Full Outer-join)

Realiza uma união independente da coluna opcional estar à direita ou à esquerda.


Neste caso, são geradas linhas que não existem em uma ou em ambas 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.

f. Acrescente a pesquisa anterior o nome do CD que foi gravado a música.

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

FUNÇÕES DE GRUPO E AGRUPAMENTO

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.

7.1. FUNÇÕES DE GRUPO

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;

Efeito semelhante pode ser conseguido com o seguinte comando:

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;

Outra maneira é utilizando o comando DISTINCT. Observe a diferença entre os dois


comandos:

Exemplos:
SELECT COUNT(DISTINCT aut_id)
FROM musica_autor;

SELECT COUNT(aut_id)
FROM musica_autor;

7.1.2. SUM

Retorna o valor total de uma determinada coluna em um determinado grupo de linhas.

Assim se quisermos saber o total do preço de venda dos CD‟s, utilizamos o comando:

Exemplo:
SELECT SUM(cd_preco)
FROM cd;

É possível realizar cálculos baseados na somatória ou mesmo incluir outras colunas e


operações no comando.

Exemplo:
SELECT SUM(cd_preco) * 1.2
FROM cd;

7.1.3. AVG

Extrai a média aritmética de um determinado grupo de linhas.

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

Retorna o menor valor de uma coluna em um grupo de linhas. Podemos utilizá-la em


colunas do tipo data ou alfanuméricas.

Para saber o preço de venda do CD mais barato execute o seguinte comando:

Exemplos:
SELECT MIN(cd_preco)
FROM cd;

SELECT MIN(cd_dt_lancamento)
FROM cd;

SELECT MIN(cd_nome)
FROM cd;

7.1.5. MAX

Retorna o maior valor de uma coluna em um grupo de linhas. Podemos utilizá-la em


colunas do tipo data ou alfanuméricas.

Para saber o preço de venda do CD mais caro execute o seguinte comando:

Exemplos:
SELECT MAX(cd_preco)
FROM cd;

SELECT MAX(cd_dt_lancamento)
FROM cd;

SELECT MAX(cd_nome)
FROM cd;

7.1.6. STDDEV (Não funciona em alguns bancos de dados.)

Retorna o desvio padrão de uma determinada coluna.


Para saber o desvio padrão dos preços de venda dos CD‟s da loja execute o seguinte
comando:

Exemplo:
SELECT STDDEV(cd_preco)
FROM cd;

7.1.7. VARIANCE (Não funciona em alguns bancos de dados.)

Retorna a variância de uma determinada coluna.

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. AGRUPANDO RESULTADOS

É possível agrupar valores com base em determinadas colunas. Desta forma,


estaremos trabalhando um pequeno grupo de dados. Para isso usamos a cláusula GROUP BY.

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).

Para saber quantas músicas há em cada CD:

Exemplo:
SELECT cd_id, COUNT(*)
FROM faixa
GROUP BY cd_id;

Para o preço médio de venda de cada CD agrupado por gravadora:

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;

7.3. AGRUPAMENTOS COM MAIS DE UMA TABELA

Podemos unir mais de uma tabela com as regras já citadas.

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

7.4. RESTRINGINDO O RESULTADO

Em algumas situações os dados agrupados podem ser restringidos ou filtrados. Até


agora vimos que toda tabela era afetada pelo comando GROUP BY. Contudo, nem sempre
isso é desejável.
Para isso podemos utilizar a cláusula WHERE em conjunto com GROUP BY ou utilizar
a cláusula HAVING.
Retornar o total de autores agrupados por MUS_ID sendo este menor que 3:

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

Usando o filtro da cláusula WHERE as linhas são filtradas antes do agrupamento;


Usando HAVING, as linhas são filtradas depois do agrupamento.
A única restrição é que a cláusula HAVING só pode usar as colunas que fazem parte do
GROUP BY. Para o WHERE isso não acontece.
Nunca use na cláusula WHERE uma função de grupo para filtrar os grupos. Dessa forma, o
comando abaixo é inválido:

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

A forma correta seria:


SELECT grav_id, AVG(cd_preco) FROM cd
GROUP BY grav_id
HAVING AVG(cd_preco) > 12

7.5. EXERCÍCIOS

a. Verifique o maior e menor valor entre os preços de venda dos CD‟s.

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;

d. Mostre através de uma consulta o tempo total do CD 1 (cd_id = 1);

e. Mostre através de uma consulta a média de duração das músicas cujo nome comece
com a letra A;

f. Faça uma consulta que retorne a quantidade de CD‟s cadastrados.

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

As subqueries fazem parte do padrão SQL-86 logo, todos os bancos de dados


relacionais que utilizam SQL devem permitir essa utilização.

Sintaxe:
SELECT colunas
FROM tabela
WHERE expressão operador (SELECT colunas FROM tabela
WHERE ...)

Há três tipos de subquery:


a) Subquery de uma linha: o retorno do SELECT interno será uma única linha.
b) Subquery de múltiplas linhas: o retorno do SELECT interno será mais de uma
linha.
c) Subquery de múltiplas colunas: o retorno do SELECT interno será conterá mais de
uma linha e coluna.

8.1.1. Subquery de uma linha

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);

8.1.1.1. SUBQUERY EM CLÁUSULA HAVING

A utilização é semelhante a cláusula WHERE. A subquery será executada primeiro e o


resultado da busca servirá de base para filtrar as linhas do GROUP BY.

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)

SELECT grav_id, MAX(cd_preco) FROM cd c


GROUP BY grav_id
HAVING MAX(cd_preco) > (SELECT AVG(cd_preco) FROM cd
WHERE grav_id = c.grav_id)

58
SUBCONSULTAS

8.1.1.2. COMANDO EXISTS

Verifica o número de linhas retornadas pela subquery. Caso contenha uma ou mais
linhas, então o resultado será mostrado.

Exemplo:

SELECT grav_id, grav_nome FROM gravadora


WHERE EXISTS (SELECT * FROM cd
WHERE cd.grav_id = gravadora.grav_id)

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.

8.1.2. Subquery de múltiplas linhas

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.

SELECT MIN(cd_preco) FROM cd


GROUP BY grav_id

Para saber quais são os CD‟s escreveríamos o seguinte comando:

SELECT cd_id, cd_nome, cd_preco FROM cd


WHERE cd_preco IN (19, 23, 11)

Para fazer isso em um único comando, escreveríamos o comando da seguinte forma:

SELECT cd_id, cd_nome, cd_preco FROM cd


WHERE cd_preco IN (SELECT MIN(cd_preco) FROM cd
GROUP BY grav_id)

59
SUBCONSULTAS

8.1.2.2. ANY (Compara com qualquer valor)

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:

SELECT cd_id, cd_nome, cd_preco FROM cd


WHERE grav_id != 2

Depois precisamos saber quais os preços dos CD‟s da gravadora 2 com o comando da
seguinte forma:

SELECT cd_preco FROM cd


WHERE grav_id = 2

Agora realizamos a pesquisa na tabela de CD para comparar os preços inferiores a


esses:

SELECT cd_id, cd_nome, cd_preco FROM cd


WHERE cd_preco < ANY (SELECT cd_preco FROM cd
WHERE grav_id = 2)
AND grav_id != 2

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:

SELECT AVG(cd_preco) FROM cd


GROUP BY grav_id;

Depois verificamos quais são os CD‟s com preço inferior a todos anteriores.

SELECT cd_id, cd_nome, cd_preco FROM cd


WHERE cd_preco < ALL (SELECT AVG(cd_preco) FROM cd
GROUP BY grav_id)

60
SUBCONSULTAS

8.1.3. Subquery de múltiplas colunas

A técnica consiste em colocar as colunas unidas na cláusula WHERE do SELECT


externo e realizar a busca no SELECT interno dessas colunas unidas da mesma forma. Essa
técnica tende a ser muito lenta, mas pode ser feita em qualquer banco de dados.
Temos vários CD‟s indicados no cadastro e queremos conhecer os dados do CD dentre
os menores CD‟s indicados de cada gravadora. Para isso temos que saber o menor CD
indicado de cada gravadora. Utilizamos o || para unir as colunas.

Exemplo:
SELECT grav_id || cast(MIN(cd_indicado) as varchar)
FROM cd
GROUP BY grav_id

Agora realizamos a busca dos dados que atendem essas características:

SELECT cd_id, cd_nome, grav_id, cd_indicado


FROM cd
WHERE (grav_id || cast (cd_indicado as varchar)) IN
(SELECT grav_id || cast(MIN(cd_indicado) as varchar) FROM cd
GROUP BY grav_id)

Outra técnica consiste em colocar as colunas de busca entre parênteses no SELECT


externo, entretanto não está disponível em alguns bancos de dados.

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.

8.1.4. Subquery na Cláusula FROM

Podemos utilizar uma subquery na cláusula FROM de um comando SELECT.


Essa estrutura não está disponível para todos os bancos de dados, mas faz parte do
padrão SQL. Sua utilização é muito parecida com as visões (Views).
Imagine que queremos extrair o nome do CD, seu preço e o preço médio da gravadora,
e o preço médio da gravadora é extraído por uma subquery na própria cláusula FROM:

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

As visões podem ser classificadas de duas formas:

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

9.2. CRIAÇÃO DA VISÃO

Para criar uma visão, utilizamos o comando CREATE VIEW:

Sintaxe:
CREATE VIEW nome
AS query/subquery

Exemplo:
CREATE VIEW vCD AS
SELECT cd_id, cd_nome, cd_preco FROM cd;

Como visto anteriormente esta é uma visão simples.


Como uma visão é sempre baseada em um comando SELECT, podemos criar visões
extremamente complexas.

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)

CREATE VIEW vCD_FAIXA AS


SELECT cd_id, item_faixa FROM item_cd
WHERE mus_id IN (SELECT mus_id FROM musica
WHERE UPPER(mus_nome) LIKE ‘%A’)

CREATE VIEW VGRAV_MAX AS


SELECT grav_id, cd_preco FROM cd a
WHERE cd_preco > (SELECT AVG(cd_preco) FROM cd
WHERE grav_id = a.grav_id)

9.3. BUSCANDO CONTEÚDO DE VISÕES

Utilizamos o comando SELECT para buscar o conteúdo de visões exatamente como


fazemos com qualquer tabela.

Exemplo:
SELECT * FROM vCD;
SELECT * FROM vCD_FAIXA;

Podemos, ainda, incluir qualquer outra cláusula do comando SELECT, mesmo em


pesquisa realizadas em visões.

64
VISÕES/VIEW

Exemplo:
SELECT * FROM VPRECO_CD
WHERE cd_preco > 8;

9.4. UTILIZAÇÃO DE COMANDOS DML EM VISÕES

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.

9.5. EXCLUINDO UMA VISÃO

Para excluir uma visão, utilizamos o comando DROP VIEW;


Ao excluir uma visão não estamos excluindo os dados (linhas e colunas), visto que é
apenas uma tabela virtual.

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.

b) Crie uma visão que mostre os CD‟s e suas respectivas gravadoras.

c) Crie uma visão que mostre as músicas e seus respectivos autores.

d) Construa uma visão que mostre as músicas sua duração e a que CD pertence.

e) Construa uma visão que mostre os autores e em quais gravadoras possuem CD


gravado.

65
PROCEDIMENTOS ARMAZENADOS/STORED PROCEDURES

10
Parte

PROCEDIMENTOS ARMAZENADOS

m muitas situações será necessário armazenar procedimentos escritos com a finalidade

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).

10.1. VANTAGENS DO USO DE STORED PROCEDURES

- Redução de tráfico de rede.


- Aumenta a performance da aplicação, particularmente em uma WAN ou em uma
conexão de baixa velocidade.
- Utilizando stored procedure, elimina-se o processo de “parsed”, ou seja, da query ter
que ser analisada gramaticalmente e submetido ao otimizador para formulação de um plano de
execução.
- São analisadas, otimizadas e armazenadas em uma forma executável no momento em
que são adicionadas ao banco de dados.
- É possível executar operações muito mais complexas que uma simples query.
- Pode ser usada por aplicações distintas.
- Facilita a manutenção, pois é possível alterá-la sem ter que recompilar a aplicação.
- Proporciona mais segurança ao banco de dados, acessando tabelas que o usuário
não tem acesso.

10.2. QUANDO USAR STORED PROCEDURES

- Sempre que a metodologia de desenvolvimento do software permitir.


- Não existem desvantagens em usar procedimentos armazenados, entretanto existem
duas limitações:
- Deve ser possível passar qualquer informação variável para a stored procedure
(parâmetros).
- Operações complexas podem ser limitadas.

66
PROCEDIMENTOS ARMAZENADOS/STORED PROCEDURES

10.3. STORED PROCEDURES NO POSTGRESQL

Como visto, Stored Procedures são programas desenvolvidos em determinada


linguagem de script e armazenados no servidor, local onde serão processados. Também são
conhecidos como funções, este o motivo pelo qual as Stored Procedures no PostgreSQL são
referenciadas como Function.
O PostgreSQL conta com três formas diferentes de criar funções:
a) Funções em Linguagem SQL: São funções que utilizam a sintaxe SQL e se
caracterizam por não possuírem estruturas de condição (if, else, case), estruturas de repetição
(while, do while, for), não permitirem a criação de variáveis e utilizam sempre algum dos
seguintes comandos SQL: SELECT, INSERT, DELETE ou UPDATE.

b) Funções de Linguagens Procedurais: Ao contrário das funções SQL, aqui é


permitido o uso de estruturas de condição e repetição e o uso de variáveis. As funções em
linguagens procedurais caracterizam-se também por não possuírem apenas uma possibilidade
de linguagem, mas várias. Normalmente a mais utilizada é conhecida como PL/PgSQL,
linguagem semelhante ao conhecido PL/SQL da Oracle. Existem outras linguagens como, por
exemplo, o PL/Perl, PL/Python e PL/Tcl, que possuem sintaxe igual ou semelhante às
linguagens que lhes deram origem.

c) Funções em Linguagens Externas ou de Rotinas Complexas: São funções


normalmente escritas em C++ que trazem consigo a vantagem de utilizarem uma linguagem
com diversos recursos, na qual pode-se implementar algoritmos com grande complexidade.
Tais funções são empacotadas e registradas no Sistema Gerenciador de Banco de Dados para
seu uso futuro.
Existem ainda outras linguagens como PL/Ruby, PL/sh e PL/Java, no entanto, estas são
definidas por projetos independentes. Dentre elas destacam-se as funções criadas com
PL/Java devido a sua crescente demanda entre usuários do PostgreSQL.
Para criar uma função utilizando SQL no PostgreSQL utiliza-se o comando CREATE
FUNCTION:

Sintaxe:
CREATE [OR REPLACE] FUNCTION nome ([tipo_do_parametro1],[...])
RETURNS tipo_retornado AS '
Implementação_da_função;
'
LANGUAGE 'SQL';

- CREATE FUNCTION é o comando que define a criação de uma função, [OR


REPLACE] informa que se acaso existir uma função com este nome, a atual função deverá
sobrescrever a antiga.
- RETURNS tipo_retornado informa o tipo de dado que será retornado ao término da
função. Tais tipos de retornos são os convencionais como o INTEGER, FLOAT, VARCHAR,
etc. As funções em SQL também permitem o retorno de múltiplos valores e para isso informa-
se como retorno SETOF. Na implementação haverá as linhas de programação para a
implementação da stored procedure.
- LANGUAGE indica para a função em qual linguagem ela está sendo implementada.

67
PROCEDIMENTOS ARMAZENADOS/STORED PROCEDURES

Na passagem de parâmetros à função não se utiliza o nome nas variáveis declaradas


nos parênteses da assinatura da função. Utiliza-se o tipo da variável de parâmetro separado
por vírgula. Para acessar o valor dos parâmetros, utiliza-se o $ mais o número da posição que
ocupa nos parâmetros, seguindo a ordem da esquerda para a direita.

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';

CREATE OR REPLACE FUNCTION cdGravados2(in INT, out f1 INT, out f2


TEXT, out f3 NUMERIC)
AS $$ SELECT CAST(cd_id as integer), CAST(cd_nome AS text),
CAST(cd_preco AS numeric)
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)

Para usar a função utiliza-se a cláusula SELECT.

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;

Passando o RESTRICT como parâmetro, a exclusão da função será recusada caso


existam dependências de objetos em torno da função (como por exemplo, Triggers e
operadores). Com o CASCADE esses objetos serão excluídos juntamente com a função.

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.

10.4.2. Elementos da Linguagem

A criação de Stored Procedures inclui todas as construções de uma linguagem de


programação estruturada, como:
- Comentários: -- Este é um comentário
- Bloco de comandos (BEGIN/END): É possível usar construções como IF-THEN-ELSE
e loops WHILE que somente podem conter um comando.
- Comandos de atribuição: var1 := var2 * var3
- Operador de concatenação: || (duas barras verticais)
Além desses elementos é possível usar as expressões condicionais:
- BETWEEN
- LIKE IN
- EXISTS
- ANY
- ALL
- IS NULL
- IS NOT NULL

10.4.3. Estrutura da Linguagem

A PL/pgSQL é estruturada em blocos, assim, todo o texto de definição de uma função


precisa estar em um bloco.

Sintaxe:
[<<label>>]
[DECLARE
declarações]
BEGIN
conteúdo 1;
conteúdo 2;
conteúdo n;
END;

70
PROCEDIMENTOS ARMAZENADOS/STORED PROCEDURES

- DECLARE é a área para declaração de variáveis. As variáveis declaradas nessa


sessão são inicializadas recebendo seus valores default sempre que existe uma entrada nesse
bloco. Como na maior parte das linguagens existentes, na PL/pgSQL, variáveis com o mesmo
nome possuem o seu escopo definido para o bloco imediatamente posterior à sua declaração.

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);

Como visto é possível usar as mesmas estruturas de controle disponíveis nas


linguagens de programação:

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');

Além de todos os recursos advindos da estrutura de programação é permitido fazer


interação com a estrutura do banco de dados nas operações da DML como no exemplo abaixo:

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;

SELECT alteraPreco(1, 16.5);


SELECT alteraPreco(2, 120);

As versões 8.3 e posteriores do PostgreSQL permitem o retorno de conjuntos de linhas


e colunas de uma função através da funcionalidade RETURN QUERY. O RETURN QUERY
aceita o tipo RECORD como valor de retorno tornando fácil retornar resultados de consultas
genéricas.

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;

A diferença desta forma de programar está na chamada da função. Ao utilizar valor de


retorno do tipo RECORD, deve ser indicada a lista de campos a serem retornados e seus tipos.
Esta pode ser vista como uma limitação, embora na prática também seja uma forma de se
garantir a confiabilidade dos resultados retornados na execução de comandos SQL dentro de
funções pela validação dos valores retornados.

Exemplo:
SELECT * FROM cd_grav(2) AS ( c1 VARCHAR(50), c2 VARCHAR(50) );

72
PROCEDIMENTOS ARMAZENADOS/STORED PROCEDURES

Esses são alguns recursos possíveis com Stored Procedures/Functions no PostgreSQL.


Contudo, é importante saber que existe um gama de outros recursos possíveis fazendo uso do
PgSQL, assim como acontece com outros bancos de dados, como o Oracle.

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

TRIGGERS (GATILHOS OU AUTOMATISMOS)

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.

A criação de uma trigger envolve duas etapas:


- Um comando SQL que vai disparar o Trigger (INSERT, DELETE, UPDATE)
- A ação que a trigger vai executar (Geralmente um bloco de códigos SQL)

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).

Uma trigger é executada automaticamente mediante seis eventos da DML:


- BEFORE UPDATE (Antes da atualização);
- AFTER UPDATE (Após a atualização);
- BEFORE INSERT (Antes da inserção);
- AFTER INSERT (Após a inserção);

74
TRIGGERS (G ATILHOS OU AUTOMATISMOS)

- BEFORE DELETE (Antes da exclusão);


- AFTER DELETE (Após a exclusão);

11.1. BEFORE OU UPDATE

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.

11.2. USANDO OLD E NEW

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

Com esses comandos é possível criar registros de histórico, calcular percentual de


alteração de valores, etc.

11.3. TRIGGERS NO POSTGRESQL

Um diferencial das triggers no PostgreSQL é que elas são sempre associadas a


funções de triggers e em outros Bancos de Dados elas são criadas no corpo da trigger.

11.3.1. Tipos de Triggers

O PostgreSQL possui dois tipos de triggers:


- Triggers-por-linha
- Triggers-por-instrução

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)

11.3.2. Funções de Trigger e Linguagens Procedurais

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;

Por fim, criando a trigger:

Exemplo:
CREATE TRIGGER tFormataCpf BEFORE INSERT
ON autor FOR EACH ROW
EXECUTE PROCEDURE ftFormataCPF ();

Verificando seu funcionamento:


INSERT INTO autor (aut_id, aut_nome, aut_cpf) VALUES (102, 'teste
function2', '00000000002');

11.3.3. Parâmetros Especiais

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:

CREATE TABLE historico_cd (


hcd_id INTEGER,
hcd_preco_novo NUMERIC(14,2),
hcd_preco_antigo NUMERIC(14,2),
hcd_data_hora TIMESTAMP,
hcd_operacao VARCHAR(50) );

77
TRIGGERS (G ATILHOS OU AUTOMATISMOS)

Depois criamos a função:

CREATE OR REPLACE FUNCTION auditaCD()


RETURNS trigger AS
$$
BEGIN
IF (TG_OP = 'INSERT') THEN
INSERT INTO historico_cd (hcd_id, hcd_preco_novo,
hcd_preco_antigo, hcd_data_hora, hcd_operacao) VALUES (NEW.cd_id,
NEW.cd_preco, NULL, CURRENT_TIMESTAMP, ‘INSERT’);
RETURN NEW;

ELSIF (TG_OP = 'UPDATE') THEN


INSERT INTO historico_cd (hcd_id, hcd_preco_novo,
hcd_preco_antigo, hcd_data_hora, hcd_operacao) VALUES (OLD.cd_id,
NEW.cd_preco, OLD.cd_preco, CURRENT_TIMESTAMP, ‘UPDATE’);
RETURN NEW;

ELSIF (TG_OP = 'DELETE') THEN


INSERT INTO historico_cd (hcd_id, hcd_preco_novo,
hcd_preco_antigo, hcd_data_hora, hcd_operacao) VALUES (OLD.cd_id,
NULL, OLD.cd_preco, CURRENT_TIMESTAMP, ‘DELETE’);
RETURN NEW;
END IF;
END;
$$
LANGUAGE plpgsql;

Por fim, criamos a Trigger:

CREATE TRIGGER tg_auditaCD AFTER INSERT OR UPDATE OR DELETE


ON cd
FOR EACH ROW EXECUTE PROCEDURE auditaCD();

Verificando seu funcionamento:

INSERT INTO cd (cd_id, grav_id, cd_nome, cd_preco,


cd_dt_lancamento) VALUES (100, 1, 'teste trigger1', 10.00, '2009-11-
15');
UPDATE cd SET cd_preco = 20.00 WHERE cd_id = 100;
DELETE FROM cd WHERE cd_id = 100;

11.3.4. Triggers Recursivas

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.

11.3.5. Alterando uma Trigger

É possível alterar o nome de trigger usando a sintaxe abaixo:

Sintaxe:
ALTER TRIGGER nome ON tabela RENAME TO novo_nome;

11.3.6. Excluindo uma Trigger

Para excluir uma trigiger basta executar o comando abaixo:

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).

11.3.7. Desabilitando/Habilitando uma Trigger

Para desabilitar/habilitar uma trigger execute o comando abaixo:

Sintaxe:
ALTER TABLE nome_tabela [DISABLE|ENABLE] TRIGGER nome_trigger;

Para desabilitar todas as triggers da tabela, execute o seguinte comando:

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

SEGURANÇA DE BANCO DE DADOS

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.

12.1. VISÃO DE SEGURANÇA

O Sistema Gerenciador de Banco de Dados deve fornecer ao usuário uma


representação conceitual dos dados (visão), sem fornecer muitos detalhes de como as
informações estão armazenadas.
Muitas verificações de autorização podem aplicar-se ao tempo de execução, entretanto
a abordagem de segurança de que se baseia uma visão é um tanto inábil, pois um usuário
pode precisar de direitos diferentes sobre subconjuntos diferentes da mesma tabela.
Existem muitos aspectos relativos aos problemas de segurança, dentre eles os
aspectos legais, sociais e éticos. O que deve ser analisado é se quem faz a solicitação da
informação tem direito legal sobre ela.
Outro aspecto a se analisar são os controles físicos. Considera-se a sala a sala do
servidor um lugar inviolável, pois lá estão todas as informações.
Para que o sistema seja capaz de decidir que limitações se aplicam a determinada
solicitação é necessário reconhecer a fonte daquela solicitação, isto é, deve ser capaz de
reconhecer de que usuário específico partiu aquela demanda. Neste sentido é necessário
atribuir mecanismos de autenticação para os responsáveis pela solicitação sejam identificados,
como um meio de garantir a auditoria sobre os feitos daquele usuário nos dados armazenados.

12.2. INSTRUÇÕES GRANT E REVOKE

O mecanismo de visão possibilita dividir o banco de dados em partes conceituais de


modo que a informação sensível fique oculta aos usuários não autorizados.
Por meio das instruções GRANT e REVOKE é possível atribuir restrições aos usuários
de acordo com um perfil previamente estabelecido. Esses representam a principal interface que

80
SEGURANÇA DE BANCO DE DADOS

concede ao usuário capacidade de desempenhar qualquer operação através de comandos


SQL.

12.3. OUTROS ASPECTOS DE SEGURANÇA

As visões e o mecanismo de GRANT e REVOKE não são os únicos meios de se


implementar segurança em banco de dados. Na verdade, não existe nenhum ponto no Sistema
Gerenciador de Banco de Dados que proporcione um conjunto amplo de controles de
segurança. Dessa forma, um suposto infiltrador suficientemente determinado é capaz de
passar por todos os controles já mencionados.
Para situações em que os dados sejam sensíveis, torna-se necessário um arquivo ou
banco de dados especial, onde o sistema registra automaticamente todas as operações
desempenhadas por determinado usuário. A isso chamamos de Log.
Outro nível de segurança pode ser proporcionado pela codificação de dados. A idéia
básica consiste no armazenamento físico dos dados no disco e antes de serem transmitidos
são codificados (Criptografados).

12.4. CRIAÇÃO DE USUÁRIOS NO POSTGRESQL

Para possibilitar a utilização da base de dados por usuários distintos, cada um


trabalhando em uma sessão diferente é necessário realizar a criação de um usuário no
Sistema Gerenciador de Banco de Dados atribuindo-lhe um nome para autenticação e senha.
A este usuário criado poderão ser concedidas permissões diversas assegurando-lhe acesso
aos dados, bem como concedendo e restringindo operações sobre as informações.
O comando usando no PostgreSQL para criar usuário é o CREATE USER. No entanto,
nas versões mais modernas é possível fazê-lo diretamente através do comando CREATE
ROLE, possibilitando a utilização de mais recursos.

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:

- Nome: O nome do usuário.


- id_do_usuário: A cláusula SYSID pode ser utilizada para escolher o identificador de
usuário do PostgreSQL do novo usuário. Normalmente não é necessário, mas pode ser útil se
for necessário recriar o dono de um objeto que ficou órfão. Se não for especificado, será
utilizado por padrão o maior identificador de usuário atribuído acrescido de um (com mínimo de
100).

81
SEGURANÇA DE BANCO DE DADOS

- CREATEDB NOCREATEDB: Estas cláusulas definem a permissão para o usuário criar


banco de dados. Se for especificado CREATEDB, o usuário sendo definido terá permissão
para criar seus próprios bancos de dados. Se for especificado NOCREATEDB, nega-se ao
usuário a permissão para criar banco de dados. Se nenhuma destas cláusulas for especificada,
o padrão é NOCREATEDB.
- CREATEUSER NOCREATEUSER : Estas cláusulas determinam se o usuário pode ou
não criar novos usuários. CREATEUSER também torna o usuário um superusuário, o qual
pode passar por cima de todas as restrições de acesso. Se nenhuma destas cláusulas for
especificada, o padrão é NOCREATEUSER.
- nome_do_grupo: O nome de um grupo existente onde o usuário será incluído como
um novo membro. Podem ser especificados nomes de vários grupos.
- Senha: Define a senha do usuário. Se não se pretende utilizar autenticação por senha
esta opção pode ser omitida, mas o usuário não poderá mais se conectar se for decidido mudar
para autenticação por senha. A senha poderá ser definida ou mudada posteriormente através
do comando ALTER USER.
- ENCRYPTED UNENCRYPTED: Estas cláusulas controlam se a senha será
armazenada criptografada, ou não, nos catálogos do sistema; Se não for especificada
nenhuma destas cláusulas, o comportamento padrão será determinado pelo parâmetro de
configuração password_encryption. Se a cadeia de caracteres da senha já estiver criptografada
no formato MD5, então a cadeia de caracteres será armazenada como está,
independentemente de ser especificado ENCRYPTED ou UNENCRYPTED (porque o sistema
não pode descriptografar a cadeia de caracteres criptografada contendo a senha). Esta
funcionalidade permite a restauração de senhas criptografadas efetuadas por uma operação de
dump/restore. Deve ser observado que os clientes antigos podem não possuir suporte para o
mecanismo de autenticação MD5, necessário para trabalhar com as senhas que são
armazenadas criptografadas.
- data_e_hora: A cláusula VALID UNTIL define uma data e hora após a qual a senha do
usuário não é mais válida. Se esta cláusula for omitida, a conta será válida para sempre.
A cláusula VALID UNTIL define uma data de expiração para a senha apenas, e não para a
conta do usuário per se. Em particular, a obediência à data de expiração não é imposta ao se
conectar utilizando um método de autenticação não baseado em senha.

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 senha:


CREATE ROLE manuel WITH PASSWORD 'jw8s0F4';

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';

Criar uma conta onde o usuário pode criar bancos de dados:


CREATE ROLE manuel WITH PASSWORD 'jw8s0F4' CREATEDB;

Criar um usuário com poderes de superusuário:


CREATE ROLE administrador WITH SUPERUSER ENCRYPTED PASSWORD
‘xxxxx’;

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 excluir usuário do banco de dados utiliza-se o comando DROP:


DROP ROLE Manoel;

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;

12.5. CRIANDO GRUPOS DE USUÁRIOS

No PostgreSQL é possível criar grupos de usuários. Lembrando que todas as


permissões atribuídas ao grupo serão repassadas aos usuários pertencentes a ele.

Sintaxe:
CREATE GROUP nomedogrupo;

Exemplos:
CREATE GROUP adm;

83
SEGURANÇA DE BANCO DE DADOS

Adicionar e remover usuário de um grupo:

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;

Para listar todos os grupos criados é necessário consultar a tabelas do sistema


pg_group:

SELECT gronome FROM pg_group;

12.6. CONCEDENDO PRIVILÉGIOS AOS USUÁRIOS

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

A concessão de privilégios se dá através do comando GRANT e sua revogação através


do comando REVOKE.

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;

Para atribuir e retirar permissão ao grupo:


GRANT SELECT, DELETE ON cliente TO adm;
REVOKE UPDATE ON cliente FROM miriam;

Para remover os privilégios de todos os usuários:


REVOKE ALL ON cliente FROM PUBLIC;

84
SEGURANÇA DE BANCO DE DADOS

Os privilégios especiais do dono da tabela são sempre inerentes à condição de ser o


dono, não podendo ser concedidos ou revogados. No entanto, o dono do objeto pode revogar
seus próprios privilégios, tornando-se um usuário comum como os demais no que se refere ao
objeto na qual é proprietário.
Em geral, somente o dono e o superusuário podem conceder ou revogar privilégios para
um objeto.

12.7. OBSERVAÇÕES IMPORTANTES

O usuário do sistema (superusuário) deve ser um usuário criado exclusivamente para o


PostgreSQL. Nunca devemos torná-lo dono de um executável.
Os nomes de usuário são globais para todos os bancos de dados.

85
REFERÊNCIAS

REFERÊNCIAS

ELMASRI, Ramez; Sistema de Banco de Dados - Fundamentos e Aplicações - 4ª Edição,


Pearson Education, 2005.

OLIVEIRA, Celso Henrique Poderoso; SQL – Curso Prático; Novatec, 2002.

Momjian, Bruce; PostgreSQL: Introduction and Concepts. E-Book; Addison-Wesley, 2001.

PostgreSQL – Manual (With user comments) do PostgreSQL 8.3. Disponível em


<http://www.postgresql.org/files/documentation/pdf/8.3/postgresql-8.3-A4.pdf>

86

You might also like