cursobdp1

39
FALS – BANCO DE DADOS 1 Página 1 de 39 Curso: Banco de Dados FALS Apostila – Parte 1 Professor: Paulo Roberto Tazinazo Cândido

Upload: marcos-paulo

Post on 02-Jul-2015

88 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: CursoBDP1

FALS – BANCO DE DADOS 1

Página 1 de 39

Curso: Banco de Dados

FALS

Apostila – Parte 1

Professor: Paulo Roberto Tazinazo Cândido

Page 2: CursoBDP1

FALS – BANCO DE DADOS 1

Página 2 de 39

I. Introdução a Banco de Dado Relacional ................................................................ 3

A. Criando Tabelas – Conceitos Básicos ................................................................ 4 1. Primeira versão da tabela de clientes .............................................................. 4

B. Nome completo e parcial. .................................................................................. 5 C. Exclusão de uma tabela do banco de dados ........................................................ 5 D. Manipulação Básica de Dados ........................................................................... 6

1. Inserindo dados na tabela de Clientes ............................................................. 6 2. Recuperar (ler) dados de uma tabela .............................................................. 6 3. Exclusão de Linhas ........................................................................................ 8 4. Alteração de valores de colunas ..................................................................... 8

II. Tipos de dados. ..................................................................................................... 9 A. Tipos providos pelo sistema............................................................................... 9 B. Tipos criados pelo usuário ............................................................................... 11 C. Visualizando definição de tabelas e tipos criados pelo usuário ......................... 11

III. Incluindo e excluindo colunas de uma tabela ................................................... 12 A. Incluindo uma coluna. ..................................................................................... 12 B. Excluindo uma coluna ..................................................................................... 12

IV. Colunas Identity .............................................................................................. 12 V. Integridade de Dados ........................................................................................... 13

A. CHECK ........................................................................................................... 14 B. DEFAULT ...................................................................................................... 15 C. PRIMARY KEY ............................................................................................. 16 D. UNIQUE ......................................................................................................... 18 E. REVISÃO 1 .................................................................................................... 18 F. FOREIGN KEY .............................................................................................. 19 G. Habilitar e desabilitar constraints ..................................................................... 21 H. Criar constraints sem que os dados existentes na tabela sejam verificados ....... 21

VI. SELECT Avançado ......................................................................................... 22 A. Consultas com JOIN ........................................................................................ 22 B. USO DE APELIDO ......................................................................................... 24 C. INNER JOIN ................................................................................................... 24 D. LEFT JOIN ..................................................................................................... 25 E. RIGHT JOIN ................................................................................................... 25 F. JOIN DE UMA TABELA COM ELA MESMA .............................................. 26 G. SUBQUERY ................................................................................................... 27 H. EXISTS ........................................................................................................... 28

VII. GERAR INFORMAÇÕES SUMARIZADAS ................................................. 29 A. EXEMPLOS ................................................................................................... 29 B. GROUP BY .................................................................................................... 30 C. HAVING ......................................................................................................... 31 D. COMPUTE e COMPUTE BY ......................................................................... 32

Page 3: CursoBDP1

FALS – BANCO DE DADOS 1

Página 3 de 39

I. Introdução a Banco de Dado Relacional Cada um dos diferentes modelos de banco de dados é caracterizado pela forma (ou estrutura) utilizada para armazenamento de dados e implementação de ligações entre os mesmos. Nos Bancos de Dados Relacionais são utilizadas tabelas bidimensionais, também chamadas de relações, para armazenamento dados. Tais tabelas são organizadas em linhas e colunas, conforme exemplo abaixo utilizado para armazenar dados sobre funcionários de uma empresa. Numero_Matrícula Nome_Funcionário Salário Idade 1000 Paulo 1000,00 20 1010 Maria 5000,00 45 2045 João 800,00 38 Note que cada linha representa um elemento do conjunto dos funcionários da empresa e cada coluna, uma dada informação a respeito dos funcionários. Desta forma, cada célula da tabela armazena um dado referente a um funcionário específico. Maria tem 45 anos de idade. As tabelas (ou relações) possuem as seguintes propriedades (extraídas do livro do professor Setzer): 1) Cada célula de uma tabela pode ser vazia (nula;NULL) ou, ao contrário, conter no

máximo um valor; 2) A ordem das linhas é irrelevante (do ponto de vista do usuário); 3) Não deve haver duas linhas iguais; 4) Cada coluna tem um nome; 5) Duas colunas distintas devem ter nomes diferentes; 6) Usando-se os nomes para fazer referencia às colunas, a ordem destas é irrelevante; 7) Cada tabela recebe um nome próprio , distinto do nome de qualquer outra tabela do

banco (ou base) de dados; 8) Os valores de uma coluna são retirados todos de um mesmo conjunto, denominado

domínio da coluna; 9) Duas ou mais colunas distintas podem ser definidas sobre o mesmo domínio.

Page 4: CursoBDP1

FALS – BANCO DE DADOS 1

Página 4 de 39

A. Criando Tabelas – Conceitos Básicos Apresentamos a seguir o comando SQL utilizado para criar a tabela que armazena dados sobre os clientes de uma empresa.

1. Primeira versão da tabela de clientes A seguir a descrição das colunas da tabela de clientes.

Coluna Descrição Domínio Codigo Cliente Código interno criado para cada

cliente número inteiro – quantidade estimada máxima de 20.000 clientes

Nome Cliente Nome ou razão social do cliente texto de no máximo 50 caracteres

Data Cadastro Data em que o cliente foi cadastrado

Dia, mês e ano do cadastro

Estado Estado em que o cliente reside RS, SC, PR (todos os clien. são da região sul)

Telefone Telefone do cliente O cliente pode não ter telefone Media Compras Média de compras realizadas

pelo cliente por mês Valor expresso em R$

Física/Jurídica Pessoa física ou jurídica 0 = física; 1 = jurídica

A seguir o comando SQL para criação da tabela CLIENTE. create table dbo.tbcliente ( CodCliente int not null, NomeCliente varchar(50) not null, DataCadastro datetime not null, Estado char(2) not null, Telefone char(15) null, MediaCompra money not null, FisJur int not null ) No comando acima, definiu-se o nome da tabela como “dbo.tbcliente”. Para cada coluna é necessário especificar seu nome, seu tipo (domínio) e se será ou não permitido o valor nulo (NULL). Os tipos utilizados foram: § int : número inteiro entre -2.147.483.648 e 2.147.483.647 § varchar e char : texto alfanumérico - cadeia de caracteres § datetime : data e hora § money : valores monetários

Uma descrição detalhada destes e outros tipos de dados nativos do MS SQL-Server serão estudados a seguir.

Page 5: CursoBDP1

FALS – BANCO DE DADOS 1

Página 5 de 39

B. Nome completo e parcial. Nomes de tabelas e outros objetos no MS SQL Server seguem a seguinte estrutura: Nome Completo: servidor.database.owner.table_name Nome Parcial : database.owner.table_name owner.table_name table_name Servidor = nome do servidor Database = nome do database Owner = proprietário da tabela (conta de usuário do database) Table_name = nome da tabela ou objeto. Quando um nome parcial é utilizado, o sistema completa as partes faltantes com base no contexto em que o comando está sendo executado. Por exemplo, se for utilizado o nome parcial table_name, o sistema utilizará para completar o nome do objeto o nome do servidor onde se está executando o comando, o nome do database corrente e o nome da conta do usuário que esta executando o comando. IMPORTANTE : É extremamente recomendável que todos os objetos de um database tenham o mesmo proprietário (owner). Veremos melhor o porquê disto quando estudarmos dependência entre objetos do database.

C. Exclusão de uma tabela do banco de dados O comando a seguir elimina definitivamente a tabela DBO.TBCLIENTE do database corrente.

drop table dbo.tbcliente

Page 6: CursoBDP1

FALS – BANCO DE DADOS 1

Página 6 de 39

D. Manipulação Básica de Dados Execute os comandos abaixo no MS SQL Server para visualizar os resultados. Não se esqueça de criar a tabela de clientes primeiro.

1. Inserindo dados na tabela de Clientes Atribuindo valores para todos as colunas da tabela, na ordem em que foram definidas pelo comando CREATE TABLE insert tbcliente values (100,'Ana','11/20/2001','RS','1234-5678',2000.20,0) insert tbcliente values (110,'Joao','03/05/1999','SC',null,120.33,0) Atribuindo valores apenas para as colunas obrigatórios (NOT NULL) e em qualquer ordem. insert tbcliente (CodCliente,NomeCliente,DataCadastro,Estado,MediaCompra,FisJur) values (120 , 'RGB' , '01/07/2002' , 'PR' , 481.45 , 1) insert tbcliente (NomeCliente,DataCadastro,Estado,CodCliente,MediaCompra,FisJur) values ('JRS' , '08/17/1987' , 'PR' , 130, 1000000.19 , 1)

