Sei sulla pagina 1di 16

Funes em PostGreSQL Stored Procedures so nada mais que programas desenvolvidos em determinada linguagem de script e armazenados no servidor, local

onde sero processados. Eles tambm so conhecidos como funes, este o motivo pelo qual quando nos referenciamos a uma stored procedure no PostgreSQL devemos utilizar o nome de Function. O PostgreSQL conta com trs formas diferentes de criar funes: - Funes em Linguagem SQL: So funes que utilizam a sintaxe SQL e se caracterizam por no possuirem estruturas de condio (if, else, case), estruturas de repetio (while, do while, for), no permitirem a criao de variveis e utilizam sempre algum dos seguintes comandos SQL: SELECT, INSERT, DELETE ou UPDATE. - Funes de Linguagens Procedurais: ao contrrio das funes SQL, aqui permitido o uso de estruturas de condio e repetio e o uso de variveis. As funes em linguagens procedurais caracterizam-se tambm por no possuirem apenas uma possibilidade de linguagem, mas vrias. Normalmente a mais utilizada conhecida como PL/PgSQL, linguagem fortemente semelhante ao conhecido PL/SQL utilizado no Oracle. - Funes em Liguagens Externas ou de Rotinas Complexas: So funes normalmente escritas em C++ que trazem consigo a vantagem de utilizarem uma linguagem com diversos recursos, na qual pode-se implementar algoritmos com grande complexidade. Tais funes so empacotadas e registradas no SGBD para seu uso futuro. Para criar uma funo utilizando SQL no PostgreSQL utiiza-se o comando CREATE FUNCTION, da seguinte forma: CREATE [ OR REPLACE ] FUNCTION nome ( [ tipo_do_parametro1 [, ...] ] ) RETURNS tipo_retornado AS ' Implementao_da_funo; ' LANGUAGE 'SQL'; Na qual CREATE FUNCTION o comando que define a criao de uma funo, [OR REPLACE] informa que se acaso existir uma funo com este nome, a atual funo dever sobrescrever a antiga. RETURNS tipo_retornado informa o tipo de dado que ser retornado ao trmino da funo. Tais tipos de retornos so os convencionais como o INTEGER, FLOAT, VARCHAR, etc. As funes em SQL tambm permitem o retorno de mltiplos valores e para isso informa-se como retorno SETOF. Implementao_da_funo, como o nome mesmo diz, traz as linhas de programao para a implementao da stored procedure. LANGUAGE est avisando qual linguagem em que est sendo implementada a funo. Quando passamos parmetros funo, no utilizamos nome nas variveis que esto dentro dos parnteses da assinatura da funo. Utilizamos apenas separados por vrgulas, o tipo da varivel de parmetro. Para acessarmos o valor de tais parmetros, devemos utilizar o '$' mais o nmero da posio que ocupa nos parmetros, seguindo a ordem da esquerda para a direita: CREATE FUNCTION soma(INTEGER, INTEGER) RETURNS INTEGER AS ' SELECT $1 + $2; ' LANGUAGE 'SQL';

Outro detalhe importante o fato de que as funes utilizando SQL sempre retornam valor, o que faz com que seja sempre necessrio que a ltima linha de comando da funo utilize o comando SELECT. CREATE FUNCTION cubo(INTEGER) RETURNS FLOAT AS ' SELECT $1 ^ 3; ' LANGUAGE 'SQL'; Quando desejar excluir uma funo do sistema utilize o comando: DROP FUNCTION nome_da_funcao(); Para excluir uma funo necessrio passar toda a sua assinatura: DROP FUNCTION nome_da_funcao(INTEGER); Ainda existe o fato que no momento da excluso voc pode excluir a funo passando mais um parmetro, como no exemplo a seguir: DROP FUNCTION totalNota(INTEGER) RESTRICT; ou DROP FUNCTION totalNota(INTEGER) CASCADE; Digite a funo abaixo no PostGres, no mesmo local onde se digita os comandos SQL.

Caso tenha obtido alguma mensagem de erro, preciso preparar o postgres para executar a linguagem plpgsql. Neste caso deve-se cadastrar no item LANGUAGES do POSTGRES a linguagem PSPGSQL. Veja figura.

