Introdução
Quando os Bancos de Dados Relacionais estavam sendo desenvolvidos, foram
criadas linguagens destinadas à sua manipulação. O Departamento de Pesquisas da
IBM, desenvolveu a SQL como forma de interface para o sistema de BD relacional
denominado SYSTEM R, início dos anos 70. Em 1986 o American National Standard
Institute ( ANSI ), publicou um padrão SQL.
A SQL estabeleceu-se como linguagem padrão de Banco de Dados Relacional.
SQL apresenta uma série de comandos que permitem a definição dos dados,
chamada de DDL (Data Definition Language), composta entre outros pelos comandos
Create, que é destinado a criação do Banco de Dados, das Tabelas que o compõe,
além das relações existentes entre as tabelas. Como exemplo de comandos da
classe DDL temos os comandos Create, Alter e Drop.
Os comandos da série DML (Data Manipulation Language), destinados a
consultas, inserções, exclusões e alterações em um ou mais registros de uma ou
mais tabelas de maneira simultânea. Como exemplo de comandos da classe DML temos
os comandos Select, Insert, Update e Delete.
Uma subclasse de comandos DML, a DCL (Data Control Language), dispõe de
comandos de controle como Grant e Revoke.
A Linguagem SQL tem como grandes virtudes sua capacidade de gerenciar
índices, sem a necessidade de controle individualizado de índice corrente, algo
muito comum nas linguagens de manipulação de dados do tipo registro a registro.
Outra característica muito importante disponível em SQL é sua capacidade de
construção de visões, que são formas de visualizarmos os dados na forma de
listagens independente das tabelas e organização lógica dos dados.
Outra característica interessante na linguagem SQL é a capacidade que
dispomos de cancelar uma série de atualizações ou de as gravarmos, depois de
iniciarmos uma seqüência de atualizações. Os comandos Commit e Rollback são
responsáveis por estas facilidades.
Devemos notar que a linguagem SQL consegue implementar estas soluções,
somente pelo fato de estar baseada em Banco de Dados, que garantem por si mesmo
a integridade das relações existentes entre as tabelas e seus índices.
O Ambiente SQL
Analisaremos dois softwares destinados a linguagem SQL: o ISQL e o
WinSQL.
O ISQL faz parte do pacote Ideo e permite construirmos Banco de Dados e
tabelas diretamente pelo interpretador SQL, bem como acessarmos as Bases de
Dados construídas no Ideo. O ISQL pode gerar Banco de Dados em seu ambiente
proprietário (Watcom, hoje pertencente a Symantech) ou ainda nos consagrados
Banco de Dados Oracle, SyBase, Ingres (Computer Associates), DB/2 (IBM) e
Informix. Devido as origens do Ideo, o Banco de Dados SQL Server da Microsoft
não é suportado, pois este Banco de Dados originou-se na microinformática e
somente recentemente a Sapiens migrou seu software dos Ambientes Mainframe e
Unix.
Já o WinSQL é um ambiente inteiramente gráfico (ao contrário do ISQL que
guarda fortes características do ambiente em Mainframe onde se originou),
destinado ao aprendizado, portanto somente pode criar Banco de Dados em seu
formato proprietário.
Os comandos do WinSQL por serem visuais, não necessitam de maior
esclarecimento além daqueles já contidos no Help. Já o ISQL apesar de possuir um
Help bastante completo necessita, em nosso entender, de alguns esclarecimentos
iniciais.
Uma série de comandos do interpretador, que funciona de forma análoga àquela
existente no dBase modo interativo, podem ser utilizados pelo usuário. Não
obstante alguns comandos tenham nome idêntico a alguns comandos do DOS, devemos
notar que muitas vezes sua sintaxe é bastante diversa daquele sistema
operacional. Vamos destacar os seguintes comandos:
\EDIT - Carrega o editor de bloco de notas do windows, o qual serve para
a criação de arquivos para serem executados no Ideo.
Ex: \edit teste.sql
\CD - Mostra o diretório onde serão gravados os arquivos *.sql, *.dic
*.dat.
Permite alterar para determinado diretório (\CD DADO, fará com que o
diretório corrente passe a ser C:\DADO, caso o diretório corrente fosse a raiz.
Permite retornar ao diretório de nível inferior (\CD ..). Atenção
este comando não é análogo ao Change Dir do DOS, na medida em que não permite a
mudança direta de um subnível do diretório X para um diretório Y por exemplo.
\DEFAULT <drive> - permite alterarmos o drive corrente.
Ex: \DEFAULT F:
\INCLUDE - Executa arquivos *.sql. O arquivo .sql deverá conter uma série
de instruções SQL.
Ex: \include teste.sql
@< file > ; - Também executa arquivos *.sql.
Ex: @teste.sql;
EXIT; - Finaliza a sessão do ISQL. ou ( \QUIT )
COMMIT; - Confirma a transação.
ROLLBACK; - Desfaz a transação.
SHOW <tabela>; - Mostra os nomes das tabelas existentes em
determinado banco de dados.
Ex: SHOW tables;
SHOW FIELDS FOR <tabela>; - Mostra os campos de determinada
tabela.
Ex: SHOW FIELDS FOR ATOR;
SHOW INDEXES FOR <tabela>; - Lista de indices da tabela.
SHOW RELATIONSHIPS FOR <tabela>; - Lista de relacionamentos da
tabela.
LIST <tabela> ; - Lista conteúdo da tabela.
Estudo Dirigido
Consideramos a linguagem SQL eminentemente prática, desta forma criamos um
exmplo completo e propomos um exercício análogo, para tornar o estudante apto a
manipular a linguagem SQL de maneira prática, em conformidade a filosofia
eminentemente prática da Linguagem SQL.
O exemplo apresentado nesta apostila já está disponível para sua utilização
do diretório \IDEO\SQL, bastando para isso você copiar este exemplo para seu
diretório e iniciar os testes de forma simultânea a
sua apresentação pelo professor.
É conveniente que você procure montar o exercício clássico (mundo), de forma
a testar todos os conhecimentos adquiridos. Para tanto analise cuidadosamente o
exercício proposto a seguir, e construa as relações, tabelas e queries adequadas
ao final de cada exemplo.
Exercício: Elabore Banco de Dados Mundo que contenha as seguintes
tabelas: Continente, País e Cidade. Observe que uma cidade deverá pertencer
exclusivamente a um país e que cada país deverá estar cadastrado no continente
onde se localizar sua área mais importante. Assim não obstante grande parte do
território russo fazer parte Ásia, a Rússia será considerada fazendo parte da
Europa. Assim teríamos basicamente uma relação do tipo:
Cidade --> País --> Continente
PARTE I - Comandos de Modificações do Esquema e Criação de Banco de
Dados
Comando Create
Este comando permite a criação de tabelas no banco de dados ou mesmo de sua
criação.
Sintaxe:
CREATE DATABASE < nome_db >;
onde:
nome_db - indica o nome do Banco de Dados a ser criado.
Sintaxe:
CREATE TABLE < nome_tabela >
( nome_atributo1 < tipo > [ NOT NULL ],
nome_atributo2 < tipo > [ NOT NULL ],
......
nome_atributoN < tipo > [ NOT NULL ] ) ;
onde:
nome_table - indica o nome da tabela a ser criada.
nome_atributo - indica o nome do campo a ser criado na tabela.
tipo - indica a definição do tipo de atributo ( integer(n), char(n),
real(n,m), date... ).
n- número de dígitos ou de caracteres
m- número de casas decimais
Agora vamos criar uma tabela. Use o editor para salvar em um arquivo ou
digite na linha de comando do ISQL.
CREATE DATABASE TRABALHO;
O comando acima criou um Banco de Dados, porém este na verdade não passa de
uma abertura no diretório, pois não conta com nenhuma tabela.
Agora criaremos as tabelas que estarão contidas no Banco de Dados
TRABALHO.
A primeira Tabela será a de Departamentos (DEPT). Esta tabela conterá além
dos campos também sua chave primária, suas chaves estrangeiras e também seus
índices. A segunda tabela será a de Empregados (EMP), que também será
criada.
Não devemos esquecer de primeiramente abrirmos o Banco de Dados.
Diferentemente do que ocorre em alguns aplicativos, em SQL o fato de criarmos um
Banco de Dados, não significa que o banco recém criado já está preparado para
utilização. A instrução a seguir, providencia a abertura do Banco de Dados
criado.
OPEN DATABASE TRABALHO;
Agora estamos prontos para criarmos as tabelas necessárias. Lembramos aos
Estudantes, que o Arquivo TABS.SQL, contém todas as instruções necessárias para
criação do Banco de Dados Trabalho e de suas tabelas. Já o Arquivo DADOS.SQL irá
popular estas tabelas. Para efeitos didáticos, criamos as tabelas de forma que
sua população, em outras palavras os dados, sejam facilmente referenciáveis
pelos estudantes. Assim sendo, na tabela de departamentos, contamos com 5
departamentos, cada um deles tendo seu gerente. Todos os "gerentes" tem nomes de
cantoras brasileiras (Gal Costa, Marina Lima, etc), todos os "operários" tem
nomes de jogadores de futebol, todas as vendedoras tem nomes de jogadoras de
volei, todas as balconistas tem nome de jogadoras de basquete e o presidente da
empresa exemplo, tem o mesmo nome do presidente do Brasil. Desta forma os testes
devem resultar em grupos bastante definidos. Assim se você estiver listando
Gerentes e aparecer um homônimo da Ana Paula (jogadora de volei), verifique sua
query atentamente, pois muito provavelmente a mesma estará errada.
A seguir código necessário a criação da tabela Departamento e seu índice:
create table Dept
(DepNume integer(4) not null,
DepNome char(20) not null,
DepLoca char(20) not null,
DepOrca integer(12,2),
primary key (DepNume)
);
create unique index DepNum on Dept (DepNume asc);
Note-se que a chave primária já está definida juntamente com o registro da
tabela. A criação do índice, que por razões óbvias deve ser criado após a
tabela, naturalmente é um comando totalmente independente do primeiro create,
que serviu para criar a tabela e suas característica básicas.
Vamos analisar o código necessário para a criação da tabela de empregados,
apresentado a seguir:
create table Emp
(EmpNume integer(5) not null,
EmpNome char(30) not null,
EmpGere integer(5) ,
EmpServ char(20) ,
DepNume integer(4) not null,
EmpAdmi date not null,
EmpSala integer(10,2),
EmpComi integer(10,2),
primary key (EmpNume),
foreign key has (DepNume)
references Dept
on delete restrict
on update cascade
);
create unique index EmpNum on Emp (EmpNume asc);
create index EmpDep on Emp (DepNume asc);
A Tabela de Empregados não poderia ter sido criada antes da Tabela de
Departamento, pois contém uma referência direta àquela tabela. Quando declaramos
que DepNume é chave estrangeira, promovemos de fato a ligação do cadastro
de empregados como o cadastro de departamentos. Ao restringirmos as exclusões,
permitimos a existência de funcionários não alocados a nenhum departamento.
Apesar desta prática ser contrária a tese de que devemos possuir apenas tuplas
perfeitamente relacionáveis em nossas tabelas, podemos deixar esta pequena
abertura, pois um usuário que excluisse inadivertidamente determinado
departamento, acabaria por excluir também uma grande quantidade de funcionários,
que estivessem ligados a este departamento.
Já a atualização em cascata dos códigos de departamento é uma boa
providência, na medida em que teremos, uma vez alterado algum código de
departamento, a atualização imediata de todos os funcionários pertencentes ao
departamento cujo código foi modificado.
Observações:
1- Observar que os índices são parte intrínseca das tabelas.
2- A integridade relacional é garantida pelo Banco de Dados e não pelo
aplicativo.
3- Exclusões ou Alterações em Chaves Primárias, podem acarretar exclusões,
anulações ou até mesmo perda de integridade nas tabelas onde esta chave
primária existir como chave estrangeira. Portanto é imprescindível muito
cuidado quando da elaboração do Banco de Dados. Uma tentação muito comum ao
estudante é começar criando as tabelas do Banco de Dados sem prévia
Normalização. Este talvez seja o melhor caminho para perder-se tempo em vão,
pois quando você terminar de projetar suas telas de entrada de dados, notará
"que nada funciona!". Esta será a senha para usar o velho comando DEL do DOS e
depois começar tudo de novo ...
Comando Drop
Este comando elimina a definição da tabela, seus dados e referências.
Sintaxe:
DROP TABLE < nome_tabela > ;
Ex:
DROP TABLE EMP;
Comando Alter
Este comando permite inserir/eliminar atributos nas tabelas já
existentes.
Comando:
ALTER TABLE < nome_tabela > ADD / DROP (
nome_atributo1 < tipo > [ NOT NULL ],
nome_atributoN < tipo > [ NOT NULL ] ) ;
Não existe nenhum comando SQL que permita eliminar algum atributo de uma
relação já definida. Assim caso você desejar eliminar uma chave primária
devidamente referenciada em outra tabela como chave estrangeira, ao invés de
obter a eliminação do campo, obterá apenas um erro.
Além do comando DROP que poderá eliminar uma tabela e suas relações, também
podemos criar uma relação que tenha os atributos que se deseja, copiar-se a
relação antiga sobre a nova e apgando-se então a relação que originalmente
desejávamos eliminar.
Ex:
ALTER TABLE DEPT (
ADD DEPSALA DECIMAL (10,2) );
Exercício: Criar o Banco de Dados Mundo. Observar que se um continente
for excluído, todos os países contidos em tal continente também o serão. Esta
situação é conhecida como exclusão em Cascata. Observar também que a exclusão de
um País eliminará todas as Cidades contidas no mesmo.
Prática
O Exemplo Trabalho já possue pequeno programa destinado a construção das
tabelas contidas no Banco de Dados TRABALHO. Execute "trabalho.sql" de forma a
obter as tabelas acima sem necessidade de digitar as instruções SQL de maneira
interativa.
Para tanto, você deverá copiar para seu diretório de trabalho o arquivo
"trabalho.sql" do diretório \IDEO\SQL.
Execute: "@trabalho;" que deverá:
- Criar o banco de dados Trabalho.
- Abrir o banco de dados Trabalho.
- Criar as Tabelas, Indices e Relações contidas neste Banco de Dados.
Posteriormente execute o comando "show tables", que deverá exibir as tabelas
"dept" e "emp".
E ao executar "show fields dept" serão exibidos os campos da tabela
"dept".
Copie e execute enchetra.sql do diretório \IDEO\SQL de forma a obter um
conjunto de dados preparados para os testes a seguir apresentados.
Na próxima etapa de nosso curso, estaremos realizando pesquisas utilizando a
instrução Select. Julgamos conveniente que os estudantes populem seu exercício e
realizem exercícios análogos aos apresentados na Base de Dados Trabalho no Banco
de Dados Mundo.
Parte II - Comandos de Consulta ao Esquema
Devemos ressaltar que a linguagem SQL é utilizada tanto pelos profissionais
responsáveis pelos dados, onde é ressaltada a figura do Administrador do Banco
de Dados e dos Analistas de Dados, como também pelos desenvolvedores de
Aplicações. Enquanto àqueles estão preocupados com o desempenho, integridade do
Banco de Dados e utilizam toda gama de recusos disponíveis no SQL, estes estão
preocupados apenas em "transformar dados em informações", portanto para os
desenvolvedores costuma-se dizer que conhecer o "select" já basta. Em nosso
curso enfatizaremos a importância de TODOS os comandos do SQL, mas sabemos de
antemão que os professores responsáveis pelas linguagens IDEO, VB e Delphi,
ressaltarão a preponderância da instrução "select", que será apresentada a
seguir e não no final do curso de SQL como geralmente acontece, pelo fato de que
diversas disciplinas necessitam especificamente deste comando, que passaremos a
apresentar:
1) Seleção de todas os campos (ou colunas) da tabela de
Departamentos.
Resp:
SELECT * FROM DEPT;
O exemplo utiliza o coringa "*" para selecionar as colunas na ordem em que
foram criadas. A instrução Select, como pudemos observar seleciona um
grupo de registros de uma (ou mais) tabela(s). No caso a instrução From
nos indica a necessidade de pesquisarmos tais dados apenas na tabela Dept.
Where como base das Restrição de tuplas.
A cláusula "where" corresponde ao operador restrição da álgebra relacional.
Contém a condição que as tuplas devem obedecer a fim de serem listadas. Ela pode
comparar valores em colunas, literais, expressões aritméticas
ou funções.
A seguir apresentamos operadores lógicos e complementares a serem utilizados
nas expressões apresentadas em where.
Operadores lógicos
operador significado
= igual a
> maior que
>= maior que ou igual a
< menor que
<= menor que ou igual a
Exemplos:
SELECT EMPNOME, EMPSERV
FROM EMP
WHERE DEPNUME > 10;
SELECT EMPNOME, EMPSERV
FROM EMP
WHERE EMPSERV = 'GERENTE';
O conjunto de caracteres ou datas devem estar entre apóstrofes (‘) na
cláusula "where".
2) Selecione todos os departamentos cujo orçamento mensal seja maior que
100000. Apresente o Nome de tal departamento e seu orçamento anual, que será
obtido multiplicando-se o orçamento mensal por 12.
Resp: Neste problema precisamos de uma expressão que é a combinação de um ou
mais valores, operadores ou funções que resultarão em um valor. Esta expressão
poderá conter nomes de colunas, valores numéricos, constantes e operadores
aritméticos.
SELECT DEPNOME, DEPORCA * 12
FROM DEPT
WHERE DEPORCA > 100000;
3) Apresente a instrução anterior porém ao invés dos "feios" DepNome e
DepOrca, os Títulos Departamento e Orçamento.
Resp: Neste exemplo deveremos denominar colunas por apelidos. Os nomes das
colunas mostradas por uma consulta, são geralmente os nomes existentes no
Dicionário de Dado, porém geralmente estão armazenados na forma do mais puro
"informatiquês", onde "todo mundo" sabe que CliCodi significa Código do Cliente.
É possível (e provável) que o usuário desconheça estes símbolos, portanto
devemos os apresentar dando apelidos às colunas "contaminadas" pelo
informatiquês, que apesar de fundamental para os analistas, somente são vistos
como enigmas para os usuários.
SELECT DEPNOME "DEPARTAMENTO", DEPORCA * 12 "ORCAMENTO ANUAL"
FROM DEPT
WHERE DEPORCA > 100000;
4) Apresente todos os salários existentes na empresa, porém omita eventuais
duplicidades.
Resp: A cláusula Distinct elimina duplicidades, significando que somente
relações distintas serão apresentadas como resultado de uma pesquisa.
SELECT DISTINCT EMPSERV
FROM EMP;
5) Apresente todos os dados dos empregados, considerando sua existência
física diferente de sua existência lógica (ou seja devidamente
inicializado).
Resp: Desejamos um tratamento diferenciado para valores nulos. Qualquer
coluna de uma tupla que não contenha informações é denominada de nula, portanto
informação não existente. Isto não é o mesmo que "zero", pois zero é um número
como outro qualquer, enquanto que um valor nulo utiliza um "byte" de armazenagem
interna e são tratados de forma diferenciada pelo SQL.
SELECT EMPNOME, EMPSALA + EMPCOMI
FROM EMP;
SELECT EMPNOME, NVL(EMPSALA,0) + NVL(EMPCOMI,0)
FROM EMP;
Obs: a função "NVL" é utilizada para converter valores nulos em zeros.
6) Apresente os nomes e funções da cada funcionário contidos na tabela
empresa, porém classificados alfabeticamente (A..Z) e depois alfabeticamente
invertido (Z..A).
Resp: A cláusula Order By modificará a ordem de apresentação do resultado da
pesquisa (ascendente ou descendente).
SELECT EMPNOME, EMPSERV
FROM EMP
ORDER BY EMPNOME;
SELECT EMPNOME, EMPSERV
FROM EMP
ORDER BY EMPPNOME DESC;
Nota: Também é possível fazer com que o resultado da pesquisa venha
classificado por várias colunas. Sem a claúsula "order by" as linhas serão
exibidas na sequência que o SGBD determinar.
7) Selecione os Nomes dos Departamentos que estejam na fábrica.
Resp:
SELECT DEPNOME
FROM DEPT
WHERE DEPLOCA = "SAO PAULO";
O exemplo exigiu uma restrição (São Paulo) que nos obrigou a utilizar da
instrução Where. Alguns analistas costumam afirmar em tom jocoso que SQL não
passa de
"Selecione algo De algum lugar Onde se verificam tais relações"
Acreditamos que esta brincadeira pode ser útil ao estudante, na medida em que
facilita sua compreensão dos objetivos elementares do SQL.
Demais Operadores
Operador Significado
between ... and ... entre dois valores ( inclusive )
in ( .... ) lista de valores
like com um padrao de caracteres
is null é um valor nulo
Exemplos:
SELECT EMPNOME, EMPSALA
FROM EMP
WHERE EMPSALA BETWEEN 500 AND 1000;
SELECT EMPNOME, DEPNUME
FROM EMP
WHERE DEPNUME IN (10,30);
SELECT EMPNOME, EMPSERV
FROM EMP
WHERE EMPNOME LIKE 'F%';
SELECT EMPNOME, EMPSERV
FROM EMP
WHERE EMPCOMI IS NULL;
O símbolo "%" pode ser usado para construir a pesquisa ("%" = qualquer
sequência de nenhum até vários caracteres).
Operadores Negativos
operador descrição
<> diferente
not nome_coluna = diferente da coluna
not nome_coluna > não maior que
not between não entre dois valores informados
not in não existente numa dada lista de valores
not like diferente do padrao de caracteres informado
is not null não é um valor nulo
8) Selecione os Empregados cujos salários sejam menores que 1000 ou maiores
que 3500.
Resp: Necessitaremos aqui a utilização de expressão negativas. A seguir
apresentamos operadores negativos.
SELECT EMPNOME, EMPSALA
FROM EMP
WHERE EMPSALA NOT BETWEEN 1000 AND 3500;
9) Apresente todos os funcionários com salários entre 200 e 700 e que sejam
Vendedores.
Resp: Necessitaremos de consultas com condições múltiplas.
Operadores "AND" (E) e "OR" (OU).
SELECT EMPNOME, EMPSALA, EMPSERV
FROM EMP
WHERE EMPSALA BETWEEN 700 AND 2000
AND EMPSERV = 'VENDEDOR';
10) Apresente todos os funcionários com salários entre 200 e 700 ou que sejam
Vendedores.
Resp:
SELECT EMPNOME, EMPSALA, EMPSERV
FROM EMP
WHERE EMPSALA BETWEEN 700 AND 2000
OR EMPSERV = 'VENDEDOR';
11) Apresente todos os funcionários com salários entre 200 e 700 e que
sejam Vendedores ou Balconistas.
Resp:
SELECT EMPNOME, EMPSALA, EMPSERV
FROM EMP
WHERE EMPSALA BETWEEN 700 AND 2000
AND ( EMPSERV = 'BALCONISTA' OR EMPSERV = 'VENDEDOR' );
Funções de Caracteres
Lower - força caracteres maiúsculos aparecerem em minúsculos.
Upper - força caracteres minúsculos aparecerem em maiúsculos.
Concat(x,y)- concatena a string "x" com a string "y".
Substring(x,y,str)- extrai um substring da string "str", começando em "x", e
termina em "y".
To_Char(num)- converte um valor numérico para uma string de caracteres.
To_Date(char,fmt)- converte uma string caracter em uma data.
^Q - converte data para o formato apresentado.
12) Apresente o nome de todos os empregados em letras minúsculas.
Resp:
SELECT LOWER( EMPNOME )
FROM EMP;
13) Apresente o nome de todos os empregados (somente as 10 primeiras
letras).
Resp:
SELECT SUBSTRING (1,10,EMPNOME)
FROM EMP;
14) Apresente o nome de todos os empregados admitidos em 01/01/80.
Resp:
SELECT *
FROM EMP
WHERE EMPADMI = ^Q"DD-AAA-YYYY"("01-JAN-1980");
ou
SELECT *
FROM EMP
WHERE EMPADMI = ^Q("01-JAN-1980");
Funções Agregadas (ou de Agrupamento)
função retorno
avg(n) média do valor n, ignorando nulos
count(expr) vezes que o número da expr avalia para algo nao nulo
max(expr) maior valor da expr
min(expr) menor valor da expr
sum(n) soma dos valores de n, ignorando nulos
15) Apresente a Média, o Maior, o Menor e também a Somatória dos Salários
pagos aos empregados.
Resp:
SELECT AVG(EMPSALA) FROM EMP;
SELECT MIN(EMPSALA) FROM EMP;
SELECT MAX(EMPSALA) FROM EMP;
SELECT SUM(EMPSALA) FROM EMP;
Agrupamentos
As funções de grupo operam sobre grupos de tuplas(linhas). Retornam
resultados baseados em grupos de tuplas em vez de resultados de funções por
tupla individual. A claúsula "group by" do comando "select" é utilizada para
dividir tuplas em grupos menores.
A cláusula "GROUP BY" pode ser usada para dividir as tuplas de uma tabela em
grupos menores. As funções de grupo devolvem uma informação sumarizada para cada
grupo.
16) Apresente a média de salário pagos por departamento.
Resp:
SELECT DUPNUME, AVG(EMPSALA)
FROM EMP
GROUP BY DEPNUME;
Obs.: Qualquer coluna ou expressão na lista de seleção, que não for uma
função agregada, deverá constar da claúsula "group by". Portanto é errado tentar
impor uma "restrição" do tipo agregada na cláusula Where.
Having
A cláusula "HAVING" pode ser utilizada para especificar quais grupos deverão
ser exibidos, portanto restringindo-os.
17) Retome o problema anterior, porém apresente resposta apenas para
departamentos com mais de 10 empregados.
Resp:
SELECT DEPNUME, AVG(EMPSALA)
FROM EMP
GROUP BY DEPNUME
HAVING COUNT(*) > 3;
Obs.: A claúsula "group by" deve ser colocada antes da "having", pois os
grupos são formados e as funções de grupos são calculadas antes de se resolver a
cláusula "having".
A cláusula "where" não pode ser utilizada para restringir grupos que deverão
ser exibidos.
Exemplificando ERRO típico - Restringindo Média Maior que 1000:
SELECT DEPNUME, AVG(EMPSALA)
FROM EMP
WHERE AVG(SALARIO) > 1000
GROUP BY DEPNUME;
( Esta seleção está ERRADA! )
SELECT DEPNUME, AVG(EMPSALA)
FROM EMP
GROUP BY DEPNUME
HAVING AVG(EMPSALA) > 1000;
( Seleção Adequada )
Seqüência no comando "Select":
SELECT coluna(s)
FROM tabela(s)
WHERE condição(ões) da(s) tupla(s)
GROUP BY condição(ões) do(s) grupo(s) de tupla(s)
HAVING condição(ões) do(s) grupo(s) de tupla(s)
ORDER BY coluna(s);
A "sql" fará a seguinte avaliação:
a) WHERE, para estabelecer tuplas individuais candidatas (não pode conter
funções de grupo)
b) GROUP BY, para fixar grupos.
c) HAVING, para selecionar grupos para exibiçao.
Equi-Junção ( Junção por igualdade )
O relacionamento existente entre tabelas é chamado de equi-junção, pois os
valores de colunas das duas tabelas são iguais. A Equi-junção é possível apenas
quando tivermos definido de forma adequada a chave estrangeira de uma tabela e
sua referência a chave primária da tabela precedente. Apesar de admitir-se em
alguns casos, a equi-junção de tabelas, sem a correspondência Chave
Primária-Chave Estrangeira, recomendamos fortemente ao estudante não utilizar
este tipo de construção, pois certamente em nenhum momento nos exemplos
propostos em nossa disciplina ou nas disciplinas de Análise e Projeto de
Sistemas, serão necessárias tais junções.
18) Listar Nomes de Empregados, Cargos e Nome do Departamento onde o
empregado trabalha.
Resp: Observemos que dois dos três dados solicitados estão na Tabela Emp,
enquanto o outro dado está na Tabela Dept. Deveremos então acessar os dados
restringindo convenientemente as relações existentes entre as tabelas. De fato
sabemos que DEPNUME é chave primária da tabela de Departamentos e também é chave
estrangeira da Tabela de Empregados. Portanto, este campo será o responsável
pela equi-junção.
SELECT A.EMPNOME, A.EMPSERV, B.DEPNOME
FROM EMP A, DEPT B
WHERE A.DEPNUME = B.DEPNUME;
Obs.: Note que as tabelas quando contém colunas com o mesmo nome, usa-se um
apelido "alias" para substituir o nome da tabela associado a coluna. Imagine que
alguém tivesse definido NOME para ser o Nome do Empregado na Tabela de
Empregados e também NOME para ser o Nome do Departamento na Tabela de
Departamentos. Tudo funcionaria de forma adequada, pois o aliás se
encarregaria de evitar que uma ambiqüidade fosse verificada. Embora SQL resolva
de forma muito elegante o problema da nomenclatura idêntica para campos de
tabelas, recomendamos que o estudante fortemente evite tal forma de nomear os
campos. O SQL nunca confundirá um A.NOME com um B.NOME, porém podemos afirmar o
mesmo de nós mesmos?
19) Liste os Códigos do Cada Funcionário, seus Nomes, seus Cargos e o nome
do Gerente ao qual este se relaciona.
Resp: Precisamos criar um auto-relacionamento, ou seja, juntar uma tabela a
ela própria. É possível juntarmos uma tabela a ela mesma com a utilização de
apelidos, permitindo juntar tuplas da tabela a outra tuplas da mesma tabela.
SELECT A.EMPNUME, A.EMPNOME, A.EMPSERV, B.EMPNOME
FROM EMP A, EMP B
WHERE A.EMPGERE = B.EMPNUME;
As Sub-Consultas
Uma sub-consulta é um comando "select" que é aninhado dentro de outro
"select" e que devolve resultados intermediários.
20) Relacione todos os nomes de funcionários e seus respectivos cargos, desde
que o orçamento do departamento seja igual a 300000.
Resp:
SELECT EMPNOME, EMPSERV
FROM EMP A
WHERE 300000 IN ( SELECT DEPORCA
FROM DEPT
WHERE DEPT.DEPNUME = A.DEPNUME );
Nota: Observe que a cláusula IN torna-se verdadeira quando o atributo
indicado está presente no conjunto obtido através da subconsulta.
21) Relacione todos os departamentos que possuem empregados com remuneração
maior que 3500.
Resp:
SELECT DEPNOME
FROM DEPT A
WHERE EXISTS (SELECT *
FROM EMP
WHERE EMPSALA > 3500 AND EMP.DEPNUME = A.DEPNUME');
Nota: Observe que a cláusula EXISTS indica se o resultado de uma pesquisa
contém ou não tuplas. Observe também que poderemos verficar a não existência
(NOT EXISTS) caso esta alternativa seja mais conveniente.
Uniões
Podemos eventualmente unir duas linhas de consultas simplesmente utilizando a
palavra reservada UNION.
22) Liste todos os empregados que tenham códigos > 10 ou Funcionários
que trabalhem em departamentos com código maior que 10.
Resp: Poderíamos resolver esta pesquisa com um único Select, porém devido ao
fato de estarmos trabalhando em nosso exemplo com apenas duas tabelas não
consiguimos criar um exemplo muito adequado para utilização deste recurso.
(Select *
From Emp
Where EmpNume > 10)
Union
(Select *
From Emp
Where DepNume > 10);
Inserções, Alterações e Exclusões
Uma linguagem direcionada a extração de informações de um conjunto de dados,
em tese não deveria incorporar comandos de manipulação dos dados. Devemos
observar contudo que a mera existência de uma linguagem padronizada para acesso
aos dados "convidava" os desenvolvedores a aderirem a uma linguagem "padrão" de
manipulação de tabelas. Naturalmente cada desenvolvedor coloca "um algo mais" em
seu SQL (SQL PLUS, SQL *, ISQL, e toda sorte de nomenclaturas), por um lado
desvirtuando os objetivos da linguagem (padronização absoluta), mas em
contrapartida otimiza os acessos ao seu banco de dados e por maior que sejam
estas mudanças, jamais são tão importantes que impeçam que um programador
versado em SQL tenha grandes dificuldades em se adaptar ao padrão de determinada
implementação. De fato as diferenças entre o SQL da Sybase, Oracle, Microsoft,
são muito menores dos que as existentes entre o C, o BASIC e o Pascal, que são
chamadas de linguagens "irmãs", pois todas originam-se conceitualmente no
FORTRAN. Podemos observar que todas as três linguagens mencionadas possuem
estruturas de controle tipo "para" (for), "enquanto" (while) e repita
(do..while, repeat..until). Todas trabalham com blocos de instrução, todas tem
regras semelhantes para declaração de variáveis e todas usam comandos de tomada
decisão baseadas em instruções do tipo "se" ou "caso", porém apesar de tantas
semelhanças (sic), é praticamente impossível que um programador excelente em uma
linguagem consiga rapidamente ser excelente em outra linguagem do grupo.
Poderíamos arriscar a dizer que um excelente programador C que utilize a
implementação da Symantech terá que passar por um breve período de adaptação
para adaptar-se ao C da Microsoft.
O que ocorreria então se este programador tiver que adaptar-se ao Delphi
(Pascal) da Borland?
De forma alguma o mesmo ocorrerá com o especialista em SQL ao ter que migrar
do Banco de Dados X para o Banco de Dados Y. Naturalmente existirá a necessidade
de aprendizado, mas este programador poderá ir adaptando-se aos poucos sem
precisar ser retreinado, o que é um aspecto extremamente vantajoso para as
empresas.
Inserir (Insert)
INSERT INTO <tabela> [<campos>] [VALUES <valores>]
Ex:
INSERT INTO DEPT;
Possibilita a inserção de registros de forma interativa.
INSERT INTO DEPT (DEPNUME,DEPNOME,DEPLOCA) VALUES (70,"PRODUCAO","RIO DE
JANEIRO");
Possibilita a inserção de registros em tabelas sem digitação dos dados.
Atualizar (Update)
UPDATE <tabela> SET <campo> = <expressão> [WHERE
<condição>];
Ex:
UPDATE EMP SET EMPSALA = EMPSALA* 1.2 WHERE EMPSALA< 1000;
Excluir (Delete)
DELETE FROM <tabela> [WHERE <condição>];
Ex:
DELETE FROM emp WHERE EMPSALA > 5000;
Transações
Muitas vezes gostaríamos que determinado processo, caso fosse abortado por
qualquer motivo, pudesse ser inteiramente cancelado. Imaginemos por exemplo um
usuário digitando um pedido. Imaginemos ainda que o sistema possa reservar cada
item solicitado de maneira "on line", ou seja ao mesmo tempo em que estou
digitando a quantidade o sistema já "empenhe" uma quantidade equivalente no
estoque. Imaginemos ainda que o sistema deve cancelar todas as operações se
apenas um dos itens não puder ser atendido. Grande problema, caso não pudéssemos
anular todos os processos a partir de determinada condição.
Vamos simular tal ocorrência com nosso banco de dados EMP. Imaginemos que ao
invés de digitarmos DELETE FROM emp WHERE salario > 5000; tivéssemos digitado
DELETE FROM emp WHERE salario > 500; Ao invés de eliminarmos 2 registros,
praticamente teríamos eliminado o banco de dados todo. Para evitarmos que um
erro de digitação, ou um processo iniciado porém sem condição de ser completado
integralmente comprometa todos nossos dados podemos criar uma transação que nos
assegurará que nossos testes sejam bem sucedidos ou cancelados sem comprometer
nossos dados.
begin transaction;
delete from emp where salario > 500;
if SQL_RECORDCOUNT > 20 THEN;
ROLLBACK TRASACTION;
else
COMMIT;
endif;
end transaction;
Visões
Uma visão consiste basicamente de uma tabela derivada de outras tabelas.
Considerando o exemplo TRABALHO, poderíamos criar uma visão baseada na Tabela de
Empregados (EMP) e na Tabela de Departamentos (DEPT) onde tivéssemos somente os
Nomes dos Funcionários e os Departamenos nos quais estes trabalhassem. Teríamos
algo assemelhado ao abaixo representado
CREATE VIEW EMP_DEP
AS SELECT E.EMPNOME, D.DEPNOME
FROM EMP E, DEPT D
WHERE E.DEPNUME = D.DEPNUME;
Devemos observar que:
1- Uma visão definida sobre uma única tabela somente será atualizável se os
atributos da tal visão contiverem a chave primária de tal tabela.
2- Visões sobre várias tabelas não são passíveis de atualizações.
3- Visões que se utilizam de funções de agrupamentos, também não poderão
ser atualizadas.
PARTE III - Relatórios
Comando:
REPORT DISTINCT / UNIQUE
[ atributo(s) ]
REPORTTOP
PAGETOP
TOP
DETAIL
NONE
BOTTOM
PAGEBOTTOM
REPORTBOTTOM
FROM [ tabela(s) ]
[ WHERE clausula-where ]
[ GROUP BY clausula-grupo ]
[ ORDER BY clausula-order by ];
Como exemplo converteremos um simples Select em um Report, temos:
SELECT EMPNOME
FROM EMP
WHERE DEPNUME = 1000;
REPORT
DETAIL EMPNOME
WHERE DEPNUME = 1000;
Podemos direcionar a saida de um relatório tanto para um arquivo como para
uma impressora.
Para um arquivo:
REPORT ON "RELAT.DAT" ...
Para uma impressora:
REPORT ON LP:" ...
Agora incrementando um report temos:
REPORT
REPORTTOP COL 10, "*** RELATORIO DE FUNCIONARIOS *** ",
TODAY %Q"DD/MM/YY", SKIP,
COL 10, "=================================", SKIP 2
DETAIL COL 10, NOME %C22, SALARIO %FS, ADMISSAO %Q"DD/MM/YY"
REPORTBOTTOM COL 10,
"=================================", SKIP,
COL 20, "TOTAL:", TOTAL(SALARIO)
FROM EMP
ORDER BY NOME;
Onde:
REPORTTOP - O que sera impresso no topo do relatório.
PAGETOP - Impresso em cada topo de pagina.
TOP - Impresso em cada Topo do Sort-Grupo do relatório.
DETAIL - O que sera impresso em cada linha.
NONE - Se não tiver resultado o select, não sera impresso o relatório.
BOTTOM - Impresso em cada Bottom do Sort-Grupo do relatório
PAGEBOTTOM - O que sera impresso no rodapé de cada pagina.
REPORTBOTTOM - O que sera impresso no rodape do relatório.
Formatos:
%C - caracter
%D - data
y - ano,
n - mes numérico,
a - mes alfanumérico,
d - dia,
j - dia e ano juliano
Exemplo: %D"dd/mm/yy"
%I - inteiro
%F - ponto flutuante
%FSZ onde: S - separador de 3 digitos e decimal point
Z - zeros serão suprimidos
%Q - data
%J - Hora
h - hora, m - minutos, s - segundos
%T - hora
E temos as funções: TOTAL, AVERAGE, MAXIMUM,
MINIMUM.
|