Banco de Dados I
Capítulo 6: Uso de SQL em
Aplicações
UFPB/DSC
Bacharelado em Ciência da
Computação
Cláudio Baptista
SQL Embutido
– Até então vinhamos usando o SQL
interativo, mas como fazer para usarmos
SQL numa aplicação?
– Porquê SQL não é uma linguagem
completa?
– Várias formas de conexão a BD: SQL
Estático, SQL Dinâmico e Call Level
Interface (SQL/CLI, ODBC/JDBC)
– Nesta seção estudaremos SQL embutido
em linguagem hospedeira.
- SQL + Linguagem Hospedeira (Pascal, C,
Cobol, Java …)
– Geralmente, diferentes sistemas seguem
diferentes convenções para embutir
comandos SQL
SQL Embutido
Linguagem Hospedeira (C, Pascal, Fortran,
Cobol, Ada, SQLJ (java)) + SQL Embutido
Pré-processador
Linguagem hospedeira +
Chamadas de funções
Compilador
Linguagem
Hospedeira
Código objeto
SQL Embutido
• Problema: “Impedance Mismatch”
• SQL trabalha com relações
• Linguagens de programação trabalham
orientada a registro
• Como fazer para ler os dados de um
conjunto retornado pelo SQL numa
linguagem de programação?
• Precisamos ter um mecanismos para
associar os valores retornados pelo SGBD
em variáveis da aplicação. Faz-se isso
usando variáveis hospedeiras.
– Obs.: Java tem um tratamento diferenciado
pelo fato de se tirar proveito de suas
características Orientada a Objetos Existe
um padrão para isto SQL/OLB (Object
Language Bindings)
SQL Embutido
• Tratamento de exceções
• é realizado pelo comando WHENEVER que
permite indicar as ações que devem ser
realizadas quando um erro ocorrer.
• Isto evita de fazer verificação de exceção
para cada comando SQL produzido
• Pode-se usar o SQLSTATE,
SQLEXECPTION, SQLWARNING, NOT
FOUND (02000) dentre outros.
• SQLSTATE é um array de 5 caracteres,
cada vez que um comando SQL é
executado o SGBD retorna no SQLSTATE
informações sobre erros, através de
códigos (SQL-89 chamava de SQLCODE)
• Ex.: Código ‘00000’ => não houve erro
• Código ‘02000’=> tupla não encontrada
SQL Embutido
• A seção DECLARE
– Qualquer declaração SQL (por
exemplo a definição de variáveis
host) é feita entre os comandos:
• EXEC SQL BEGIN DECLARE SECTION
• EXEC SQL END DECLARE SECTION
• Ex.: Em C
EXEC SQL BEGIN DECLARE SECTION;
char nomeStudio[50],
endStudio[256];
char SQLSTATE[6];
EXEC SQL END DECLARE SECTION;
SQL Embutido
• Variáveis host:
– são compartilhadas entre a aplicação
e o BD
– são definidas na aplicação e
precedidas por dois_pontos (:)
• o comando EXEC SQL
– Quando queremos invocar um
comando SQL de dentro de uma
aplicação simplesmente usamos o
comando EXEC SQL ou outra
diretiva(por exemplo $ ou #)
SQL Embutido
Exemplo de cadastro de cliente em C:
void cadastraCliente() {
EXEC SQL BEGIN DECLARE SECTION;
char nome[50], endereco[256];
char SQLSTATE[6];
EXEC SQL END DECLARE SECTION;
printf(“Entre o nome e endereço\n”);
gets(nome);
gets(endereco);
insert into Cliente (nome, endereco);
values (:nome, :endereco);
}
SQL Embutido
Exemplo de consulta que retorna uma única tupla:
void printCliente() {
EXEC SQL BEGIN DECLARE SECTION;
char nome[25], endereco[256];
char SQLSTATE[6];
EXEC SQL END DECLARE SECTION;
printf(“Entre com o nome do cliente\n”);
gets(nome);
EXEC SQL
select nome, endereco
into :nome, endereco
from Cliente
where nome = :nome
if (strcmp(SQLSTATE, “00000”))
printf (“Nome = %s\tendereco = %s\n”, nome, endereco);
else printf (“ERRO no ACESSO AO BD = %s”, SQLSTATE);
}
Ex.: Escreva um programa Pascal que leia a matricula de um empregado e imprima as
informações sobre este empregado.
program Imprima;
var loop: boolean;
matricula: integer;
E: record of
nome: string[15];
endereco: string[30];
funcao: string[10];
salario: real;
end;
begin
loop := true;
while (loop = true) do
begin
writeln(‘Entre com a matricula:’);
readln(matricula);
$ select nome, endereço, função, salario
into :E.nome, E.endereco, :E.funcao,
:E.salario
where matricula = :matricula;
writeln(E.nome, E.endereco, E.funcao, E.salario);
writeln(‘Deseja ler mais empregados(S/N)?’);
readln(loop);
end;
end.
SQL Embutido
– No programa anterior uma única tupla é
selecionada
pelo
SQL
embutido.
Geralmente, uma query resulta em várias
tuplas.
– Problema: SQL processa um conjunto de
tuplas, enquanto que C e Pascal (ou
outra linguagem host) processa um
registro por vez.
– Solução: Introduziu-se o conceito de
cursor para permitir processar uma tupla
por vez nas linguagens hospedeiras.
SQL Embutido
– Um cursor pode ser visto como um
ponteiro que aponta para uma única
tupla(linha) do resultado da query.
– Cada cursor possui uma pesquisa
associada, especificada como parte da
operação que define o cursor.
– A pesquisa é executada quando o cursor
for aberto.
– Numa mesma transação um cursor pode
ser aberto ou fechado qualquer número
de vezes. Pode-se ter vários cursores
abertos ao mesmo tempo.
SQL Embutido
– Sintaxe da especificação de um cursor:
EXEC SQL DECLARE nome-cursor
CURSOR FOR cláusula-select
– Um
cursor
possui
as
seguintes
operações:
- OPEN: executa a query especificada e pões o
cursos para apontar para uma posição anterior
a primeira tupla do resultado da consulta
- FETCH: move o cursor para apontar para
próxima linha no resultado da consulta.
Tornando-a a tupla corrente e copiando todos
os valores dos atributos para as variáveis da
linguagem hospedeira usada.
- CLOSE: fecha o cursor.
SQL Embutido
- UPDATE … CURRENT OF: realiza a atualização
dos atributos da tupla que está sendo
apontada pelo cursor (linha corrente). Sintaxe:
– UPDATE tabela
– SET lista de atribuições
– WHERE CURRENT OF cursor
- DELETE ... CURRENT OF: elimina a tupla que
está sendo apontada pelo cursor. Sintaxe:
– DELETE
– FROM tabela
– WHERE CURRENT OF curso
Um Exemplo em C:
EXEC SQL BEGIN DECLARE SECTION;
char SQLSTATE[6];
char titulo[101];
char ano[5];
EXEC SQL DECLARE filme_cursor CURSOR FOR
SELECT titulo
FROM filmes
WHERE ano = :ano;
void main () {
EXEC SQL WHENEVER SQLERROR GOTO erro;
ano = “1998”;
EXEC SQL OPEN filme_cursor;
while (strcmp(SQLSTATE, “02000”) != 0) {
EXEC SQL FETCH filme_cursor
INTO :titulo;
printf(“%s\n”, titulo);
};
EXEC SQL CLOSE filme_cursor;
return;
erro:
printf(“Um Erro ocorreu!\n”);
};
Exemplo usando Delete e Update
// Se empregado ganha mais de 10000 é demitido senão tem seu
// salário reduzido em 20%
void reducaodeFolhadePagamento() {
EXEC SQL BEGIN DECLARE SECTION;
char SQLSTATE[6];
float salario;
EXEC SQL END DECLARE SECTION;
EXEC SQL DECLARE salCursor CURSOR FOR
SELECT salario FROM Empregado ;
EXEC SQL OPEN salCursor;
while(1) {
EXEC SQL FETCH FROM salCursor
INTO :salario;
// Verifica se não há mais tuplas
IF (strcmp(SQLSTATE, “02000”)) break;
if (salario > 10000)
EXEC SQL DELETE FROM CLIENTE
WHERE CURRENT OF salCursor;
else EXEC SQL UPDATE CLIENTE
SET salario = salario - salario * 0.2;
WHERE CURRENT OF salCursor;
}
EXEC SQL CLOSE salCursor;
}
SQL Embutido
• Scrolling cursors
– cursores movem-se por default do
inicio do result set para frente
(forward)
– podemos, entretanto, movê-lo
também para trás e/ou para
qualquer posição no result set,
– para tanto, devemos acrescentar
SCROLL na definição do cursor
– EX. EXEC DECLARE meuCursor
SCROLL CURSOR FOR Empregado;
SQL Embutido
• Scrolling cursors
– Num FETCH, podemos adicionar as
seguintes opções:
• NEXT ou PRIOR: pega o próximo ou
anterior
• FIRST ou LAST: obtém o primeiro ou
último
• RELATIVE seguido de um inteiro: indica
quantas tuplas mover para frente (se
positivo) ou para trás (se negativo)
• ABSOLUTE seguido de um inteiro: indica a
posição da tupla contando do início (se
positivo) ou do final (se negativo)
SQL Embutido
– Exemplo em SQLJ:
• #sql { CREATE TABLE EMPREGADO ( matricula
int not null, nome varchar(30), Primary
key(matricula) )};
SQL Dinâmico
Motivação:
• SQL em uma linguagem hospedeira é
bom em aplicações estáticas, p.e., um
programa de reserva de passagens
aéreas.
• Não serve para escrever um programa
como sqlplus, porque não se sabe de
antemão qual o código que segue um
sinal de prontidão SQL>.
• Para resolver, precisamos de dois
comandos:
– PREPARE converte uma cadeia de caracteres
em um comando SQL.
– EXECUTE executa o comando.
Exemplo: Versão Simplificada do Sqlplus
EXEC SQL BEGIN DECLARE SECTION;
char query[MAX_QUERY_LENGTH];
EXEC SQL END DECLARE SECTION;
/* issue SQL> prompt */
/* read user's text into array query */
EXEC SQL PREPARE q FROM :query;
EXEC SQL EXECUTE q;
/* go back to reissue prompt */
• Uma vez preparada, uma consulta pode ser
executada muitas vezes.
– “Prepare” = otimiza a consulta, i.e., encontra um
meio de executá-la com um mínimo de I/O’s.
• Alternativamente, PREPARE e EXECUTE podem ser
combinadas em:
EXEC SQL EXECUTE IMMEDIATE :query;
Desvantagens da Abordagem
'Linguagens Hospedeira'
• Nem é C e nem é SQL, nem é Java e
nem é SQL, …
• O programa é executado no lado
cliente da arquitetura clienteservidor
– Problema de desempenho
Interfaces “Call-Level” (SQL/CLI)
Nesta abordagem, C (ou outra
linguagem) cria comandos SQL
como cadeias de caracteres
passados como argumentos de
funções que são parte de uma
biblioteca.
• SQL/CLI (ODBC = open database
connectivity) e JDBC (Java
database connectivity).
• Grande vantagem em relação ao
enfoque Linguagem Hospedeira: o
programa continua C puro
ODBC
• Em C, necessita-se do include sqlcli.h
• O programa pode então usar 4 tipos de estruturas:
– 1. Environment: prepara para conexão
– 2. Connections: conecta a aplicação ao
SGBD
– 3. Statements: contém os comandos a serem
processados
– 4. Descriptions: metadados
ODBC
•Em C, a biblioteca permite que você crie um statement
handle = estrutura em que você coloca um comando SQL.
Os handles são:
1. SQLHENV: para setar o environment
2. SQLHDBC: para conexão
3. SQLHSTMT: para statements
4. SQLHDESC: para descriptions
ODBC
Exemplo:
#include <sqlcli.h>
SQLHENV ambiente;
SQLHDBC conexao;
SQLHSTMT comando;
SQLHRETURN erro1, erro2, erro3;
erro1 = SQLAllocHandle(SQL_HANDLE_ENV,
SQL_NULL_HANDLE, &ambiente);
if (!erro1) {
erro2 = SQLAllocHandle(SQL_HANDLE_DBC,
ambiente, &conexao);
if(!erro2)
erro3 = SQLAllocHandle(SQL_HANDLE_SMT,
conexao, &comando);
}
ODBC
• Use SQLPrepare(myHandle, <statement>,length) para
fazer myHandle representar o comando SQL no segundo
argumento.
– Length é o tamanho do string. Pode ser usado SQL_NTS que
o próprio SQLPrepare descobre automaticamente.
• Use SQLExecute(myHandle) para executar o comando.
Exemplo
SQLPrepare(comando, "SELECT nome, salario
FROM Empregado
WHERE depto = 10";)
SQLExecute(comando);
Recuperando Dados
Para obter os dados retornados por uma consulta, usa-se:
•
Variáveis de ligação (“bind”) para os componentes das
tuplas retornadas.
–
•
SQLBindCol aplica-se a um handle, o número da coluna, e a
variável de ligação, mais outros argumentos.
Comando “Fetch”, usando o handle.
–
SQLFetch aplica-se a um handle.
Exemplo
SQLBindCol(handle1, 1, SQL_CHAR, &coluna1, size(coluna1),
&col1Info)
SQLBindCol(handle1, 2, SQL_REAL, &coluna2, size(coluna2),
&col2Info)
SQLExecute(handle1);
...
while(SQLFetch(handle1) != SQL_NO_DATA) {
...
}
ODBC – Passando Parâmetros
para Queries
• Use:
– 1. SQLPrepare(Comando)
– 2. SQLBindParameter()
– 3. SQLExecute()
Exemplo:
SQLPrepare(comando, “insert into projeto(codigo, nome)
values (?,?)”, SQL_NTS);
SQLBindParameter(comando, 1,..., codProj, ...);
SQLBindParameter(comando, 2, ..., nomeProj, ...)~;
SQLExecute(comando);
JDBC
• JDBC é uma Call-level Interface que
permite acesso externo a banco de
dados SQL
• Difere de SQL Embutido, pois possui
uma API que é chamada na própria
linguagem de progração para
acessar o BD
• Implementa o modelo clienteservidor
JDBC Estabelecendo uma
Conexão
• 1) Precisa-se carregar um driver JDBC
para o SGBD que se está usando.
• No Oracle, isto pode ser feito da
seguinte forma:
• Class.forName("oracle.jdbc.driver.OracleDriver"
)
• 2) Fazer uma conexão
• Connection con =
DriverManager.getConnection(
"jdbc:oracle:thin:@oracle-prod:1521:OPROD",
username, passwd);
Criando JDBC Statement
• JDBC Statement é um objeto usado para mandar um
comando SQL para o SGBD
• Está associado a uma conexão aberta
• O método createStatement() retorna um objeto da classe
Statement (se não houver argumento) ou
PreparedStatement se houver um comando SQL como
argumento ("overload" de métodos).
Exemplo
Statement stat1 = myCon.createStatement();
PreparedStatement stat2 =
myCon.createStatement(
"SELECT nome, salario" +
"FROM Empregado" +
"WHERE salario > 5000'"
);
•
myCon é uma conexão, stat1 é um objeto “vazio” da classe Statement, e
stat2 é um objeto da classe PreparedStatement que tem um comando
SQL associado.
Executando Comandos
• JDBC distingue consultas (comandos que retornam
dados) de updates (comandos que somente afetam o
BD).
• Os métodos executeQuery() e executeUpdate() são
usados para executar essas duas espécies de
comandos.
– Eles devem ter um argumento se aplicados a
Statement, nunca se aplicados a PreparedStatement.
• Quando uma consulta é executada, retorna um
objeto da classe ResultSet.
Exemplo
stat1.executeUpdate(
"INSERT INTO Empregado" +
"VALUES(‘’Ana Maria, ‘Engenheira', 3000.00)"
);
ResultSet rs = stat2.executeQuery();
Executando comandos
• Comandos DDL (criar tabelas) e updates são
realizados com o método: executeUpdate()
Statement stmt = con.createStatement();
stmt.executeUpdate("CREATE TABLE Sells " +
"(bar VARCHAR2(40), beer VARCHAR2(40), price REAL)" );
stmt.executeUpdate("INSERT INTO Sells " +
"VALUES ('Bar', 'BudLite', 2.00)" );
String sqlString = "CREATE TABLE Bars " +
"(name VARCHAR2(40), address VARCHAR2(80), license INT)" ;
stmt.executeUpdate(sqlString);
Obtendo as Tuplas de um ResultSet
• O método next() se aplica a um ResultSet e
move um
“cursor” para a próxima tupla do conjunto.
– Aplique next() para obter a primeira tupla.
– next() returna FALSE se não houver mais tuplas.
• Para a tupla corrente do cursor, você pode
obter seu i-ésimo componente aplicando o
método getX(i), onde X é o nome para o tipo
do argumento.
Exemplo
while(rs.next()) {
nome = rs.getString(1);
salario = rs.getFloat(2);
...
}
Executando SELECT
• Usa o método executeQuery() que retorna
um objeto ResultSet
String bar, beer ; float price ;
ResultSet rs = stmt.executeQuery("SELECT * FROM Sells");
while ( rs.next() ) {
bar = rs.getString("bar");
beer = rs.getString("beer");
price = rs.getFloat("price");
System.out.println(bar + " sells " + beer + " for " + price +
" Dollars.");
}
Executando SELECT
• Alternativamente, podemos usar
bar = rs.getString(1);
price = rs.getFloat(3);
beer = rs.getString(2);
ResultSet
• Contém métodos getRow, isFirst,
isBeforeFirst, isLast, isAfterLast que indicam
aonde o cursor está
• Pode-se criar cursores scrollable que podem
se movimentar em qualquer sentido no
ResultSet
• Com isso podem ser usados:
• rs.absolute(3); // move para a terceira
tupla rs.previous(); // move para trás 1
tupla rs.relative(2); // move para frente 2
tuplas rs.relative(-3); // move para trás 3
tuplas
Prepared Statement
• Usado quando se quer usar a mesma query com
diferentes parâmetros várias vezes
• o comando é compilado e otimizado pelo SGBD apenas
uma vez
• PreparedStatement prepareUpdatePrice =
con.prepareStatement( "UPDATE Sells SET
price = ? WHERE bar = ? AND beer = ?");
• Então precisamos preencher os parâmetros:
• prepareUpdatePrice.setInt(1, 3);
prepareUpdatePrice.setString(2, "Bar Of
Foo"); prepareUpdatePrice.setString(3,
"BudLite");
Desvantagens de ODBC/JDBC
• Os programas C, Java, … , ainda são
executados no lado cliente
Integração Estreita com SGBDs
• O uso de SQL/PSM (Stored
Procedures) tais como PL/SQL,
SQLJ, TransactSQL, … , são
extensões da SQL
– Processadas no lado servidor da
arquitetura cliente - servidor
• Isto é muito bom para o desempenho
6.3 Stored Procedures
• É um conjunto de comandos SQL definidos
pelo usuário que ficam armazenados num
BD como um procedimento/função, para
eventuais processamentos.
• São processamentos de tarefas da
aplicação que residem no SGBD ao invés
de no código da aplicação (cliente).
6.3 Stored Procedures
• Vantagens:
• 1.Desempenho
– Ex.: Seja a consulta
SELECT codigop, nome, COUNT(*)
FROM Projeto p, Alocacao a
WHERE p.codproj = a.codigop
GROUP BY p.codproj, p.nome
6.3 Stored Procedures
• Se vários usuários realizarem esta consulta
o tráfego de rede será alto.
• se criarmos uma stored procedure para
executar esta consulta, os usuários
necessitarão apenas de um comando para
executar a consulta anterior: EXEC
nomeProcedimento;
• Outro ponto é a compilação, a consulta
anterior seria compilada a cada chamada,
enquanto o procedimento contendo a
consulta seria compilado uma única vez
6.3 Stored Procedures
• 2. Facilita o gerenciamento do BD,
pois a consulta é escrita em um único
lugar, portanto a manutenção desta
torna-se mais eficaz e segura.
6.3 Stored Procedures
• 3. Segurança, como veremos no
próximo capítulo, podemos usar
stored procedures para limitar o
acesso de alguns usuários ao BD.
Desta forma, a maneira em que o BD
pode ser modificado é estritamente
definida.
Stored Procedures
• SQL/PSM - Persistent Stored
Modules
• No momento cada SGBD oferece
sua própria linguagem (Oracle
PL/SQL, Microsoft Transact/SQL,
etc)
• Em PSM, definimos módulos que
são coleções de definições
defunções ou procedimentos,
declarações de tabelas
temporárias, dentre outros.
Stored Procedures -SQL/PSM
• Criando Funções e Procedimentos
– CREATE PROCEDURE <NOME>
(<parâmetros>)
declarações locais
corpo do procedimento;
– CREATE FUNCTION <NOME>
RETURNS <tipo>
declarações locais
corpo da função;
• obs.: parâmetros são do tipo modo-nometipo (onde modo indica IN, OUT ou
INOUT)
• Parâmetros em funções devem ter modo
IN
Stored Procedures -SQL/PSM
Exemplo:
CREATE PROCEDURE MudaEndereco (
IN endAntigo VARCHAR(255),
IN endNovo VARCHAR(255)
)
UPDATE Empregado
SET endereco = endNovo
WHERE endereco = endAntigo;
Stored Procedures -SQL/PSM
Alguns Comandos:
1) Chamada a um procedimento:
CALL <nome procedure> (<lista argumentos>);
Obs.: CALL é aplicado apenas a Procedures (não Function)
Esta chamada pode ser realizada de vários lugares:
- Programa com SQL embutido
EXEC SQL CALL calcula(:x, 3);
- Como comando em outro procedimento ou função PSM:
CALL calcula (10);
2) Comando de Retorno (usado apenas em funções)
RETURN <expressão>; (OBS este comando não encerra
a função)
Stored Procedures -SQL/PSM
3) Declaração de variáveis locais:
DECLARE <nome> <tipo>;
4) Comando de atribuição
SET <variável> = <expressão>;
5) Grupo de comandos:
delimitados por BEGIN e END
6) Labels: colocamos labels em comandos precedendo estes
pelo nome do label e dois pontos.
7) Comandos condicionais
8) Laços
IF <condição> THEN
LOOP
<comandos>
<Comandos>
ELSEIF <condição> THEN
END LOOP;
<comandos>
…
ELSE <comandos>
END IF;
Stored Procedures -SQL/PSM
Exemplo: Função sobre o esquema Filmes que recebe um ano
e nome de estúdio e retorna TRUE se aquele estúdio produziu
apenas um filme preto e branco naquele ano ou nada produziu.
CREATE FUNCION PretoeBranco( a int, studio char[15])
RETURNS BOOLEAN
IF not exists (
select * from Filme where ano = a and
nomeStudio = studio)
THEN RETURN TRUE; -- não faz a função retornar agora
ELSEIF 1 <=
(select count(*) from Filme where ano = a and
nomeStudio = nome and NOT emcores)
THEN RETURN TRUE;
ELSE RETURN FALSE;
END IF;
Stored Procedures -SQL/PSM
Exemplo: Procedimento que calcula a média e variância de um
estúdio
CREATE PROCEDURE MeanVar ( IN s char[15],
OUT mean REAL, OUT variance REAL)
DECLARE NotFound FOR SQLSTATE ‘02000’;
DECLARE filmeCursor CURSOR FOR
select duracao from Filme where nomeStudio = s;
DECLARE novaDuracao INTEGER;
DECLARE contaFilmes INTEGER;
BEGIN
SET mean = 0.0;
SET variance = 0.0;
SET contaFilmes = 0;
OPEN filmeCursor;
filmeLOOP: LOOP
FETCH filmeCursor INTO novaDuracao;
IF NotFound THEN LEAVE filmeCurdor END IF;
SET contaFilmes = contaFilmes + 1;
SET mean = mean + novaDuracao;
SET variance = variance + novaDuracao * novaDuracao;
END LOOP;
SET mean = mean / contaFilmes;
SET variance = variance/contaFilmes - mean * mean;
CLOSE filmeCursor;
END;
Stored Procedures -SQL/PSM
- For-Loops
usado para fazer iterator num cursor
FOR <nome laço> AS <nome cursor> CURSOR FOR
<query>
DO
<comandos>
END FOR;
Veja exemplo no próximo slide!
- WHILE <condição> DO
<comandos>
END WHILE;
- REPEAT
<comandos>
UNTIL <condição>
END REPEAT;
Stored Procedures -SQL/PSM
Exemplo: Mesmo procedimento de média e variância de estúdios,
usando FOR-Loops
CREATE PROCEDURE MeanVar ( IN s char[15],
OUT mean REAL, OUT variance REAL)
DECLARE contaFilmes INTEGER;
BEGIN
SET mean = 0.0;
SET variance = 0.0;
SET contaFilmes = 0;
FOR filmeLOOP AS filmeCursor CURSOR FOR
select duracao from Filme where nomeStudio = s;
DO
SET contaFilmes = contaFilmes + 1;
SET mean = mean + novaDuracao;
SET variance = variance + novaDuracao * novaDuracao;
END FOR;
SET mean = mean / contaFilmes;
SET variance = variance/contaFilmes - mean * mean;
END;
OBS.Veja que não é necessário OPEN, FETCH e CLOSE do cursor
Stored Procedures -SQL/PSM
Exceções em PSM:
É possível testar o SQLSTATE para verificar a ocorrência
de erros e tomar uma decisão, quando erros ocorram
Isto é feito através do EXCEPTION HANDLER que é
associado a blocos BEGIN END (o handler aparece dentro do bloco)
Os componentes do handler são:
1) Lista de exceções a serem tratadas
2) Código a ser executado quando execeção ocorrer
3) Indicação para onde ir depois que o handler concluir
SINTAXE: DECLARE <onde ir> HANDLER FOR <condições>
<comando>
AS escolhas de <onde ir> são:
- CONTINUE
- EXIT (sai do bloco BEGIN .. END)
- UNDO
Stored Procedures -SQL/PSM
Exemplo de exceções em PSM:
CREATE FUNCTION getSalario (mat integer) RETURNS FLOAT
DECLARE NotFound CONDITION FOR SQLSTATE ‘02000’;
DECLARE TooMany CONDITION FOR SQLSTATE ‘21000’;
BEGIN
DECLARE EXIT HANDLER FOR NotFound, TooMany
RETURN NULL;
RETURN ( select salario
from Empregado where
where matricula = mat);
END;
PL-SQL : Oracle Stored Procedures
• Linguagem de desenvolvimento do Oracle.
– Usada via a ferramenta Sqlplus.
• Um compromisso entre uma linguagem de programação
totalmente `procedural´ e a linguagem declarativa SQL.
• Permite variáveis locais, laços, procedures, consulta a
relações “one tuple at a time”.
• Forma geral:
DECLARE
declarações
BEGIN
comandos executáveis;
EXCEPTION
Comandos para manipular erros (optativo)
END;
.
run;
• A parte DECLARE é opcional.
• `Dot and run´ finalizam o comando e o executam.
Procedures
Objetos armazenados no BD, que
usam comandos PL/SQL em seus
corpos.
Declarações de Procedure
CREATE OR REPLACE PROCEDURE
<nome>(<lista_argumentos>) AS
<declarações>
BEGIN
<comandos PL/SQL>
END;
PL-SQL : Oracle Stored Procedures
• <Lista_argumentos> tem triplas
nome-modo-tipo.
– Modo: IN, OUT, ou IN OUT para readonly, write-only, read/write,
respectivamente.
– Tipos: padrão SQL + tipos genéricos
como NUMBER = qualquer tipo inteiro ou
real.
– Desde que tipos nas procedures devem
casar com tipos no esquema do BD,
pode-se usar uma expressão da forma
relação.atributo %TYPE
para capturar o tipo corretamente.
Oracle: Exemplo
Uma procedure que inclui uma nova cerveja e seu preço no
menu do bar RubroNegro.
Vende(bar, cerveja, preço)
CREATE PROCEDURE MenuRubroNegro(
c IN Vende.cerveja %TYPE,
p IN Vende.preço %TYPE
) AS
BEGIN
INSERT INTO Vende
VALUES(`RubroNegro´´, c, p);
END;
.
run;
• Note “run” somente armazena a procedure, não a
executando.
Oracle: Invocando Procedures
Uma chamada a uma procedure pode
aparecer no corpo de um comando
PL/SQL.
• Exemplo:
BEGIN
MenuRubroNegro('Bud', 2,50);
MenuRubroNegro(‘Carlsberg', 5,00);
END;
ORACLE PSM
Atribuição de valores a variáveis é denotada por :=.
Desvio
IF <condição> THEN
<comando(s)>
ELSE
<comando(s)>
END IF;
• Em `ninhos´ de IFs, use ELSIF em lugar de ELSE
IF.
Laço
LOOP
...
EXIT WHEN <condição>
...
END LOOP;
Oracle: Consultas em PL/SQL
•
•
Single-row selects permitem
atribuir a uma variável o resultado
de uma consulta que produz uma
única tupla.
Cursors permitem a recuperação
de muitas tuplas, com o cursor e
um laço sendo usados para
processar tupla-a-tupla.
Single-Row Select
• Um select-from-where em PL/SQL deve ter uma
cláusula INTO listando as variáveis que recebem os
resultados da consulta.
• É erro se o select-from-where retorna mais de uma
tupla; neste caso, é preciso usar um cursor.
Exemplo
• Encontrar o preço da cerveja Schincarioll no bar
Tricolor.
Vende(bar, cerveja, preço)
DECLARE
p Vende.preço %TYPE;
BEGIN
SELECT preço
INTO p
FROM Vende
WHERE bar = `Tricolor´
END;
AND cerveja = `Schincarioll´;
Cursores
Declarados por:
CURSOR <nome> IS
comando select-from-where
• O cursor aponta para cada tupla por vez da relaçãoresultado da consulta select-from-where, usando um
fetch statement dentro de um laço.
– Fetch statement:
FETCH <nome_cursor> INTO
lista_variáveis;
• Um laço é interrompido por:
EXIT WHEN <nome_cursor> %NOTFOUND;
– O valor é Verdade se não houver mais tupla a apontar.
•
OPEN e CLOSE abrem e fecham um cursor,
respectivamente.
Exemplo
Uma procedure que examina o menu
do bar Tricolor e aumenta de 1,00
todos os preços que são menores
que 3,00.
Vende(bar, cerveja, preço)
• Um simples UPDATE podia resolver o
problema, mas mudanças mais
complicadas podiam exigir uma
procedure.
CREATE PROCEDURE Aumento() AS
aCerveja Vende.cerveja%TYPE;
oPreço Vende.preço%TYPE;
CURSOR c IS
SELECT cerveja, preço
FROM Vende
WHERE bar =`Tricolor´;
BEGIN
OPEN c;
LOOP
FETCH c INTO aCerveja, oPreço;
EXIT WHEN c%NOTFOUND;
IF oPreço < 3.00 THEN
UDPATE Vende
SET preço = oPreço + 1.00
WHERE bar = `Tricolor´
AND cerveja = aCerveja;
END IF;
END LOOP;
CLOSE c;
END;
Tipo ROWTYPE
Qualquer coisa (i.e., cursores, nomes
de tabela) que tem um tipo tupla
pode ter seu tipo capturado com
%ROWTYPE.
• Pode-se criar variáveis temporárias
tipo tupla e acessar seus
componentes como
variável.componente (“dot
notation”).
• Muito útil, principalmente se a tupla
tem muitos componentes.
Exemplo
A mesma procedure com a variável tupla cp.
CREATE PROCEDURE Aumento() AS
CURSOR c IS
SELECT cerveja, preço
FROM Vende
WHERE bar = `Tricolor´;
cp c
%ROWTYPE;
BEGIN
OPEN c;
LOOP
FETCH c INTO cp;
EXIT WHEN c %NOTFOUND;
IF cp.preço < 3.00 THEN
UDPATE Vende
SET preço= cp.preço + 1.00
WHERE bar = `Tricolor´
AND cerveja = cp.cerveja;
END IF;
END LOOP;
CLOSE c;
END;
Definição de Function
- Podemos definir uma função:
CREATE FUNCTION <func_name>(<param_list>)
RETURN <return_type> AS ...
No corpo da função, "RETURN <expression>;"
sai (retorna) da função e retorna o valor da
<expression>.
- Para descobrir quais procedures e functions você já criou:
select object_type, object_name
from user_objects
where object_type = 'PROCEDURE'
or object_type = 'FUNCTION';
Removendo
Procedures/Functions
Para remover uma stored procedure/function:
drop procedure <procedure_name>;
drop function <function_name>;
Outras formas de Laços
• Comando For
– permite que uma determinada
sequencia de comandos seja
executada n vezes
FOR contador IN [REVERSE] valorInicial .. valorFinal
LOOP
sequencia de comandos
END LOOP
Outras formas de Laços
• Comando For - Exemplo
Create procedure VerificaEstoque
Declare
codInicial Produto.codProduto%Type;
codFinal CodInicial%Type;
estoque Produto.estoque%Type;
Begin
select Min(CodProduto), Max(codProduto)
into codInicial, codFinal
from Produto
for c in codInicial..codFinal
loop
select estoque into estoque
from produto
where codProd = c and estoque>0
Dbms_Output.Put_Line(‘O codigo ’|| c || ‘ tem em estoque’);
end loop;
End
Outras formas de Laços
• Comando while
Sintaxe:
WHILE condição LOOP
Comandos
END LOOP;
Exemplo
Manipulando Exceções
• Exceções são todos os erros e
imprevistos que podem ocorrer
durante a execução de um bloco
PL/SQL
• Quando uma exceção ocorre o
Oracle aborta a execução e
procura a área de exceções
(EXCEPTION) para tratar a falha.
• As exceções podem ser
– Pré-definidas
– Definidas pelo usuário
Manipulando Exceções
Sintaxe:
EXCEPTION
WHEN
nomeExceção 1
Comandos
WHEN
nomeExceção2
Comandos
Exemplo
THEN
THEN
begin
insert into Pais values (100, ‘Brasil’);
Commit;
Dbms_Output.Put_Line(‘Inserção realizada com sucesso’);
Exception
when Dup_Val_On_Index Then
Dbms_Output.Put_Line(‘País já cadastrado!’);
when Others then
Dbms_Output.Put_Line(‘Erro ao cadastrar país’);
end;
Execeções Pré-definidas
•
•
•
•
•
•
•
•
•
•
•
•
•
Cursor_Already_Open
DUP_Val_On_INDEX
INVALID_CURSOR
Invalid_Number
Login_Denied
No_Data_Found
Not_Logged_On
RowType_Mismatch
Storage_Error
Too_Many_Rows
Value_Error
Zero_Divide
Others
Exemplo de Exceção
Declare
Aux_X number(1);
Subtype TipoX is Aux_X%Type;
-- Limitado entre -9 e 9
x TipoX;
y TipoX;
Begin
x := 10;
Exception
when value_error then
Dbms_Output.Put_Line(‘Valor fora do limite’);
End;
Exceção definida pelo Usuário
Devem ser declaradas na área de declarações de um bloco ou
procedure/function ou package
Comando:
Declare
nomeExceção EXCEPTION;
Begin
Sequencia de comandos
If … then
RAISE nomeExceção;
End If;
Comandos
Exception
When NomeExceção then Comandos
End
Exemplos de SP em SQL Server
1. CREATE PROCEDURE DBO.MostraEmpregadosDep
@nomeDep varchar(50) = ‘Pessoal’ - - Dep Default
AS
SELECT e.mat, e.nome, e.endereco, e.salario
FROM Empregados e, Departamento d
WHERE d.nomeD = @nomeDep
Uma chamada a este procedimento seria:
USE Empresa -- BB Empresa
EXEC MostraEmpregadosDep ‘Informatica’
SQLServer:Exemplos de SP
2. Usando parâmetros de saída (transact-SQL)
CREATE PROCEDURE DBO.Calc
@x int,
@y int,
@res int OUTPUT
AS
SET @res = @x + @y
Possível chamada:
DECLARE @resposta int
EXEC Calc 1,2 @resposta OUTPUT
Select ‘Resposta = ‘, @resposta
SQLServer:Exemplos de SP
3. CREATE PROCEDURE InsereEmpregado
@mat int,
@nomeE varchar(30),
@endereco varchar(60),
@salario float,
@depto int
AS
INSERT INTO Empregado
VALUES (@mat, @nomeE, @endereco,
@salario,
@depto)
SQLServer:Exemplos de SP
4.Alguns Stored Procedures do SQL-Server
sp_tables: mostra todos os nomes das tabelas do catálogo
sp_store_procedures: mostra todos os stored procedures
sp_server_info: mostra configuração do SQL-Server
sp_databases: mostra os BD disponíveis
sp_monitor: mostra como o SQL-server está executando
(memória, grau de atividade do processador, etc)
sp_who: informa quem está usando o BD num dado
instante
sp_help: dá informações sobre qualquer objeto do BD
Download

Capitulo5_SQL