Cada Sistema Gerenciador de Banco de Dados pode tratar as linguagens de forma diferente, aqui estamos configurando o POSTGRESQL para interpretar as FUNCTIONS. Caso sua funo tenha retornado o valor esperado, sinal de que voc j pode efetuar alguns exemplos, veja abaixo: Obs.: Digite todas os COMANDOS abaixo e os execute, pea ajuda ao professor se necessrio. CREATE TABLE genero ( id numeric(5) NOT NULL, nome varchar(100), CONSTRAINT genero_pkey PRIMARY KEY (id) ); CREATE TABLE filme ( nome varchar(100), duracao varchar(100), sinapse varchar(2000),

id numeric(5) NOT NULL, genero numeric(5), data timestamp, CONSTRAINT fk_genero_filme FOREIGN KEY (genero) REFERENCES genero (id) ON UPDATE NO ACTION ON DELETE NO ACTION );

CREATE FUNCTION duracao_filme(INTEGER) RETURNS VARCHAR AS 'SELECT duracao FROM filme WHERE id = $1;' LANGUAGE 'SQL';

select duracao_filme(1);

CREATE FUNCTION filmes_genero(integer) RETURNS SETOF varchar AS 'SELECT nome FROM filme WHERE genero = $1;' LANGUAGE 'SQL';

select filmes_genero(1);

drop function soma1(integer, integer);

CREATE OR REPLACE FUNCTION primeira_funcao() RETURNS VOID AS $body$ BEGIN

RAISE NOTICE 'Minha primeira rotina em PL/pgSQL'; RETURN; END; $body$ LANGUAGE 'plpgsql';

select primeira_funcao();

CREATE OR REPLACE FUNCTION primeira_funcao(integer,integer) RETURNS integer AS $body$ declare soma integer; BEGIN RAISE NOTICE 'Minha primeira rotina em PL/pgSQL'; soma:=$1+$2; RETURN(soma); END; $body$ LANGUAGE 'plpgsql';

select * from primeira_funcao(5,1);

CREATE OR REPLACE FUNCTION primeira_funcao(integer, integer) RETURNS integer AS

$body$ declare soma integer; BEGIN RAISE NOTICE 'Minha primeira rotina em PL/pgSQL'; if $1 > $2 then soma:=$1-$2; else soma:=$2-$1; end if; RETURN(soma); END; $body$ LANGUAGE 'plpgsql'; select * from primeira_funcao(5,1);

CREATE OR REPLACE FUNCTION primeira_funcao(n1 integer,n2 integer) RETURNS integer AS $body$ declare soma integer; BEGIN RAISE NOTICE 'Minha primeira rotina em PL/pgSQL'; if n1 > n2 then soma:=n1-n2; else

soma:=n2-n1; end if; RETURN(soma); END; $body$ LANGUAGE 'plpgsql';

select * from primeira_funcao(5,1);

CREATE OR REPLACE FUNCTION f_cnpjcpf(integer, bpchar) RETURNS integer AS $BODY$ DECLARE

-- Argumentos -- Tipo de verificacao : 0 (PJ), 1 (PF) e 2 (Livre) pTipo ALIAS FOR $1; -- Numero do documento pNumero ALIAS FOR $2;

-- Variaveis i INT4; -- Contador iProd INT4; -- Somatrio iMult INT4; -- Fator iDigito INT4; -- Digito verificador calculado sNumero VARCHAR(20); -- numero do docto completo

BEGIN

-- verifica Argumentos validos IF (pTipo < 0) OR (pTipo > 2) THEN RETURN -1; END IF;

-- se for Livre, nao eh necessario a verificacao IF pTipo = 2 THEN RETURN 1; END IF;

sNumero := trim(pNumero); FOR i IN 1..char_length(sNumero) LOOP IF position(substring(sNumero, i, 1) in '1234567890') = 0 THEN RETURN -2; END IF; END LOOP; sNumero := '';

-- ***************************************************** -- Verifica a validade do CNPJ -- *****************************************************

IF (char_length(trim(pNumero)) = 14) AND (pTipo = 0) THEN

-- primeiro digito sNumero := substring(pNumero from 1 for 12);

iMult := 2; iProd := 0;

FOR i IN REVERSE 12..1 LOOP iProd := iProd + to_number(substring(sNumero from i for 1),'9') * iMult; IF iMult = 9 THEN iMult := 2; ELSE iMult := iMult + 1; END IF; END LOOP;

iDigito := 11 - (iProd % 11); IF iDigito >= 10 THEN iDigito := 0; END IF;