2. Recuperar (ler) dados de uma tabela Listando todas as linhas e todos as colunas. select * from tbcliente Listando todas as linhas e algumas colunas select NomeCliente, MediaCompra from tbcliente Alterando os cabeçalho de coluna na listagem gerada pelo comando select. Quando existirem brancos, deve-se utilizar []. select NomeCliente as Nome_Cliente, MediaCompra as [Media Compra Mensal], [Data Cadastro] = DataCadastro from tbcliente

Page 7: CursoBDP1

FALS – BANCO DE DADOS 1

Página 7 de 39

Classificando (ordenando) o resultado em ordem crescente pelos valores da coluna NomeCliente select NomeCliente as Nome_Cliente,

MediaCompra as [Media Compra Mensal], [Data Cadastro] = DataCadastro from tbcliente order by NomeCliente asc asc é o padrão, portanto não precisaria ter sido utilizado. Classificando (ordenando) o resultado em ordem decrescente pela coluna MediaCompra select NomeCliente as Nome_Cliente,

MediaCompra as [Media Compra Mensal], [Data Cadastro] = DataCadastro from tbcliente order by 2 desc O número 2 específica que a classificação deve ser feita pela segunda coluna ou seja MediaCompra. Poderíamos ter escrito “order by MediaCompra desc”, o resultado seria o mesmo. Modificando a consulta (query) anterior, para listar apenas os 3 melhores clientes. select top 3 NomeCliente as Nome_Cliente,

MediaCompra as [Media Compra Mensal], [Data Cadastro] = DataCadastro from tbcliente order by 2 desc TOP 3 especifica que apenas as três primeiras linhas do resultado serão apresentadas. Selecionando linhas. Listar, em ordem decrescente por Estado e Nome do cliente, apenas as pessoas físicas. select NomeCliente as Nome_Cliente, MediaCompra as [Media Compra Mensal], [Data Cadastro] = DataCadastro, Estado from tbcliente where FisJur=0 order by 4,NomeCliente desc Apenas as linhas que satisfizerem a condição da cláusula WHERE serão apresentadas no resultado. Pode se utilizar conectivos lógicos (and , or e not) para produzir expressões lógicas compostas.

Page 8: CursoBDP1

FALS – BANCO DE DADOS 1

Página 8 de 39

3. Exclusão de Linhas Excluir todas as linhas de uma tabela. Exclui apenas o conteúdo, a tabela continua existindo no database, vazia. delete tbcliente Outra forma. truncate table tbcliente Mais rápido. Apenas usuários com previlégio de proprietário (db_owner) podem executar este comando. Excluir apenas algumas linhas Excluir de tbcliente todos os clientes com média de compras mensal inferior a R$500,00 delete tbcliente where MediaCompra < 500 Apenas linhas que satisfizerem a condições da cláusula WHERE serão excluídas.

4. Alteração de valores de colunas O cliente RGB mudou-se para o RS e sua média de compras passou de R$481,45 para R$356,34. update tbcliente set estado='RS', MediaCompra=356.34 where codcliente=120 Se você não colocar a cláusula WHERE, todas as linhas da tabela terão os valores das colunas Estado e MediaCompra alterados. CUIDADO .

Page 9: CursoBDP1

FALS – BANCO DE DADOS 1

Página 9 de 39

II. Tipos de dados.

A. Tipos providos pelo sistema

Tipo Descrição Tamanho BIT Número inteiro 0 ou 1 1 Bit TINYINT Números inteiros entre 0 e 255 1 Byte SMALLINT Números inteiros entre –32.768 e 32.767 2 Bytes INT Números inteiros entre –2.147.483.648 e

+2.147.483.647 4 Bytes

DECIMAL(P,S) ou NUMERIC(P,S)

Números com tamanho máximo (precisão - P) e números de casas decimais (escala - S) especificadas da seguinte forma: DECIMAL(P,S). Por exemplo, o número 12345,678, que tem 8 dígitos (P), sendo 3 decimais (S), pode ser armazenado em uma coluna de uma tabela de tipo: DECIMAL(8,3). Por padrão a maior precisão é de 28. Alternativamente o Sql Server pode ser configurado para até a precisão 38. 0 <= S <= P

Depende da precisão (P): P Bytes 1 – 9 5 10-19 9 20-28 13 29-38 17

MONEY Valores monetarios entre -922.337.203.685.477,5808 e +922.337.203.685.477,5807

8 Bytes

SMALLMONEY Valores monetarios entre –214.748,3648 e +214.748,3647

4 Bytes

FLOAT(N) Números reais na notação ponto flutuante. Pode, opcionalmente, ser especificado o número de bits (N) a serem utilizados para armazenar a mantissa do número em notação científica, por exemplo: float(24). Float(53) é equivalente a precisão dupla (double). Mais utilizado em aplicações científicas e de engenharia. Números entre – 1,79E + 308 e 1,79E + 308

Depende de N N Precisão Bytes 1-24 7dig 4 25-53 15dig 8

REAL Mesmo que float(24) 4 Bytes DATETIME Data e hora entre 01/01/1753 e 31/12/9999,

com precisão de 3.33 milesegundos. 8 Bytes

SMALLDATETIME Data e hora entre 01/01/1900 e 06/06/2079, com precisão de 1 segundo.

4 Bytes

CHAR(N) Strings de caracteres de tamanho fixo. Tamanho (N) máximo 8000 caracteres

N Bytes

VARCHAR(N) Strings de caracteres de tamanho variável. Tamanho (N) máximo 8000 caracteres.

N Bytes ou menos, dependendo do tamanho do dado armazenado)

Page 10: CursoBDP1

FALS – BANCO DE DADOS 1

Página 10 de 39

TEXT Texto de até 2.147.483.647 caracteres. Tamanho do

texto NCHAR(N) Strings de caracteres UNICODE de

tamanho fixo. Tamanho (N) máximo 4000 caracteres

N*2 Bytes

NVARCHAR(N) Strings de caracteres UNICODE de tamanho variável. Tamanho (N) máximo 4000 caracteres.

N*2 Bytes ou menos, dependendo do tamanho do dado armazenado)

NTEXT Texto de até 1.073.741.823 caracteres. Tamanho do texto * 2

BINARY(N) Strings binárias de tamanho fixo. Máximo de 8000 bytes.

N

VARBINARY Strings binárias de tamanho VARIÁVEL. Máximo de 8000 bytes.

N ou menos, dependendo do dado armazenado.

IMAGE Campo binário de até 2.147.483.647 bytes. Utilizado para armazenar imagens.

Tamanho da imagem.

CURSOR Utilizado em programação. Permite navegar por um conjunto de registros oriundos de uma consulta (query). Não pode ser utilizado como tipo de coluna de tabelas.

TIMESTAMP Utilizado internamente pelo Sql Server no processo de Recovery (veremos futuramente). Pode ser utilizado como tipo de coluna de tabelas. Quando uma linha é inserida, o Sql Server gera automaticamente um valor para a coluna. Quando uma linha é alterada, o valor da coluna timestamp é alterado. Nunca utilizar colunas timestamp em chaves, especialmente chaves primárias.

8 Bytes

UNIQUEIDENTIFIER Usado para armazenar GUID (globally unique identification number). GUID são números binários com garantia de serem únicos, nenhum computador no mundo pode gerar um GUID igual a um já existente. Utiliza-se a função NEWID para gerá-los. Utilizado para atribuir um identificador que seja único dentro de uma rede de computadores.

16 Bytes

Page 11: CursoBDP1

FALS – BANCO DE DADOS 1

Página 11 de 39

Exercício Crie a tabela descrita abaixo, para armazenamento de dados sobre veículos à venda em uma agência de automóveis, utilizando sempre o tipo mais adequado. Treine na tabela criada os comando INSERT, SELECT, DELETE e UPDATE. Nome da tabela: Automóvel Colunas:

Nome Coluna Descrição Marca Máximo de 15 caracteres Modelo Máximo de 10 caracteres Potencia Número com no máximo 2 casas inteiras e 3