sNumero := substring(pNumero from 1 for 12) || trim(to_char(iDigito,'9')) || '0';

-- segundo digito iMult := 2; iProd := 0;

FOR i IN REVERSE 13..1 LOOP iProd := iProd + to_number(substring(sNumero from i for 1),'9') * iMult; IF iMult = 9 THEN iMult := 2; ELSE iMult := iMult + 1;

END IF; END LOOP;

iDigito := 11 - (iProd % 11); IF iDigito >= 10 THEN iDigito := 0; END IF;

sNumero := substring(sNumero from 1 for 13) || trim(to_char(iDigito,'9')); END IF;

-- ***************************************************** -- Verifica a validade do CPF -- *****************************************************

IF (char_length(trim(pNumero)) = 11) AND (pTipo = 1) THEN

-- primeiro digito iDigito := 0; iProd := 0; sNumero := substring(pNumero from 1 for 9);

FOR i IN 1..9 LOOP iProd := iProd + (to_number(substring(sNumero from i for 1),'9') * (11 - i)); END LOOP; iDigito := 11 - (iProd % 11); IF (iDigito) >= 10 THEN iDigito := 0; END IF;

sNumero := substring(pNumero from 1 for 9) || trim(to_char(iDigito,'9')) || '0';

-- segundo digito iProd := 0; FOR i IN 1..10 LOOP iProd := iProd + (to_number(substring(sNumero from i for 1),'9') * (12 - i)); END LOOP; iDigito := 11 - (iProd % 11); IF (iDigito) >= 10 THEN iDigito := 0; END IF; sNumero := substring(sNumero from 1 for 10) || trim(to_char(iDigito,'9'));

END IF;

-- faz a verificacao do digito verificador calculado IF pNumero = sNumero::bpchar THEN RETURN 1; ELSE RETURN -3; END IF; END; $BODY$ LANGUAGE 'plpgsql' VOLATILE;

Aps a digitao desta Funo escreva: SELECT f_cnpjcpf( 1, '12312312345' ); Verifique que o CPF invlido e desta maneira o registro no ser inserido. SELECT f_cnpjcpf( 1, 'Digite seu CPF' );

Vamos fazer uma tabela que faz uma condio para uma funo, digite a funo abaixo: Crie a tabela abaixo e verifique que em um dos CONSTRAINTS a funo chamada. drop table cadastro; CREATE TABLE cadastro ( id integer NOT NULL, nome character varying(50) NOT NULL, tipopessoa smallint NOT NULL, cpfcnpj character(20) NOT NULL, CONSTRAINT cadastro_pkey PRIMARY KEY (id), CONSTRAINT cadastro_check CHECK (f_cnpjcpf(tipopessoa::integer, cpfcnpj) = 1), CONSTRAINT cadastro_tipopessoa_check CHECK (tipopessoa = ANY (ARRAY[1, 2])) ); Vamos fazer uma funo que retorne um RecordSet, veja abaixo: drop function getcadastro(text); CREATE OR REPLACE FUNCTION getcadastro(text) RETURNS SETOF cadastro AS $BODY$ SELECT * FROM cadastro WHERE nome LIKE $1 || '%'; $BODY$ LANGUAGE 'sql' VOLATILE; Neste exemplo abaixo, podemos verificar que a funo faz o INSERT, basta que passemos os parmetros para ela. drop function insert_cadastro(integer,text,smallint,text); CREATE OR REPLACE FUNCTION insert_cadastro(integer,text,smallint,text) RETURNS text as $$ DECLARE valor1 ALIAS FOR $1;

valor2 ALIAS FOR $2; valor3 ALIAS FOR $3; valor4 ALIAS FOR $4; Begin INSERT INTO cadastro VALUES ($1,$2,$3,$4); return 'Sucesso!'; end; $$LANGUAGE 'plpgsql' volatile called ON NULL input security invoker; select insert_cadastro(11,'oi','2','123'); select getcadastro('o'); Ob.: Faa quantas vezes for necessrio cada exemplo, at entender como as coisas funcionam.

Usando as Funo como TRIGGERS (Gatilhos).


So usados para disparar funes quando algo acontece nas tabelas, ou seja, um delete, update ou insert. Veja e execute os exemplos abaixo:

CREATE TABLE usuarios (nome varchar(30), senha char(32)); CREATE FUNCTION md5_senha() RETURNS TRIGGER AS $body$ BEGIN NEW.senha := md5(NEW.senha); RETURN NEW; END; $body$ LANGUAGE 'plpgsql';