decimais Velocidade_Maxima Número inteiro de no máximo 500. Preço Valor monetário de no máximo R$200.000,00 Data_Fabricacao Dia, mês e ano de fabricação do veículo. Datas

pertencentes aos anos de 1950 a 2050. Numero_Donos Número de proprietários que o veículo já teve.

Máximo 100.

B. Tipos criados pelo usuário São tipos de dados definidos pelos usuários (desenvolvedores) com base nos tipos fornecidos pelo sistema. A criação e a exclusão de tipos definidos pelo usuário são executadas através de System Stored Procedure: programas definidos pelo sistema. Futuramente veremos quais são as procedures mais utilizadas e como criar nossas próprias. Os nomes de todas as System Stored Procedures começam com SP_. exec sp_addtype cep, 'char(10)' -- cria o tipo CEP create table dbo.teste ( rua varchar(100) not null, cep cep not null ) -- cria tabela drop table dbo.teste -- apaga tabela exec sp_droptype cep -- apaga tipo definido pelo usuário

C. Visualizando definição de tabelas e tipos criados pelo usuário

Se você necessitar visualizar a estrutura de uma tabela, isto é, quais são suas colunas e respectivos tipos e propriedades (você perdeu o arquivo onde estava o comando Create Table), utilize a System Stored Procedure SP_HELP, da seguinte forma. EXEC SP_HELP NOME_TABELA

Page 12: CursoBDP1

FALS – BANCO DE DADOS 1

Página 12 de 39

Uma listagem com todas as informações referentes à estrutura da tabela será apresentada. A procedure SP_HELP também pode ser utilizada para visualizar informações sobre tipos de dados criados pelo usuário, por exemplo: EXEC SP_HELP CEP

III. Incluindo e excluindo colunas de uma tabela Com o comando ALTER TABLE é possível alterar a definição (estrutura) de uma tabela, incluindo ou excluindo colunas na mesma (também é possível definir CONSTRAINT – veremos a seguir).

A. Incluindo uma coluna. ALTER TABLE TBCLIENTE ADD DATA_NASCIMENTO DATETIME NULL O exemplo acima inclui a coluna DATA_NASCIMENTO na tabela TBCLIENTE. Observação: Se a tabela contiver dados, só será possível incluir uma coluna com o atributo NULL; a menos que a definição da coluna possua uma constraint DEFAULT ( veremos constraints a seguir).

B. Excluindo uma coluna ALTER TABLE TBCLIENTE DROP COLUMN DATA_NASCIMENTO O exemplo acima exclui a coluna DATA_NASCIMENTO da tabela TBCLIENTE.

IV. Colunas Identity A propriedade IDENTITY definida junto a uma coluna numérica (int, smallint, tinyint, decimal ou numeric) torna-a auto incrementável. O sistema passa a gerar valores para a coluna IDENTITY, para todas as linhas incluídas na tabela (portanto, não se deve atribuir valor para ela no comando INSERT). Importante:

• Só pode haver uma coluna IDENTITY por tabela; • Não pode ser atualizada; • Não permite NULL.

CREATE TABLE DBO.TBPRODUTO (IDPRODUTO INT NOT NULL IDENTITY, DESCRPRODUTO VARCHAR(200) NOT NULL) -- DESCRIÇÃO DO PROD.

Page 13: CursoBDP1

FALS – BANCO DE DADOS 1

Página 13 de 39

O exemplo acima cria uma tabela de nome TBPRODUTO. O valor para a coluna IDPRODUTO (número interno de identificação de um produto vendido pela companhia) é gerado automaticamente pelo sistema quando uma linha (produto) é inserida na tabela. O comando a seguir insere um produto na tabela TBPRODUTO. INSERT TBPRODUTO (DESCRPRODUTO) VALUES (‘PARAFUSO FENDA 5MM’) Observe que a coluna IDPRODUTO não foi referenciada (nem pode) no comando INSERT. Crie esta tabela, insira linhas e visualize, com o comando SELECT, os valores gerados pelo sistema para a coluna IDPRODUTO. Veja outra possibilidade: CREATE TABLE DBO.TBPRODUTO (

IDPRODUTO INT NOT NULL IDENTITY(1000,5), DESCRPRODUTO VARCHAR(200) NOT NULL) -- DESCRIÇÃO DO PROD. Neste exemplo, utilizamos IDENTITY(1000,5). O número 1000 (semente) será o valor gerado para a primeira linha inserida na tabela. Para a segunda linha, o sistema gerará o valor 1005, pois o número 5 em IDENTITY(1000,5) indica qual deve ser o incremento, o padrão é 1.

V. Integridade de Dados A integridade dos dados armazenados no database é conseguida definindo-se restrições:

a) Sobre o conjunto de valores válidos para as colunas de uma tabela, por exemplo, a coluna ESTADO da tabela TBCLIENTE, do exemplo utilizado anteriormente, de acordo com sua definição, só deve aceitar RS, SC e PR, como valores válidos;

b) Sobre a relação entre os valores de duas ou mais colunas de uma tabela, por exemplo, suponha a tabela ALUNO de um database de uma escola, com duas colunas tipo data: DATA_INICIO_CURSO e DATA_FORMATURA, obviamente, DATA_FORMATURA deve ser posterior (>=) a DATA_INICIO_CURSO;

c) Que impeçam a duplicação indevida de linhas em tabelas; d) Que mantenham a consistência referencial entre duas ou mais tabelas, por

exemplo, suponha um database com dados sobre os funcionários de uma empresa e seus dependentes (esposa, filhos, etc), suponha ainda que, por motivos que veremos a seguir, sejam criadas duas tabelas: TBFUNCIONARIO e TBDEPENDENTE, a restrição em que “todo dependente deve estar associado a pelo menos um funcionário” deve ser atendida, de forma a não termos linhas “órfãs” em TBDEPENDENTE (inconsistência).

No SQL Server 7.0, os quatro tipos de restrição descritos acima podem ser implementados através de CONSTRAINTS ou programas (TRIGGERS e STORED PROCEDURES). Por enquanto veremos apenas as CONSTRAINTS

Page 14: CursoBDP1

FALS – BANCO DE DADOS 1

Página 14 de 39

A. CHECK Através da constraint CHECK podemos restringir o conjunto de valores válidos para uma coluna. A seguir utilizamos CHECK para limitar os valores válidos para a coluna ESTADO a uma das seguintes strings: RS,SC ou PR. create table dbo.tbcliente ( CodCliente int not null, NomeCliente varchar(50) not null, DataCadastro datetime not null, Estado char(2) not null check ( Estado=’RS’ or

Estado=’SC’ or Estado=’PR’),

Telefone char(15) null, MediaCompra money not null, FisJur int not null ) Se você executar o seguinte comando, obterá uma mensagem de erro, pois SP não é um valor válido para a coluna ESTADO. insert tbcliente values (100,'Ana','11/20/2001','SP','1234-5678',2000.20,0)

A mensagem de erro será algo parecido com a seguinte: Server: Msg 547, Level 16, State 1, Line 1 INSERT statement conflicted with COLUMN CHECK constraint 'CK__tbcliente__Estad__45F365D3'. The conflict occurred in database 'prof1', table 'tbcliente', column 'Estado'. The statement has been terminated. Obs: 'CK__tbcliente__Estad__45F365D3' é o nome gerado automaticamente pelo sistema para a constraint check. Você pode definir um nome menos complicado modificando o comando da seguinte forma: create table dbo.tbcliente ( CodCliente int not null, NomeCliente varchar(50) not null, DataCadastro datetime not null, Estado char(2) not null constraint EstadoCK

check (Estado=’RS’ or Estado=’SC’ or Estado=’PR’),

Telefone char(15) null, MediaCompra money not null, FisJur int not null )

Page 15: CursoBDP1

FALS – BANCO DE DADOS 1

Página 15 de 39

Exercício: Utilize a system stored procedure SP_HELP, para obter a listagem descrevendo a estrutura (definição) da tabela TBCLIENTE e localize na mesma a constraint check criada e sua definição.

Outra forma de escrever a constraint check mantendo o mesmo resultado é utilizando a cláusula IN, como segue: create table dbo.tbcliente ( CodCliente int not null, NomeCliente varchar(50) not null, DataCadastro datetime not null, Estado char(2) not null

check ( Estado in (’RS’,’SC’,’PR’) ), Telefone char(15) null, MediaCompra money not null, FisJur int not null ) Obs: Vale ressaltar que o tipo de dado selecionado para uma coluna assim como o atributo NULL (ou NOT NULL) também impõem integridade a coluna. Campos numéricos, por exemplo, não aceitam, obviamente, valores não numéricos, sendo, portanto, impossível ter-se uma coluna INT com o valor 15X.34 . Em sistemas mais antigos, era comum (não muito) encontrar datas armazenadas em campos caracteres (CHAR), como campos caracteres aceitam tudo, datas como 31/02/2002, por exemplo, eram encontradas. A utilização de tipos de dados apropriados para armazenamento de datas garantem que apenas datas válidas serão aceitas. Como último exemplo, considere o absurdo de se ter uma linha na tabela TBCLIENTE sem valor na coluna NOMECLIENTE, caso esta coluna tivesse sido definida como não obrigatória (NULL). Exercício:

Defina uma constraint check que restrinja a coluna FISJUR aos valores 0 (pessoa física) e 1 (pessoa jurídica), conforme definição.

B. DEFAULT A constraint DEFAULT especifica um valor padrão a ser atribuído à coluna quando um não for explicitamente definido no comando INSERT.

Page 16: CursoBDP1

FALS – BANCO DE DADOS 1

Página 16 de 39

Introduzimos a seguir duas constraints DEFAULT para a tabela TBCLIENTE. create table dbo.tbcliente ( CodCliente int not null, NomeCliente varchar(50) not null, DataCadastro datetime not null default getdate(), Estado char(2) not null check ( Estado=’RS’ or

Estado=’SC’ or Estado=’PR’),

Telefone char(15) null, MediaCompra money not null default 0, FisJur int not null ) A constraint DEFAULT definida para a coluna DATACADASTRO especifica que se não for explicitamente atribuída uma data a esta coluna no comando INSERT, a data do sistema, obtida pela função GETDATE, será automaticamente atribuída a ela. Já para a coluna MEDIACOMPRA, em condições semelhantes, é atribuído o valor 0 (zero). Recrie a tabela, execute o INSERT abaixo e verifique o resultado. insert tbcliente (codcliente,nomecliente,estado,fisjur) values (1,'paulo','rs',0) Exercício:

Modifique o comando CREATE TABLE acima definindo ‘RS’ como valor padrão para a coluna ESTADO.

C. PRIMARY KEY Uma coluna ou combinação de colunas que identifiquem exclusivamente uma linha das demais linhas de uma tabela é chamada de chave da tabela (Key). Uma tabela pode ter várias chaves. Uma delas pode ser escolhida como principal (Primary). Exemplos de chaves:

a) O número de matrícula de um aluno da FALS identifica exclusivamente o aluno. Ou seja, não existem dois alunos com a mesma matrícula.

b) O CPF identifica exclusivamente uma pessoa física perante a receita federal. Para uma tabela projetada para armazenar dados sobre os alunos da FALS, por exemplo, precisamos garantir que um mesmo número de matrícula não seja utilizado, por engano, para dois ou mais alunos. No SQL Server 7.0, este tipo de integridade é facilmente implementado através da constraint PRIMARY KEY, Abaixo apresentamos um exemplo utilizando a tabela TBCLIENTE. Obs: Todas as colunas que compõem a PRIMARY KEY devem ter o atributo NOT NULL.

Page 17: CursoBDP1

FALS – BANCO DE DADOS 1

Página 17 de 39

create table dbo.tbcliente ( CodCliente int not null primary key, NomeCliente varchar(50) not null, DataCadastro datetime not null default getdate(), Estado char(2) not null check ( Estado=’RS’ or

Estado=’SC’ or Estado=’PR’),

Telefone char(15) null, MediaCompra money not null default 0, FisJur int not null ) O comando acima define a coluna CODCLIENTE como chave primária da tabela TBCLIENTE. Se você tentar executar o INSERT abaixo duas vezes, para a primeira vez você obterá sucesso, mas para a segunda, uma mensagem de erro será apresentada. insert tbcliente (codcliente,nomecliente,estado,fisjur) values (1,'paulo','rs',0) Mensagem de erro: Server: Msg 2627, Level 14, State 1, Line 1 Violation of PRIMARY KEY constraint 'PK__tbcliente__117F9D94'. Cannot insert duplicate key in object 'tbcliente'. The statement has been terminated. No exemplo abaixo, ilustramos a criação de uma chave primária composta por duas colunas. create table dbo.pedido( CodCliente int not null, DataPedido datetime not null, CodVendedor int not null, constraint chave_pedido primary key (CodCliente,DataPedido) ) O sistema garantirá que não existirão duas linhas com a mesma combinação de valores nas duas colunas, ou seja, um mesmo cliente (CODCLIENTE) pode aparecer em várias linhas da tabela desde que em cada uma delas DATAPEDIDO seja diferente. Não será possível, portanto, serem inseridas duas linhas com CODCLIENTE = 100 e DATAPEDIDO=’01/01/2003’, por exemplo.

Page 18: CursoBDP1

FALS – BANCO DE DADOS 1

Página 18 de 39

D. UNIQUE Se você precisar garantir também a integridade da tabela por outras chaves além da primária, utilize a constraint UNIQUE. A constraint UNIQUE garantirá que valores duplicados não serão inseridos na tabela. create table dbo.funcionario ( NumeroFuncionario int not null primary key, NomeFuncionario varchar(100) not null, RGFuncionario int not null unique ) No exemplo acima, a tabela funcionário é criada com a coluna NUMEROFUNCIONARIO como PRIMARY KEY e com a coluna RGFUNCIONARIO (documento de identidade) como UNIQUE. De forma que, o sistema garantirá que não existirão na tabela duas linhas com o mesmo valor na coluna RGFUNCIONARIO. Idem para a coluna NUMEROFUNCIONARIO. As chaves UNIQUE também podem ser compostas.

E. REVISÃO 1 O exercício a seguir visa o treinamento sobre os conceitos e comandos da linguagem SQL (Transact-SQL) vistos até agora. O exemplo utilizado tem caráter didático, não sendo a melhor solução a ser adotada para o cadastramento de dados sobre eletrodomésticos. Futuramente, veremos soluções melhores. Enunciado:

1. Crie a tabela ELETRODOMESTICOS conforme descrição abaixo, selecionando o tipo de dado mais adequado e implemente restrições que impeçam que valores inválidos sejam entrados.

2. Defina e implemente a chave primária para esta tabela.

Nome Coluna Descrição Valores Possíveis Obrigatório Valor Padrão

Tipo Código numérico que identifica o tipo de eletrodoméstico

1 (=geladeia); 2 (=tanquinho) ; 3 (=microondas); 4 (=lava roupa) ou 5 (=lava louça)

Sim

Fabricante Código numérico que identifica o fabricante do eletrodoméstico

1 (=Brastemp); 2 (=Cônsul); 3 (=GE)

Sim 1

Modelo Texto com o modelo do aparelho

String de no máximo 50 posições

Sim

Potencia Potência do aparelho Número entre 0.5 e 3.7

Sim

Page 19: CursoBDP1

FALS – BANCO DE DADOS 1

Página 19 de 39

Cor Cor do aparelho Uma das seguintes

strings: Branca, Azul e Vermelha

Sim Branca

NumeroSerie Número de série do aparelho

Número entre 1.000.000 e 9.999.999

Sim

DataEntraEstoque Data em que o produto entrou em estoque

Datas entre 1/1/2003 e 31/12/3002

Sim Data do sistema

Voltagem Voltagem do aparelho 110 ou 220 Sim 110 Vendido Indica se o aparelho

foi vendido ou não. 0 (= Não) ; (1=Sim) Sim 0

CodigoVendedor Código do vendedor § Número entre 1 e 300, se Vendido=1. § Ou NULL, se Vendido=0.

Não

DataVenda Data da venda § Igual ou posterior a DataEntraEstoque. § NULL, se Vendido=0. § NOT NULL, se Vendido=1

Não

F. FOREIGN KEY Para explicarmos a constraint FOREIGN KEY utilizaremos como exemplo o exercício da revisão 1 (acima). Tomemos a coluna Fabricante. Uma das formas possíveis para restringirmos os valores entrados nesta coluna (os válidos são: 1,2 ou 3) é utilizarmos uma constraint CHECK, como a seguir: Create Table dbo.eletrodomesticos ( …. Fabricante tinyint not null check (Fabricante in (1,2,3)) , …. ) O grande inconveniente é termos que alterar a estrutura da tabela sempre que passarmos a trabalhar com produtos de outro fabricante. Neste caso, um novo código (4) referente ao novo fabricante (Eletrolux, por exemplo) passa a ser válido para a coluna. Para tal, é necessário alterar a constraint CHECK, excluindo-a e recriando-a através do comando ALTER TABLE. Exclui CHECK