CREATE TRIGGER md5_senha BEFORE INSERT ON

usuarios FOR EACH ROW EXECUTE PROCEDURE md5_senha(); INSERT INTO usuarios VALUES ('usuario', 'senha'); SELECT * FROM usuarios;
Agora implementar um exemplo real: Vamos imaginar que voc possua uma loja de Ferragens e queira controlar o estoque de seus produtos, porm de desejo seu que o apontamento de movimentaes seja feito atravs do Bando de Dados a cada insero de Sada de Produto. drop table produtos; create table produtos ( id serial primary key, descricao varchar(30), qtd_estoque integer ); select * from produtos;

insert into produtos (descricao,qtd_estoque) values ('Parafuso',100); insert into produtos (descricao,qtd_estoque) values ('Porca',100); insert into produtos (descricao,qtd_estoque) values ('Arruela',100); insert into produtos (descricao,qtd_estoque) values ('Chave de Fenda',100); insert into produtos (descricao,qtd_estoque) values ('Chave de Boca',100); insert into produtos (descricao,qtd_estoque) values ('Chave Alen',100); insert into produtos (descricao,qtd_estoque) values ('Parafuso 3/4',100); insert into produtos (descricao,qtd_estoque) values ('Lana',100); insert into produtos (descricao,qtd_estoque) values ('Martelo',100); insert into produtos (descricao,qtd_estoque) values ('Colher de Pedreiro',100);

drop table movimento_estoque; create table movimento_estoque (

id serial primary key, id_produtos integer references produtos, tipo_es integer, qtd integer, data date, hora time );

insert into movimento_estoque (id_produtos,qtd,tipo_es,data,hora) values (1,3,1,'2009-0303','13:30:00');

select * from movimento_estoque;

Desta forma que est , deveramos dar baixa no estoque executando um UPDATE.

update produtos set qtd_estoque=qtd_estoque-3 where id=1;

Assim mantemos o estoque atualizado, no mesmo: Porm, seria interessante que o Banco fizesse esta tarefa automaticamente Ento vamos criar um Funo que faa este trabalho para ns

create or replace function faz_movimento() returns trigger as

$$

Begin update produtos set qtd_estoque=qtd_estoque-new.qtd where id=new.id_produtos;

return new;

end; $$ language 'plpgsql'; create trigger tr_faz_movimento after insert or update or delete on movimento_estoque for each row execute procedure faz_movimento(); Agora, quando fizer uma insero na tabela de movimentos, o Banco de Dados executar a funo passando o registro atual (NEW) como parmetros para a funo que efetuar a baixa automtica na tabela Produtos. Vamos por a mo na Massa.

Trabalho para Nota valendo 5 pontos, na P2, os outro 5 pontos sero da P1. OBS.: Trabalhos que sejam iguais, ou contenham partes de outros trabalhos sero anulados.
Deve-se realizar um trabalho em grupo de 3 pessoas, que satisfaa os seguintes requisitos da empresa Bom de Servio. 1- Uma empresa de Cosmticos necessita de seu apoio para resolver a modelagem de seu sistema, porm opta por ter as regras de seu negcio dentro de um SGBD. Sendo assim ela necessita que voc modele e crie as regras de negcio usando PLPGSQL, e que satisfaa os seguintes requisitos. Obs.: No se apegue a detalhes. a. Todos os vendedores devem possuir CPF vlido. b. Todos os vendedores devem possuir mais que 18 anos. c. Todos os produtos devem ser mantidos em estoque, desta forma deve-se manter o estoque atualizado. d. Caso seja feito uma venda e um dos produtos esteja em falta este item deve ser anulado. e. Um vendedor pode enxergar os campos referentes aos produtos, porm o campo custo do produto no pode ser exibido. f. No permitido a venda de mais de 50 produtos iguais por pedido por vendedor por ms. g. Cada item pedido deve-se computar 5% do valor do item como comisso para o vendedor. h. Deve-se emitir uma ficha contendo todos os pedidos feitos pelo vendedor dizendo o nmero do pedido o total e a comisso lanada. Desta forma o vendedor sabe quanto ele vai receber. Este trabalho tem como objetivo melhorar a capacidade de informatizar processos usando como ferramenta gerenciadora o Banco de dados e suas funcionalidades.

Potrebbero piacerti anche