ALTER TABLE ELETRODOMESTICOS DROP CONSTRAINT nome_da_constraint_check

Page 20: CursoBDP1

FALS – BANCO DE DADOS 1

Página 20 de 39

Recria CHECK

ALTER TABLE ELETRODOMESTICOS ADD CHECK (FABRICANTE IN (1,2,3,4))

Uma alternativa melhor que dispensa a alteração na estrutura da tabela ELETRODOMESTICOS, sempre que um novo fabricante deva ser considerado, é a seguinte:

1) Criar uma nova tabela, de nome TBFABRICANTE, com o cadastro de cada fabricante. Esta nova tabela teria, por exemplo, duas colunas: § IdFabricante – código numérico interno exclusivo de cada fabricante

(chave primária); § NomeFabricante – campo caracter com o nome do fabricante

Assim teríamos para a situação proposta a seguinte tabela:

IdFabricante NomeFabricante 1 Brastemp 2 Cônsul 3 GE 4 Eletrolux

2) Sempre que uma linha for inserida na tabela ELETODOMESTICOS, verificar

se o valor atribuído à coluna Fabricante é igual ao valor da coluna IdFabricante em alguma linha da tabela TBFABRICANTE, ou seja, verificar se o valor atribuído existe em TBFABRICANTE. Caso afirmativo, aceitar o valor.

Com esta solução, basta incluir um novo fabricante na tabela TBFABRICANTE para que o mesmo (seu identificador – IdFabricante) passe a ser aceito como valor válido para a coluna Fabricante da tabela ELETRODOMÉSTICOS. Para nossa sorte, através da constraint FOREIGN KEY (chave estrangeira), o próprio sistema executa este tipo de validação. Para substituir a constraint CHECK pela FOREIGN KEY, podemos fazer o seguinte: Exclui CHECK

ALTER TABLE ELETRODOMESTICOS DROP CONSTRAINT nome_da_check_constraint

Cria FOREIGN KEY

ALTER TABLE ELETRODOMESTICOS ADD FOREIGN KEY (FABRICANTE) REFERENCES TBFABRICANTE(IDFABRICANTE)

Óbvio que a tabela TBFABRICANTE deve ser criada antes que o comando acima seja executado.

Page 21: CursoBDP1

FALS – BANCO DE DADOS 1

Página 21 de 39

IMPORTANTE : Para que o exemplo acima funcione, é obrigatório que a coluna IdFabricante em TBFABRICANTE seja definida com a constraint PRIMARY KEY ou UNIQUE. É possível definir a FOREIGN KEY diretamente no comando CREATE TABLE, como segue: Create Table dbo.eletrodomesticos ( …. Fabricante tinyint not null foreign key references tbfabricante(idfabricante) , …. ) Obs: A chave estrangeira pode ser composta por mais de um campo. Exercício: Crie a tabela TBFABRICANTE, insira as quatro linhas descritas, implemente a FOREIGN KEY conforme exemplo acima e teste o seu funcionamento.

G. Habilitar e desabilitar constraints Constraints do tipo FOREIGN KEY e CHECK podem ser desabilitadas através dos seguintes comandos: ALTER TABLE nome_tabela NOCHECK CONSTRAINT nome_da_constraint Ou ALTER TABLE nome_tabela NOCHECK CONSTRAINT ALL Se especificado o nome da constraint, apenas ela será desabilitada. Se for utilizado ALL, todas o serão. Para habilitá-las, utilize os seguintes comandos: ALTER TABLE nome_tabela CHECK CONSTRAINT nome_da_constraint Ou ALTER TABLE nome_tabela CHECK CONSTRAINT ALL

H. Criar constraints sem que os dados existentes na tabela sejam verificados

Se for necessário criar uma constraint CHECK ou FOREIGN KEY em uma tabela existente e com dados (ALTER TABLE), é padrão do sistema verificar se existe alguma linha da tabela que viole a condição da constraint, se houver alguma, o comando é cancelado. Em casos raros, podemos querer criar um destes tipos de constraints sem que

Page 22: CursoBDP1

FALS – BANCO DE DADOS 1

Página 22 de 39

sejam verificadas as linhas já existentes, apenas as linhas incluídas ou alteradas a posteriore serão validadas pela constraint. Como WITH CHECK, ou seja, com verificação, é o padrão; os dois comandos a seguir são equivalentes. ALTER TABLE nome_tabela ADD CONSTRAINT nome_constraint CHECK ( expressão_booleana ) ALTER TABLE nome_tabela WITH CHECK ADD CONSTRAINT nome_constraint CHECK ( expressão_booleana ) Para que não seja feita a verificação das linhas existentes, utilizamos WITH NOCHECK, da seguinte forma: ALTER TABLE nome_tabela WITH NOCHECK ADD CONSTRAINT nome_constraint CHECK ( expressão_booleana )

VI. SELECT Avançado Já estudamos anteriormente formas simples do comando SELECT, vamos agora estudá-lo detalhadamente.

A. Consultas com JOIN Quando os dados a serem recuperados (lidos) de um database encontram-se em mais de uma tabela, as mesmas devem ser combinadas em uma consulta (unidas=join) para produzir o resultado esperado. Vamos introduzir esta operação através dos exemplos abaixo. Funcionarios NumeroFunc NomeFunc 1000 Paulo 1200 Joana 1530 Jose (Primary Key) Dependentes NumeroFunc NomeDep 1530 Carla 1000 Renato 1530 Carlos 1530 Mario (Foreign Key)

Page 23: CursoBDP1

FALS – BANCO DE DADOS 1

Página 23 de 39

Quando solicitada uma listagem dos funcionários e seus dependentes, no formato abaixo, como deverá ser o comando SELECT para produzi-lo? Resultado Desejado Nome Funcionário Nome Dependente Jose Carla Jose Carlos Jose Mario Paulo Renato Vamos analisar o problema em etapas. 1) SELECT *

FROM FUNCIONARIOS, DEPENDENTES Na cláusula FROM do comando SELECT, é possível fazer referência a mais de uma tabela, como no exemplo acima. Ao executar o SELECT acima (1), o seguinte resultado será gerado: NumeroFunc NomeFunc NumeroFunc NomeDep 1000 Paulo 1530 Carla 1200 Joana 1530 Carla 1530 Jose 1530 Carla 1000 Paulo 1000 Renato 1200 Joana 1000 Renato 1530 Jose 1000 Renato 1000 Paulo 1530 Carlos 1200 Joana 1530 Carlos 1530 Jose 1530 Carlos 1000 Paulo 1530 Mario 1200 Joana 1530 Mario 1530 Jose 1530 Mario As duas primeiras colunas se referem à tabela FUNCIONARIOS, enquanto as duas últimas, a DEPENDENTES. Cada linha do resultado é obtida combinando 1 linha de FUNCIONARIOS com 1 linha de DEPENDENTES, ou seja, gerando duplas (F,D), onde F é elemento de FUNCIONARIOS e D é elemento de DEPENDENTES. O resultado produzido é a combinação de todas as linhas de FUNCIONARIOS com todas as linhas de DEPENDENTES (Produto Cartesiano). Entretanto, não é o que desejamos. Precisamos eliminar do resultado as linhas em que as 2 colunas NUMEROFUNC, tenham valores diferentes. Ou, em outras palavras, manter as linhas onde as referidas colunas tenham valores iguais. Isto pode ser feito incluindo a cláusula WHERE no comando.

Page 24: CursoBDP1

FALS – BANCO DE DADOS 1

Página 24 de 39

2) SELECT *

FROM FUNCIONARIOS, DEPENDENTES WHERE FUNCIONARIOS.NUMEROFUNC =

DEPENDENTES.NUMEROFUNC Note que é necessário preceder as colunas NUMEROFUNC com os nomes das tabelas a que elas se referem. Para que a coluna NUMEROFUNC da tabela FUNCIONARIOS não seja confundida com a coluna NUMEROFUNC da tabela DEPENDENTES.

B. USO DE APELIDO Uma outra forma para o comando anterior que gera o mesmo resultado, mas simplifica a escrita, utiliza um apelido para cada uma das tabelas. 3) SELECT *

FROM FUNCIONARIOS FU, DEPENDENTES DP WHERE FU.NUMEROFUNC = DP.NUMEROFUNC

Neste comando, sempre que a tabela FUNCIONARIOS precisa ser referenciada, utiliza-se seu apelido FU, reduzindo a escrita. Utilizamos duas letras para o apelido, mas poderiam ser 1, 3, 5 ou mais.

C. INNER JOIN Uma 3ª forma para o comando que também produz o mesmo resultado é a seguinte. 4) SELECT *

FROM FUNCIONARIOS FU INNER JOIN DEPENDENTES DP ON FU.NUMEROFUNC = DP.NUMEROFUNC

Note que o critério para filtrar apenas as linhas desejadas, passa a ser especificado junto ao ON, não mais no WHERE. Isto não significa que a cláusula WHERE, não possa ser utilizada. No exemplo abaixo, utilizamos WHERE para selecionar apenas as linhas cuja idade do dependente seja superior a 10 anos (suponha que o campo IDADE, tenha sido acrescentado à tabela DEPENDENTES), 5) SELECT *

FROM FUNCIONARIOS FU INNER JOIN DEPENDENTES DP ON FU.NUMEROFUNC = DP.NUMEROFUNC

WHERE IDADE > 10 Note que não é preciso escrever DP.IDADE, pois não há em FUNCIONARIOS uma coluna de nome IDADE, ou seja, não há dúvida de que IDADE, refere-se a uma coluna de dependente. Não há ambigüidade.

Page 25: CursoBDP1

FALS – BANCO DE DADOS 1

Página 25 de 39

D. LEFT JOIN Note que nos resultados obtidos anteriormente, foram listados apenas funcionários que possuíam pelo menos 1 dependente. Funcionários sem dependentes nunca aparecem. Se quisermos forçar que todos os funcionários sejam apresentados pelo menos uma vez no resultado, independentemente se eles tem ou não dependentes, precisamos reescrever e consultar (4) substituindo INNER JOIN por LEFT JOIN, como segue:

6) SELECT * FROM FUNCIONARIOS FU LEFT JOIN DEPENDENTES DP

ON FU.NUMEROFUNC = DP.NUMEROFUNC O resultado gerado será o seguinte: NumeroFunc NomeFunc NumeroFunc NomeDEP ----------- ---------- ----------- ---------- 1000 Paulo 1000 Renato 1200 Joana NULL NULL 1530 Jose 1530 Carla 1530 Jose 1530 Carlos 1530 Jose 1530 Mario (5 row(s) affected) Para os funcionários sem dependentes, ou seja, que não atendam ao critério do JOIN (que segue a cláusula ON), tem-se nas colunas referentes à tabela DEPENDENTES valores NULL, como é o caso de JOANA, no exemplo.

E. RIGHT JOIN Na consulta anterior (6) utilizamos LEFT JOIN porque a tabela FUNCIONARIOS, para a qual queremos que todas as suas linhas sejam apresentadas ao menos uma vez no resultado, encontra-se à esquerda do JOIN.

7) SELECT * FROM FUNCIONARIOS FU RIGHT JOIN DEPENDENTES DP

ON FU.NUMEROFUNC = DP.NUMEROFUNC Na consulta acima (7), invertemos a direção do JOIN, ou seja , todos os dependentes serão apresentados no resultado, independentemente se eles possuírem ou não um funcionário associado. Isto pode ocorrer caso não haja uma FOREION KEY, que garanta a integridade da associação FUNCIONARIOS x DEPENDENTES. Note que, neste caso, DEPENDENTES, tabela para a qual queremos que todas as suas linhas sejam apresentadas ao menos uma vez no resultado, está à direita (RIGHT) do JOIN. Note que a consulta abaixo produz exatamente o mesmo resultado consulta (6), a menos da ordem das colunas.

8) SELECT * FROM DEPENDENTES DP RIGHT JOIN FUNCIONARIOS FU

ON FU.NUMEROFUNC = DP.NUMEROFUNC

Page 26: CursoBDP1

FALS – BANCO DE DADOS 1

Página 26 de 39

NumeroFunc NomeDEP NumeroFunc NomeFunc ----------- ---------- ----------- ---------- 1000 Renato 1000 Paulo NULL NULL 1200 Joana 1530 Carla 1530 Jose 1530 Carlos 1530 Jose 1530 Mario 1530 Jose (5 row(s) affected) LEFT JOIN (ou RIGHT JOIN) podem ser utilizados para solucionar a seguinte questão: “Quais são os funcionários que não possuem dependentes?”. No exemplo, JOANA.

9) SELECT * FROM FUNCIONARIOS FU LEFT JOIN DEPENDENTES DP

ON FU.NUMEROFUNC = DP.NUMEROFUNC WHERE DP.NUMEROFUNC IS NULL Para tanto, basta utilizar o fato de que, utilizando LEFT JOIN como acima, todo funcionário sem dependente aparece 1 vez no resultado e tem valores NULL em todas as colunas referentes à tabela DEPENDENTES. Utilizando a cláusula WHERE selecionamos (filtramos) apenas as linhas de interesse. NumeroFunc NomeFunc NumeroFunc NomeDEP ----------- ---------- ----------- ---------- 1200 Joana NULL NULL (1 row(s) affected)

F. JOIN DE UMA TABELA COM ELA MESMA Em algumas situações uma tabela pode ser unida (JOIN) a ela mesma, principalmente quando há auto-relacionamento. Por exemplo, suponha que a coluna SUBORDINADO_A seja adicionada a tabela FUNCIONARIOS, como segue: Funcionarios NumeroFunc NomeFunc Subordinado_A 1000 Paulo 1530 1200 Joana NULL 1530 Jose 1200 (Primary Key) Os valores em SUBORDINADO_A significam que Paulo é diretamente subordinado a José (ou José é chefe de Paulo), enquanto José é diretamente subordinado a Joana (ou Joana é a chefe de José), ou ainda, Joana é presidente da companhia, pois ela não é subordinada a ninguém.

Page 27: CursoBDP1

FALS – BANCO DE DADOS 1

Página 27 de 39

Suponha que seja solicitado o relatório: “Liste os chefes e seus subordinados diretos”, como segue.

CHEFE SUBORDINADO Joana José José Paulo A seguinte consulta pode ser utilizada para produzi-lo.

10) SELECT CHE.NOMEFUNC AS CHEFE, SUB.NOMEFUNC AS SUBORDINADO

FROM FUNCIONARIOS CHE INNER JOIN FUNCIONARIOS SUB ON CHE.NUMEROFUNC = SUB.SUBORDINADO_A

G. SUBQUERY É possível na linguagem SQL construir comandos SELECT que tenham em seu corpo outros SELECTs aninhados. Os SELECTs internos são denominados SUBQUERYs.

11) SELECT * FROM FUNCIONARIOS WHERE NUMEROFUNC NOT IN

(SELECT NUMEROFUNC FROM DEPENDENTES) No exemplo acima, o texto em negrito constitui a subquery. As linhas de FUNCIONARIOS que satisfizerem a condição da cláusula WHERE constituirão o resultado. Ou seja, as linhas de FUNCIONARIOS onde o valor na coluna NUMEROFUNC não (NOT) pertencer à lista gerada pela subquery. Note que a subquery gera como resultado, se executada isoladamente, todos os valores da coluna NUMEROFUNC de DEPENDENTES. NUMEROFUNC ----------- 1530 1000 1530 1530 (4 row(s) affected) A consulta (11) é, portanto, equivalente a:

12) SELECT * FROM FUNCIONARIOS WHERE NUMEROFUNC NOT IN (1530,1000,1530,1530)

Resumindo, a consulta (11) também lista todos os funcionários que não possuem dependentes, ou seja, NUMEROFUNC não pertence (NOT IN) à lista (1530,1000,1530,1530), gerada a partir da tabela DEPENDENTES.

Page 28: CursoBDP1

FALS – BANCO DE DADOS 1

Página 28 de 39

H. EXISTS Outro exemplo de subquery é a que utiliza a palavra EXISTS. Vejamos seu comportamento através do exemplo FUNCIONARIOS x DEPENDENTES.

13) SELECT * FROM FUNCIONARIOS FU WHERE NOT EXISTS

(SELECT * FROM DEPENDENTES DP WHERE FU. NUMEROFUNC=DP. NUMEROFUNC)

Aqui novamente produzimos uma listagem com os funcionários sem dependentes. A expressão da cláusula WHERE é verdadeira (TRUE) quando a subquery não produz linhas (atenção para a palavra NOT), ou seja, quando não existem (NOT EXISTS) dependentes para um dado funcionário. Funcionarios NumeroFunc NomeFunc 1000 Paulo 1200 Joana 1530 Jose (Primary Key) O processamento desta consulta ocorre da seguinte forma:

a) Toma-se uma linha de FUNCIONARIOS, por exemplo, a primeira. b) Substitui-se na subquery FU.NUMEROFUNC por 1000 (valor de

NUMEROFUNC da 1a linha de FUNCIONARIOS) c) Execute a subquery resultante

(SELECT * FROM DEPENDENTES DP WHERE 1000=DP. NUMEROFUNC)

d) Se alguma linha for gerada significa que existe dependente para o funcionário 1000 (Paulo). Logo a expressão da cláusula WHERE será falsa.

e) Repetir o mesmo teste para todas as linhas de FUNCIONARIOS.

Page 29: CursoBDP1

FALS – BANCO DE DADOS 1

Página 29 de 39

VII. GERAR INFORMAÇÕES SUMARIZADAS Funções que calculam médias e totais são chamadas de FUNÇÕES DE AGREGAÇÃO. Com elas em comandos SELECT é possível gerar valores sumarizados para as colunas de tabelas. Por exemplo, calcular a média aritmética das idades dos dependentes (armazenados na tabela DEPENDENTES). No Sql Server 7.0, as funções de agregação são as seguintes.

Função de Agregação Descrição AVG Média aritmética dos valores em uma expressão numérica COUNT Número de valores em uma expressão numérica COUNT(*) Número de linhas selecionadas MAX Maior valor em uma expressão MIN Menor valor em uma expressão SUM Valor total em uma expressão numérica STDEV Desvio padrão para todos os valores STDEVP Desvio padrão para uma população VAR Variância para todos os valores VARP Variância para uma população

A. EXEMPLOS

a) Conta quantas linhas existem na tabela FUNCIONARIOS

SELECT COUNT(*) FROM FUNCIONARIOS

b) Calcula a média das idades dos dependentes SELECT AVG(IDADE) FROM DEPENDENTES

c) Supondo uma tabela com todas as vendas realizadas pela empresa (abaixo), calcular o valor total em reais vendido no mês de janeiro/2003.

SELECT SUM(VALOR_VENDA) FROM VENDAS WHERE DATEPART(MONTH,MES)=1 AND DATEPART(YEAR,MES)=2003

Page 30: CursoBDP1

FALS – BANCO DE DADOS 1

Página 30 de 39

VENDAS

NumeroPedido Codigo_Vendedor Mes Valor_Venda 1001 20 01/2003 100 1002 10 02/2003 200 1003 10 12/2002 300 1004 10 02/2003 400 1005 20 12/2002 500 1006 20 01/2003 600 1007 10 01/2003 700 1008 20 12/2002 800 Obs: A coluna MES é do tipo SMALLDATETIME. Para armazenamento de mês/ano, convencionamos utilizar sempre o valor 01 para o dia. Utilizamos a função DATEPART que retorna parte de uma data. Por exemplo, seja a data D = 17/02/2003, DATEPART(MONTH,D) = 2 (fevereiro), DATEPART(YEAR,D) = 2003 (ano). IMPORTANTE : As funções de agregação, com a exceção de count(*), não levam em consideração valores NULL nas colunas em que são aplicadas. Por exemplo, se uma tabela tem 10 linhas e 2 colunas A e B, se em 3 linhas o valor da coluna B for NULL, então COUNT(B) gera o valor 7. Já COUNT(*) gera 10.

B. GROUP BY Podemos melhorar o exemplo (C) acima (total vendas) para gerar o total de vendas em todos os meses. Para isto utilizamos a cláusula GROUP BY, como segue. SELECT MES , COUNT(*) AS NUMERO_VENDAS, SUM(VALOR_VENDA) AS TOTAL_VENDAS_MES FROM VENDAS GROUP BY MES A cláusula GROUP BY acima especifica que as linhas da tabela VENDAS devem ser agrupadas pela coluna MES. Ou seja, todas as linhas com o mesmo valor em MES pertencerão ao mesmo grupo. Grupo 01/2003 NumeroPedido Codigo_Vendedor Mes Valor_Venda 1001 20 01/2003 100 1006 20 01/2003 600 1007 10 01/2003 700 Grupo 02/2003 NumeroPedido Codigo_Vendedor Mes Valor_Venda 1002 10 02/2003 200 1004 10 02/2003 400

Page 31: CursoBDP1

FALS – BANCO DE DADOS 1

Página 31 de 39

Grupo 12/2002 NumeroPedido Codigo_Vendedor Mes Valor_Venda 1003 10 12/2002 300 1005 20 12/2002 500 1008 20 12/2002 800 Para cada grupo o comando SELECT gerará uma única linha, da seguinte forma: § A coluna MES terá o valor do mês a que se refere o grupo; § A coluna NUMERO_VENDAS terá o número de linha do grupo (COUNT(*)) § A coluna TOTAL_VENDAS_MES terá a soma dos valores da coluna VALOR_VENDA das linhas do grupo. O resultado do SELECT será o seguinte: MES NUMERO_VENDAS TOTAL_VENDAS_MES 01/2003 3 1400 02/2003 2 600 12/2002 3 1600 Exercício:

a) Escreva consulta que produza relatório de vendas agrupado por CODIGO_VENDEDOR;

b) Escreva consulta que produza relatório de vendas agrupado por MÊS e CODIGO_VENDEDOR;

C. HAVING É possível ainda filtrar as linhas do resultado produzido pelo comando SELECT com GROUP BY através da cláusula HAVING. SELECT MES , COUNT(*) AS NUMERO_VENDAS, SUM(VALOR_VENDA) AS TOTAL_VENDAS_MES FROM VENDAS GROUP BY MES HAVING SUM(VALOR_VENDA) > 1000 O resultado gerado seria o seguinte. MES NUMERO_VENDAS TOTAL_VENDAS_MES 01/2003 3 1400 12/2002 3 1600 Note que a aplicação da condição da cláusula HAVING é feita após o processamento do GROUP BY. Se você desejar filtrar linhas antes do processamento do GROUP BY, utilize WHERE. Por exemplo, suponha a consulta a seguir, onde se deseja no resultado apenas meses do ano de 2003.

Page 32: CursoBDP1

FALS – BANCO DE DADOS 1

Página 32 de 39

SELECT MES , COUNT(*) AS NUMERO_VENDAS, SUM(VALOR_VENDA) AS TOTAL_VENDAS_MES FROM VENDAS WHERE DATEPART(YEAR,MES)=2003 GROUP BY MES HAVING SUM(VALOR_VENDA) > 1000 ETAPAS DO PROCESSAMENTO Etapa 1 – Cláusula WHERE – vendas que não tenham sido realizadas em 2003 são desconsideradas.

VENDAS NumeroPedido Codigo_Vendedor Mes Valor_Venda 1001 20 01/2003 100 1002 10 02/2003 200 1004 10 02/2003 400 1006 20 01/2003 600 1007 10 01/2003 700 Etapa 2 – GROUP BY MES NUMERO_VENDAS TOTAL_VENDAS_MES 01/2003 3 1400 02/2003 2 600 Etapa 3 – HAVING MES NUMERO_VENDAS TOTAL_VENDAS_MES 01/2003 3 1400

D. COMPUTE e COMPUTE BY COMPUTE e COMPUTE BY são utilizados para criação de relatórios com totais e subtotais. Tomemos como exemplo a tabela VENDAS utilizada anteriormente. Através da consulta abaixo, podemos gerar um relatório detalhado de todas as vendas realizadas, com subtotais por mês e código vendedor. Importante salientar que as colunas para as quais serão gerados subtotais devem ser obrigatoriamente classificadas (ordenadas) através da cláusula ORDER BY. SELECT NumeroPedido, Codigo_Vendedor, Mes, Valor_Venda FROM VENDAS ORDER BY MES,CODIGO_VENDEDOR COMPUTE COUNT(MES), SUM(VALOR_VENDA) BY MES,Codigo_Vendedor --subtotal COMPUTE COUNT(MES), SUM(VALOR_VENDA) -- total

Page 33: CursoBDP1

FALS – BANCO DE DADOS 1

Página 33 de 39

RESULTADO NumeroPedido Codigo_Vendedor Mes Valor_Venda ------------ --------------- --------------------------- --------------------- 1003 10 2002-12-01 00:00:00 300.0000 cnt ========== 1 sum =================== 300.0000 1005 20 2002-12-01 00:00:00 500.0000 1008 20 2002-12-01 00:00:00 800.0000 cnt ========== 2 sum =================== 1300.0000 1007 10 2003-01-01 00:00:00 700.0000 cnt ========== 1 sum =================== 700.0000 1001 20 2003-01-01 00:00:00 100.0000 1006 20 2003-01-01 00:00:00 600.0000 cnt ========== 2 sum =================== 700.0000 1002 10 2003-02-01 00:00:00 200.0000 1004 10 2003-02-01 00:00:00 400.0000 cnt ========== 2 sum =================== 600.0000 cnt ========== 8

Page 34: CursoBDP1

FALS – BANCO DE DADOS 1

Página 34 de 39

sum =================== 3600.0000 (14 row(s) affected)

Page 35: CursoBDP1

FALS – BANCO DE DADOS 1

Página 35 de 39

VIII. Manipulação Avançada de Dados

A. Projeção – Select Distinct ... É com o comando SELECT DISTINCT que se realiza em SQL a operação de projeção de uma tabela (ou relação) em relação a uma ou mais de suas colunas. Considere a tabela abaixo. FUNCIONARIOS

NumeroFunc NomeFunc DataNascimento 1000 Mariana 17/04/1987 1010 Ana 01/01/2000 1020 Maria 30/10/1964 1030 Jussara 17/04/1987 O comando: Select DataNacimento from Funcionarios Produz o seguinte resultado:

DataNascimento 17/04/1987 01/01/2000 30/10/1964 17/04/1987 Já com o comando: Select distinct DataNacimento from Funcionários Temos:

DataNascimento 17/04/1987 01/01/2000 30/10/1964 Ou seja, com DISTINCT, não há repetição da data 17/04/1987, não há duas linhas iguais no resultado produzido. Dizemos que este resultado é a projeção da tabela (ou relação) Funcionários na coluna DataNascimento. A projeção pode ser feita sobre mais de uma coluna. O resultado será uma tabela (relação) composta pelas colunas projetadas e por linhas da tabela original, sem repetição nestas colunas.

Page 36: CursoBDP1

FALS – BANCO DE DADOS 1

Página 36 de 39

B. Operador LIKE Através do operador LIKE é possível fazer comparações entre expressões String (cadeia de caracteres) com um padrão criado por caracteres normais e caracteres curingas. Por exemplo, se quisermos recuperar da tabela Funcionário dados de todos os funcionários cujo nome começa com MA, poderíamos escrever a seguinte consulta: Select * from funcionários where NomeFunc Like ‘MA%’ Aqui o caracter % é um curinga, significando qualquer String de zero ou mais caracteres. Os dados de Mariana e Maria seriam apresentados como resultado do comando. Segue tabela com a descrição de todos os caracteres curingas utilizáveis como o operador LIKE (extraída do Books on Line). Curinga Descrição Exemplo % Qualquer string de

zero ou mais caracteres

SELECT * FROM livros WHERE titulo LIKE ‘%computer%’. Encontra todos os livros que tenham a palavra ‘computer’ em qualquer parte de seu título.

_ (underscore) Um único caracter. SELECT * FROM alunos WHERE pnome LIKE ‘_aulo’. Encontra todos os alunos cujo primeiro nome tem cinco letras e termina em ‘aulo’ (Paulo, Saulo, etc).

[ ] Um caracter dentro de um intervalo especificado ([a-f]) ou conjunto ([abcdef]).

SELECT * FROM alunos WHERE unome LIKE ‘[C-P]arsen’ Encontra todos os alunos cujo ultimo nome termina em ‘arsen’ e começa com C ou D ou E ou …ou P, por exemplo: Carsen, Larsen, Karsen, etc.

[^] Um caracter fora de um intervalo especificado ([^a-f]) ou conjunto ([^abcdef]).

SELECT * FROM alunos WHERE unome LIKE ‘de[^l]%’. Alunos cujo último nome começa com ‘DE’e a terceira letra não é o ‘L’.

Page 37: CursoBDP1

FALS – BANCO DE DADOS 1

Página 37 de 39

C. SELECT … INTO Com o comando SELECT…INTO é possível criar uma nova tabela no banco de dados a partir de outra(s) tabela(s) existente(s). Por exemplo: Select NumeroFunc, NomeFunc Into dbo.FuncAuxiliar from Funcionarios Where datepart(year,DataNascimento) >= 2000 O comando cria uma nova tabela de nome FuncAuxiliar, de propriedade do usuário DBO, com duas colunas: NumeroFunc e NomeFunc. As linhas da tabela Funcionários em que DataNascimento for posterior ou igual a 01/01/2000 são copia para a nova tabela. Obs: Para que este tipo de comando seja executado, é necessário que a opção 'select into/bulkcopy' esteja ativa no bando de dados. Após a execução de um comando SELECT...INTO não será mais possível fazer backup do log de trasações. Para ativar a opção, execute o comando abaixo: Execute sp_dboption nome_database, 'select into/bulkcopy', true

D. INSERT ... SELECT ... Você pode copiar dados de uma tabela para outra utilizando o comando INSERT conjuntamente com o comando SELECT. Exemplificaremos utilizando as tabelas abaixo. TAB_A

Coluna_A Coluna_B 1001 A1 2002 D2 TAB_B

Coluna_C Coluna_D Coluna_E F3 1/1/2000 3003 G2 2/2/2000 4004 H5 3/3/1999 5005 Considerando que as columas ‘Coluna_A’ (TAB_A) e ‘Coluna_E’ (TAB_B) tenham o mesmo domínio (ou similar), ou seja, tenham sido definidas com o mesmo tipo de dado (ou similar que possibilite conversão). Idem para as colunas ‘Coluna_B’ (TAB_A) e ‘Coluna_C’ (TAB_B). Poderiamos inserir em TAB_A três novas linhas com os dados provenientes de TAB_B através do seguinte comando:

Page 38: CursoBDP1

FALS – BANCO DE DADOS 1

Página 38 de 39

Insert TAB_A select Coluna_E, Coluna_C from TAB_B O SELECT poderia ter uma cláusula WHERE especificando as linhas a serem copiadas.

E. UNION Através do operador UNION é possível combinar o resultado de duas consultas, desde que ambas produzam seus resultados com a mesma quantidade de colunas e com os mesmos tipos de dados (ou similar) coluna a coluna. Por exemplo: Considere as tabelas utilizadas no exemplo do item anterior, o comando abaixo produz o seguinte resultado. Select Coluna_B,Coluna_A from TAB_A union all select Coluna_C, Coluna_E from TAB_B

Coluna_B Coluna_A A1 1001 D2 2002 F3 3003 G2 4004 H5 5005 Com a palavra ALL todas as linhas são incorporadas no resultado final, incluindo duplicadas. Se não especificada, linhas duplicadas são removidas.

F. UPDATE …FROM … Pode-se alterar linhas de uma tabela baseando-se em valores armazenados em outra tabela. Update funcionarios set salario = salario * 1.1 From funcionarios f inner join dependentes d on f.NumeroFunc = d.NumeroFunc No comando acima, apenas os funcionários com pelo menos 1 dependente terão seus salários aumentados em 10 %. Isto se deve ao fato de que no INNER JOIN apenas as linhas em funcionários com correspondentes em dependentes compõem o resultado do join. Poderíamos realizar a mesma operação utilizando subquerys, conforme abaixo: Update funcionarios set salario = salario * 1.1 Where exists (select * from dependentes d where funcionarios.numerofunc=d.numerofunc) Note que apenas quando a subquery gerar alguma linha, ou seja quando existir em Dependentes alguma linha com o valor em NumeroFunc igual ao valor em NumeroFunc de Funcionário, é que o WHERE do UPDATE será VERDADEIRO e a linha de Funcionário atualizada.

Page 39: CursoBDP1

FALS – BANCO DE DADOS 1

Página 39 de 39

G. DELETE … FROM … De forma análoga aos exemplos do item anterior, podemos excluir linhas de uma tabela com base em valores de outras tabelas. Delete funcionarios From funcionarios f inner join dependentes d on f.NumeroFunc = d.NumeroFunc O comando acima exclui da tabela Funcionários todos os funcionários com pelo menos 1 dependente (é só um exemplo!). Isso se não existir uma FOREIGN KEY entre Funcionários e Dependentes. Abaixo o mesmo exemplo utilizando subquery, só que desta vez excluindo os funcionários sem dependentes (repare no not). Delete funcionarios Where not exists (select * from dependentes d where funcionarios.numerofunc=d.numerofunc)