Вы находитесь на странице: 1из 24

CENTRO UNIVERSITRIO UNIVATES CURSO DE SISTEMAS DE INFORMAO

IMPLEMENTAO DE UM BANCO DE DADOS

Bruno Edgar Fhr Arthur Lehdermann Jonas Gualberto Diel

Lajeado, 08 de dezembro de 2010

Bruno Edgar Fhr Arthur Lehdermann Jonas Gualberto Diel

IMPLEMENTAO DE UM BANCO DE DADOS

Trabalho apresentado na disciplina de Banco de Dados, do curso de Sistemas de Informao, do Centro Universitrio Univates, como parte da exigncia para aprovao na disciplina. Professor: Evandro Franzen

Lajeado, 08 de dezembro de 2010.

SUMRIO
1 INTRODUO ............................................................................................................. 4 2 DOCUMENTAO INICIAL ........................................................................................ 5 3 MODELO LGICO ...................................................................................................... 6 4 INSTRUES SQL ..................................................................................................... 7 5 CONCLUSO ............................................................................................................ 24

1 INTRODUO
Neste trabalho iremos implementar um completo banco de dados para uma aplicao empresarial. Sero abordados os diferentes elementos que iro compor o banco de dados, tais como tabelas, vises, gatilhos, funes e consultas. Tambm ser descrita a situao a que a aplicao ser criada, bem como o modelo da base de dados necessrios.

2 DOCUMENTAO INICIAL
A situao escolhida pelo grupo para a criao de um banco de dados a de uma loja de vesturio, que comercializa itens como roupas, calados e artigos esportivos. O ttulo do banco de dados ser comerciall.

2.1 Escopo
O banco de dados dever suportar as operaes realizadas em uma loja que comercializa itens de vesturio, como roupas, calados e artigos esportivos(bolas, uniformes e equipamentos) , tais como compra e venda de produtos, controle de estoque, movimentao do caixa e administrao das contas a pagar e a receber.

2.2 Requisitos
O banco de dados deve controlar a entrada e sada de produtos (controle de estoque); Deve possibilitar realizar vendas vista e prazo; Deve possuir opes de relatrios tais como: Total de vendas em um perodo, Total de compras em um perodo, Produtos mais vendidos, Dias com maior movimentao de vendas, Valor total a receber e a pagar, Clientes inadimplentes e Vendas por cliente.

2.3 Objetivos
Descartar o controle manual (fichas) de valores a receber dos clientes, aumentar o controle sobre os itens do estoque e tornar o negcio melhor gerencivel, por meio de relatrios e consultas.

2.4 Justificativa
O gerente do estabelecimento est com dificuldades em controlar o negcio, tendo em vista que nos ltimos meses o fluxo de clientes aumentou, foi necessrio contratar mais funcionrios e decentralizar a tomada de decises da empresa.

3 MODELO LGICO
Aps o levantamento dos requisitos e dos dados que devero ser mantidos na aplicao, foi elaborado o seguinte modelo lgico do banco a ser desenvolvido:

4 INSTRUES SQL
A partir do modelo ER, foram construdas as tabelas, vises, funes, procedimentos e consultas, que veremos a seguir. Para a criao das tabelas e vises, foram utilizadas instrues SQL (DDL Linguagem de Definio de Dados); para as consultas, foram utilizadas instrues SQL (DML Linguagem de Manipulao de Dados); e para os procedimentos e funes utilizou-se a linguagem procedural PL/pgSQL. O SGDB (Sistema Gestor de Base de Dados) utilizado foi o PostgreSQL na sua verso 8.4.

4.1 Criao da base de dados


As instrues a seguir criam a base de dados, denominada comerciall, criam a linguagem PL/pgSQL, que ser usada para criar as funes e procedimentos, e altera o estilo da data da base de dados para o formato dia/ms/ano:
DROP DATABASE IF EXISTS comerciall; CREATE DATABASE comerciall; \c comerciall CREATE LANGUAGE plpgsql; ALTER DATABASE comerciall SET datestyle = SQL, DMY;

4.2 Domnios
A seguir, a definio dos domnios do sistema. O domnio , essencialmente, um tipo de dado com restries opcionais (restries no conjunto de valores permitidos). So teis para reunir restries comuns em campos em um nico local para manuteno.
CREATE DOMAIN codigo AS integer not null; CREATE DOMAIN nome AS varchar(80); CREATE DOMAIN descricao AS varchar(80); CREATE DOMAIN valor AS numeric(9,2); CREATE DOMAIN percent AS numeric(9,2); CREATE DOMAIN cpf AS char(11); CREATE DOMAIN cnpj AS char(14); CREATE DOMAIN memo as text; CREATE DOMAIN flag as boolean;

4.3 Tabelas
As tabelas em que sero armazenados os dados da aplicao so criadas utilizando-se instrues SQL (DDL). Junto com os comandos de criao, esto alguns comandos de insero de dados necessrios para o funcionamento do sistema, como por exemplo os estados brasileiros na tabela de estados.

CREATE TABLE tipos_pessoas ( codigo codigo, descricao descricao not null, tipo char(1) default 'f' check (tipo = 'f' or tipo = 'j'), -- pessoa fsica ou jurdica consumidor flag default true, -- cliente ou no fornecedor flag default false, -- fornecedor ou no constraint pk_tipos_pessoas primary key (codigo) ); INSERT INTO tipos_pessoas VALUES (1, 'Cliente - Pessoa Fsica' , 'f', true, false); INSERT INTO tipos_pessoas VALUES (2, 'Cliente - Pessoa Jurdica', 'j', true, false); INSERT INTO tipos_pessoas VALUES (3, 'Fornecedor' , 'j', false, true); INSERT INTO tipos_pessoas VALUES (4, 'Colaborador' , 'f', true, false); CREATE TABLE estados ( codigo codigo, nome nome not null, abreviatura char(2) not null, constraint pk_estados primary key (codigo) ); INSERT INTO estados (codigo, nome, abreviatura) VALUES (1, 'Acre' , 'AC'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (2, 'Alagoas' , 'AL'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (3, 'Amap' , 'AP'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (4, 'Amazonas' , 'AM'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (5, 'Bahia' , 'BA'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (6, 'Cear' , 'CE'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (7, 'Distrito Federal' , 'DF'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (8, 'Esprito Santo' , 'ES'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (9, 'Gois' , 'GO'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (10, 'Maranho' , 'MA'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (11, 'Mato Grosso' , 'MT'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (12, 'Mato Grosso do Sul' , 'MS'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (13, 'Minas Gerais' , 'MG'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (14, 'Par' , 'PA'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (15, 'Paraba' , 'PB'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (16, 'Paran' , 'PR'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (17, 'Pernambuco' , 'PE'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (18, 'Piau' , 'PI'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (19, 'Rio de Janeiro' , 'RJ'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (20, 'Rio Grande do Norte', 'RN'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (21, 'Rio Grande do Sul' , 'RS'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (22, 'Rondnia' , 'RO'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (23, 'Roraima' , 'RR'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (24, 'Santa Catarina' , 'SC'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (25, 'So Paulo' , 'SP'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (26, 'Sergipe' , 'SE'); INSERT INTO estados (codigo, nome, abreviatura) VALUES (27, 'Tocantins' , 'TO'); CREATE TABLE cidades ( codigo codigo, nome nome not null, cod_estado codigo, constraint pk_cidades primary key (codigo), constraint fk_cidades_estados foreign key (cod_estado) references estados ); CREATE TABLE estados_civis ( codigo codigo, descricao descricao not null, constraint pk_estados_civis primary key (codigo) );

INSERT INTO estados_civis (codigo, descricao) VALUES (1, 'Solteiro'); INSERT INTO estados_civis (codigo, descricao) VALUES (2, 'Casado'); INSERT INTO estados_civis (codigo, descricao) VALUES (3, 'Divorciado'); CREATE TABLE pessoas ( codigo codigo, nome nome not null, cod_tipo codigo, cpf cpf, rg char(10), sexo char(1) check (sexo = 'm' or sexo = 'f' or sexo = null), cnpj cnpj, inscr_estadual varchar(20), fantasia nome, cod_cidade integer, bairro nome, cep char(8), rua nome, numero varchar(10), complemento varchar(20), fone varchar(20), celular varchar(20), email nome, contato nome, data_nascimento date, cod_estado_civil integer, nome_conjuge nome, titulo_eleitor char(12), ativo flag default true, -- se cliente est ativo ou no data_cadastro date not null default date(now()), obs memo, constraint pk_pessoas primary key (codigo), constraint fk_pessoas_tipos_pessoas foreign key (cod_tipo) references tipos_pessoas, constraint fk_pessoas_estados_civis foreign key (cod_estado_civil) references estados_civis, constraint fk_pessoas_cidades foreign key (cod_cidade) references cidades ); CREATE TABLE usuarios ( codigo codigo, usuario descricao not null unique, senha descricao not null, cod_pessoa codigo, constraint pk_usuarios primary key (codigo), constraint fk_usuarios_pessoas foreign key (cod_pessoa) references pessoas on delete cascade on update cascade ); CREATE TABLE grupos ( codigo codigo, descricao descricao not null, constraint pk_grupos primary key (codigo) ); CREATE TABLE sub_grupos ( codigo codigo, cod_grupo codigo, descricao descricao not null, constraint pk_sub_grupos primary key (codigo), constraint pk_sub_grupos_grupos foreign key (cod_grupo) references grupos ); CREATE TABLE situacoes_produto ( codigo codigo, descricao descricao not null,

ativo flag default true, -- produto nessa situao est ativo ou no constraint pk_situacoes primary key (codigo) ); INSERT INTO situacoes_produto (codigo, descricao, ativo) VALUES (1, 'Ativo' , true); INSERT INTO situacoes_produto (codigo, descricao, ativo) VALUES (2, 'Inativo', false); CREATE TABLE tipos_operacoes ( codigo codigo, descricao descricao not null, natureza char(1) default 's' check (natureza = 's' or natureza = 'e'), -- tipo de operao: entrada ou sada constraint pk_tipos_operacoes primary key (codigo) ); INSERT INTO tipos_operacoes (codigo, descricao, natureza) VALUES (1, 'Venda' , 's'); INSERT INTO tipos_operacoes (codigo, descricao, natureza) VALUES (2, 'Compra', 'e'); CREATE TABLE tipos_produtos ( codigo codigo, descricao varchar(20) not null, controle_estoque flag default true, -- se para controlar o estoque ou no constraint pk_tipos_produtos primary key (codigo) ); INSERT INTO tipos_produtos (codigo, descricao, controle_estoque) VALUES (1, 'Produto', true); INSERT INTO tipos_produtos (codigo, descricao, controle_estoque) VALUES (2, 'Servio', false); CREATE TABLE produtos ( codigo codigo, descricao descricao not null unique, cod_tipo codigo, cod_grupo codigo, -- produto deve pertencer a um grupo cod_sub_grupo integer, -- mas no necessariamente a um sub_grupo. cod_situacao codigo, estoque_min integer default 0, estoque_max integer default 0, obs memo, constraint pk_produtos primary key (codigo), constraint fk_produtos_grupos foreign key (cod_grupo) references grupos, constraint fk_produtos_sub_grupos foreign key (cod_sub_grupo) references sub_grupos, constraint fk_produtos_situacoes_produto foreign key (cod_situacao) references situacoes_produto ); CREATE TABLE produtos_estoque ( cod_produto codigo, estoque integer default 0, constraint pk_produtos_estoque primary key (cod_produto), constraint fk_produtos_estoque_produtos foreign key (cod_produto) references produtos on delete cascade on update cascade ); CREATE TABLE produtos_valores ( cod_produto codigo, valor_entrada valor default 0.00, valor_saida valor default 0.00, valor_ult_entrada valor default 0.00, valor_ult_saida valor default 0.00, constraint pk_produtos_valores primary key (cod_produto), constraint fk_produtos_valores_produtos foreign key (cod_produto) references produtos on delete cascade on update cascade ); CREATE TABLE formas_pagamento ( codigo codigo,

descricao descricao not null, parcelado flag default true, -- forma de pagamento parcelada ou no num_parcelas integer not null default 0, tipo_intervalo_primeira char(1) default 'm' check (tipo_intervalo_primeira = 'm' or tipo_intervalo_primeira = 'd' or tipo_intervalo_primeira = 'a'), tipo_intervalo_parcelas char(1) default 'm' check (tipo_intervalo_parcelas = 'm' or tipo_intervalo_parcelas = 'd' or tipo_intervalo_parcelas = 'a'), prazo_primeira integer not null default 0, prazo_parcelas integer not null default 0, dia_vencimento integer not null default 0 check (dia_vencimento >= 0 and dia_vencimento < 31), desconto percent not null default 0, taxa_juros percent not null default 0, constraint pk_formas_pagamento primary key (codigo) ); INSERT INTO formas_pagamento (codigo, descricao, parcelado) VALUES (1, ' Vista', false); CREATE TABLE operacoes ( codigo codigo not null, cod_tipo codigo, cod_forma_pgto codigo, cod_pessoa codigo, cod_usuario codigo, num_doc_fiscal varchar(20) not null, data_operacao date not null default date(now()), titulo_gerado flag default false, -- Se j foram gerados ttulos para esta operao constraint pk_operacoes primary key (codigo), constraint fk_operacoes_tipos_operacoes foreign key (cod_tipo) references tipos_operacoes, constraint fk_operacoes_formas_pagamento foreign key (cod_forma_pgto) references formas_pagamento, constraint fk_operacoes_pessoas foreign key (cod_pessoa) references pessoas, constraint fk_operacoes_usuarios foreign key (cod_usuario) references usuarios ); CREATE TABLE itens_operacoes ( codigo codigo, cod_operacao codigo, cod_produto codigo, quantidade integer not null default 0, vlr_unitario valor not null default 0.00, constraint pk_itens_operacoes primary key (codigo), constraint fk_itens_operacoes_operacoes foreign key (cod_operacao) references operacoes on delete cascade on update cascade, constraint fk_itens_operacoes_produtos foreign key (cod_produto) references produtos ); CREATE TABLE titulos ( codigo codigo, cod_operacao codigo, valor valor not null default '0.00', data_emissao date not null default date(now()), data_vencimento date not null default date(now()), aberto flag default true, -- titulo aberto ou no data_baixa date, constraint pk_titulos primary key (codigo), constraint pk_titulos_operacoes foreign key (cod_operacao) references operacoes ); CREATE TABLE configuracoes ( codigo codigo, identificacao descricao not null unique, descricao text, valor descricao, constraint pk_configuracoes primary key (codigo, identificacao) );

INSERT INTO configuracoes VALUES (1, 'TAXA_PRECO_VENDA', 'Taxa (em %) que ser utilizada para calcular o preo de venda de um produto, em funo de seu preo de compra.', '30'); INSERT INTO configuracoes VALUES (2, 'PERIODO_CALCULO_PRECOS', 'Perodo (em meses) que sero calculadas as operaes de entrada para calcular os preos dos produtos.', '12');

4.4 Vises
Vises so consultas armazenadas na base de dados que podem ser referenciadas por outras consultas. Foram criadas algumas delas para facilitar e otimizar a consulta de dados: Viso para consultar pessoas que so consumidores;

CREATE OR REPLACE VIEW consumidores(cod_pessoa, nome_pessoa, cod_tipo, descricao_tipo) AS SELECT P.codigo, P.nome, T.codigo, T.descricao FROM pessoas P INNER JOIN tipos_pessoas T ON (T.codigo = P.cod_tipo) WHERE T.consumidor AND P.ativo;

Viso para consultar pessoas que so fornecedores;

CREATE OR REPLACE VIEW fornecedores(cod_pessoa, nome_pessoa, cod_tipo, descricao_tipo) AS SELECT P.codigo, P.nome, T.codigo, T.descricao FROM pessoas P INNER JOIN tipos_pessoas T ON (T.codigo = P.cod_tipo) WHERE T.fornecedor AND P.ativo;

Viso para consultar ttulos a pagar;

CREATE OR REPLACE VIEW titulos_a_pagar(cod_titulo, cod_operacao, operacao, cod_pessoa, nome_pessoa, valor, data_emissao, data_vencimento) AS SELECT T.codigo, O.codigo, OT.descricao, P.codigo, P.nome, T.valor, T.data_emissao, T.data_vencimento FROM titulos T, operacoes O, tipos_operacoes OT, pessoas P WHERE T.aberto AND T.cod_operacao = O.codigo AND OT.natureza = 'e' AND O.cod_tipo = OT.codigo AND O.cod_pessoa = P.codigo;

Viso para consultar ttulos a receber;

CREATE OR REPLACE VIEW titulos_a_receber(cod_titulo, cod_operacao, operacao, cod_pessoa, nome_pessoa, valor, data_emissao, data_vencimento) AS

SELECT T.codigo, O.codigo, OT.descricao, P.codigo, P.nome, T.valor, T.data_emissao, T.data_vencimento FROM titulos T, operacoes O, tipos_operacoes OT, pessoas P WHERE T.aberto AND T.cod_operacao = O.codigo AND OT.natureza = 's' AND O.cod_tipo = OT.codigo AND O.cod_pessoa = P.codigo;

Viso para consultar operaes com natureza de sada do estoque;

CREATE OR REPLACE VIEW operacoes_saida(cod_operacao, cod_tipo, descricao_tipo, cod_form_pgto, descricao_forma_pgto, cod_pessoa, cod_usuario, data_operacao, titulo_gerado) AS SELECT O.codigo, O.cod_tipo, T.descricao, O.cod_forma_pgto, F.descricao, O.cod_pessoa, O.cod_usuario, O.data_operacao, O.titulo_gerado FROM operacoes O LEFT JOIN tipos_operacoes T ON (T.codigo = O.cod_tipo) LEFT JOIN formas_pagamento F ON (F.codigo = O.cod_forma_pgto) WHERE T.natureza = 's';

Viso para consultar operacoes com natureza de entrada no estoque;

CREATE OR REPLACE VIEW operacoes_entrada(cod_operacao, cod_tipo, descricao_tipo, cod_form_pgto, descricao_forma_pgto, cod_pessoa, cod_usuario, data_operacao, titulo_gerado) AS SELECT O.codigo, O.cod_tipo, T.descricao, O.cod_forma_pgto, F.descricao, O.cod_pessoa, O.cod_usuario, O.data_operacao, O.titulo_gerado FROM operacoes O LEFT JOIN tipos_operacoes T ON (T.codigo = O.cod_tipo) LEFT JOIN formas_pagamento F ON (F.codigo = O.cod_forma_pgto) WHERE T.natureza = 'e';

Viso para consultar produtos com estoque abaixo do estoque mnimo;


produto, estoque_atual,

CREATE OR REPLACE VIEW produtos_abaixo_estoque(cod_produto, estoque_minimo) AS SELECT P.codigo, P.descricao, PE.estoque, P.estoque_min FROM produtos P INNER JOIN produtos_estoque PE ON (P.codigo = PE.cod_produto) WHERE PE.estoque < P.estoque_min;

Viso para consultar valores totais das operaes.

CREATE OR REPLACE VIEW operacoes_valores(cod_operacao, valor) AS SELECT O.codigo, SUM(I.quantidade * I.vlr_unitario) FROM operacoes O INNER JOIN itens_operacoes I ON (O.codigo = I.cod_operacao) GROUP BY O.codigo;

4.5 Triggers
Um trigger permite que uma determinada sequncia de comandos SQL seja acionada quando um determinado evento ocorre. A trigger abaixo grava na tabela produtos_estoque e produtos_valores, aps uma operao de insero na tabela de produtos, o registro referente ao novo produto.
/* Trigger para adicionar na tabela produtos_estoque depois de inserir na tabela produtos. * @return trigger * Autor: Bruno E. Fuhr */ CREATE OR REPLACE FUNCTION trigger_produtos_estoque() RETURNS trigger LANGUAGE plpgsql AS $$ DECLARE controla boolean; BEGIN SELECT INTO controla controle_estoque FROM tipos_produtos WHERE codigo = new.cod_tipo; IF (controla) THEN BEGIN INSERT INTO produtos_estoque (cod_produto) VALUES ( new.codigo ); END; END IF; INSERT INTO produtos_valores (cod_produto) VALUES ( new.codigo ); RETURN new; END; $$;

As triggers criadas a seguir fazem o controle de estoque do sistema. Para cada operao na tabela 'itens_operacoes', a tabela 'produtos_estoque' atualizada.
/* Trigger para atualizar o estoque aps uma operao de insert na tabela itens_operacoes. * @ return trigger * Autor: Bruno E. Fuhr */ CREATE OR REPLACE FUNCTION trigger_atualiza_estoque_ins() RETURNS trigger LANGUAGE plpgsql AS $$ DECLARE natureza_operacao char; controla boolean; est_antigo integer; est_atual integer; BEGIN SELECT INTO natureza_operacao T.natureza FROM tipos_operacoes T, operacoes O WHERE O.cod_tipo =

T.codigo AND O.codigo = new.cod_operacao; SELECT INTO controla T.controle_estoque FROM tipos_produtos T, produtos P WHERE P.cod_tipo = T.codigo AND P.codigo = new.cod_produto; -- Se controla estoque do produto. IF (controla) THEN BEGIN -- Se a natureza for entrada, adiciona do estoque. IF (natureza_operacao = 'e') THEN BEGIN SELECT INTO est_antigo estoque FROM produtos_estoque WHERE cod_produto = new.cod_produto; est_atual := est_antigo + new.quantidade; UPDATE produtos_estoque SET estoque = est_atual WHERE cod_produto = new.cod_produto; END; -- Seno, diminui do estoque. ELSE BEGIN SELECT INTO est_antigo estoque FROM produtos_estoque WHERE cod_produto = new.cod_produto; est_atual := est_antigo - new.quantidade; UPDATE produtos_estoque SET estoque = est_atual WHERE cod_produto = new.cod_produto; END; END IF; END; END IF; RETURN new; END; $$; CREATE TRIGGER atualiza_estoque_ins AFTER INSERT ON itens_operacoes FOR EACH ROW EXECUTE PROCEDURE trigger_atualiza_estoque_ins(); /* Trigger para atualizar o estoque aps uma operao de update na tabela itens_operacoes. * @ return trigger * Autor: Bruno E. Fuhr */ CREATE OR REPLACE FUNCTION trigger_atualiza_estoque_upd() RETURNS trigger LANGUAGE plpgsql AS $$ DECLARE natureza_operacao char; controla_old boolean; est_antigo_old integer; est_atual_old integer; controla_new boolean; est_antigo_new integer; est_atual_new integer; BEGIN SELECT INTO natureza_operacao T.natureza FROM tipos_operacoes T, operacoes O WHERE O.cod_tipo = T.codigo AND O.codigo = new.cod_operacao; SELECT INTO controla_old T.controle_estoque FROM tipos_produtos T, produtos P WHERE P.cod_tipo = T.codigo AND P.codigo = old.cod_produto; SELECT INTO controla_new T.controle_estoque FROM tipos_produtos T, produtos P WHERE P.cod_tipo = T.codigo AND P.codigo = new.cod_produto; -- Se controla estoque do produto que foi atualizado. IF (controla_old) THEN BEGIN -- Se a natureza for entrada, diminui do estoque. IF (natureza_operacao = 'e') THEN

BEGIN SELECT INTO est_antigo_old estoque FROM produtos_estoque WHERE cod_produto = old.cod_produto; est_atual_old := est_antigo_old - old.quantidade; UPDATE produtos_estoque SET estoque = est_atual_old WHERE cod_produto = old.cod_produto; END; -- Seno, adiciona no estoque. ELSE BEGIN SELECT INTO est_antigo_old estoque FROM produtos_estoque WHERE cod_produto = old.cod_produto; est_atual_old := est_antigo_old + old.quantidade; UPDATE produtos_estoque SET estoque = est_atual_old WHERE cod_produto = old.cod_produto; END; END IF; END; END IF; IF (controla_new) THEN BEGIN -- Se a natureza for entrada, adiciona do estoque. IF (natureza_operacao = 'e') THEN BEGIN SELECT INTO est_antigo_new estoque FROM produtos_estoque WHERE cod_produto = new.cod_produto; est_atual_new := est_antigo_new + new.quantidade; UPDATE produtos_estoque SET estoque = est_atual_new WHERE cod_produto = new.cod_produto; END; -- Seno, diminui do estoque. ELSE BEGIN SELECT INTO est_antigo_new estoque FROM produtos_estoque WHERE cod_produto = new.cod_produto; est_atual_new := est_antigo_new - new.quantidade; UPDATE produtos_estoque SET estoque = est_atual_new WHERE cod_produto = new.cod_produto; END; END IF; END; END IF; RETURN new; END; $$; CREATE TRIGGER atualiza_estoque_upd AFTER UPDATE ON itens_operacoes FOR EACH ROW EXECUTE PROCEDURE trigger_atualiza_estoque_upd(); /* Trigger para atualizar o estoque aps uma operao de delete na tabela itens_operacoes. * @ return trigger * Autor: Bruno E. Fuhr */ CREATE OR REPLACE FUNCTION trigger_atualiza_estoque_del() RETURNS trigger LANGUAGE plpgsql AS $$ DECLARE natureza_operacao char; controla boolean; est_antigo integer; est_atual integer; BEGIN SELECT INTO natureza_operacao T.natureza FROM tipos_operacoes T, operacoes O WHERE O.cod_tipo = T.codigo AND O.codigo = old.cod_operacao;

SELECT INTO controla T.controle_estoque FROM tipos_produtos T, produtos P WHERE P.cod_tipo = T.codigo AND P.codigo = old.cod_produto; -- Se controla estoque do produto. IF (controla) THEN BEGIN -- Se a natureza for entrada, diminui do estoque. IF (natureza_operacao = 'e') THEN BEGIN SELECT INTO est_antigo estoque FROM produtos_estoque WHERE cod_produto = old.cod_produto; est_atual := est_antigo - old.quantidade; UPDATE produtos_estoque SET estoque = est_atual WHERE cod_produto = old.cod_produto; END; -- Seno, adiciona no estoque. ELSE BEGIN SELECT INTO est_antigo estoque FROM produtos_estoque WHERE cod_produto = old.cod_produto; est_atual := est_antigo + old.quantidade; UPDATE produtos_estoque SET estoque = est_atual WHERE cod_produto = old.cod_produto; END; END IF; END; END IF; RETURN new; END; $$; CREATE TRIGGER atualiza_estoque_del AFTER DELETE ON itens_operacoes FOR EACH ROW EXECUTE PROCEDURE trigger_atualiza_estoque_del();

A prxima trigger atualiza a tabela produtos_valores aps uma operao de insero na tabela itens_operacoes.
/* * Trigger para atualizar a tabela produtos_valores, gravando no campo valor_ult_entrada ou valor_ult_saida, dependendo do tipo de operacao. * Autor: Bruno E. Fuhr */ CREATE OR REPLACE FUNCTION trigger_atualiza_ultimos_valores() RETURNS trigger LANGUAGE plpgsql AS $$ DECLARE natureza_operacao char; BEGIN SELECT INTO natureza_operacao T.natureza FROM tipos_operacoes T, operacoes O WHERE O.cod_tipo = T.codigo AND O.codigo = new.cod_operacao; IF ( natureza_operacao = 'e' ) THEN BEGIN UPDATE produtos_valores SET valor_ult_entrada = new.vlr_unitario WHERE cod_produto = new.cod_produto; END; ELSE BEGIN UPDATE produtos_valores SET valor_ult_saida = new.vlr_unitario WHERE cod_produto = new.cod_produto; END; END IF;

RETURN new; END; $$; CREATE TRIGGER atualiza_ultimos_valores AFTER INSERT ON itens_operacoes FOR EACH ROW EXECUTE PROCEDURE trigger_atualiza_ultimos_valores();

4.6 Funes e procedimentos


Funes ou procedimentos so tarefas que esto armazenadas na base de dados e que so executadas diretamente no servidor de banco de dados. Foram criadas funes para gerar dados de testes, consultar registros e atualizar valores em tabelas. 4.6.1 Funes para gerar dados de testes A seguinte funo foi criada para inserir registros na tabela produto. Ela gera o cdigo para o produto, obtm aleatoriamente o grupo e o tipo do produto e monta a descrio com a palavra 'Produto' concatenada com o cdigo gerado. Por fim, o comando para gerar os registros, passando como parmetro o nmero de registros a serem inseridos na tabela.
CREATE OR REPLACE FUNCTION gerarProdutos(integer) RETURNS INTEGER LANGUAGE plpgsql AS $$ DECLARE cod integer; tipo integer; grupo integer; BEGIN SELECT INTO cod MAX(codigo) FROM produtos; IF ( cod IS NULL ) THEN cod := 1; ELSE cod := cod + 1; END IF; WHILE ( cod <= $1 ) LOOP IF ( CAST(random()*2 AS integer) = 0 ) THEN tipo := 1; ELSE tipo := 2; END IF; grupo := CAST(random()*50 AS integer); IF ( grupo = 0 ) THEN grupo := 1; END IF; INSERT INTO produtos (codigo, descricao, cod_tipo, cod_grupo, cod_situacao, estoque_max) VALUES (cod, 'Produto ' || cod, tipo, grupo, 1, 10); cod := cod + 1; END LOOP; RETURN 0; END; $$;

SELECT gerarProdutos(800);

A seguir foi implementada uma funo para gerar as operaes. Esta operao gera um cdigo para cada operao e sorteia se a natureza entrada ou sada. Deve ser passado por parmetro o nmero de operaes a serem criadas.
CREATE OR REPLACE FUNCTION gerarOperacoes(integer) RETURNS INTEGER LANGUAGE plpgsql AS $$ DECLARE cod integer; pessoa integer; usuario integer; pgto integer; cont integer; oper integer; BEGIN SELECT INTO cod MAX(codigo) FROM operacoes; IF ( cod IS NULL ) THEN cod := 1; ELSE cod := cod + 1; END IF; cont := 1; WHILE (cont <= $1) LOOP BEGIN -- Sorteia para inserir operao de entrada ou sada. SELECT INTO oper CAST(random() * 2 as integer); IF ( oper < 2 ) THEN BEGIN SELECT INTO pessoa cod_pessoa FROM consumidores ORDER BY random() limit 1; SELECT INTO usuario codigo FROM usuarios ORDER BY random() limit 1; SELECT INTO pgto codigo FROM formas_pagamento ORDER BY random() limit 1; INSERT INTO operacoes (codigo, cod_tipo, cod_forma_pgto, cod_pessoa, cod_usuario, num_doc_fiscal) VALUES (cod, 1, pgto, pessoa, usuario, CAST(cod as varchar(20))); END; ELSE BEGIN SELECT INTO pessoa cod_pessoa FROM fornecedores ORDER BY random() limit 1; SELECT INTO usuario codigo FROM usuarios ORDER BY random() limit 1; SELECT INTO pgto codigo FROM formas_pagamento ORDER BY random() limit 1; INSERT INTO operacoes (codigo, cod_tipo, cod_forma_pgto, cod_pessoa, cod_usuario, num_doc_fiscal) VALUES (cod, 2, pgto, pessoa, usuario, cast(cod as varchar(20))); END; END IF; cod := cod + 1; cont := cont + 1; END; END LOOP; RETURN 0; END; $$; SELECT gerarOperacoes(100000);

Para inserir os itens nas operaes, foi criada a seguinte funo.

CREATE OR REPLACE FUNCTION gerarItens() RETURNS integer LANGUAGE plpgsql AS $$ DECLARE cod integer; cod_oper integer; num_itens integer; contador integer; cod_prod integer; quant integer; valor numeric(9,2); num_prod integer; BEGIN SELECT INTO cod MAX(codigo) FROM itens_operacoes; IF ( cod IS NULL ) THEN cod := 1; ELSE cod := cod + 1; END IF; SELECT INTO num_prod count(*) FROM produtos; FOR cod_oper IN SELECT codigo FROM operacoes LOOP BEGIN contador := 1; -- Sorteia quantos itens sero adicionados operao. Mximo de 6 itens. SELECT INTO num_itens CAST((random() * 6) as integer); WHILE ( contador <= num_itens ) LOOP BEGIN SELECT INTO quant CAST((random() * 10) as integer); IF ( quant = 0 ) THEN quant := 1; END IF; SELECT INTO valor CAST((random() * 100) as numeric(9,2)); IF ( valor = 0 ) THEN valor := 1; END IF; SELECT INTO cod_prod CAST((random() * num_prod) as integer); IF ( cod_prod = 0 ) THEN cod_prod := 1; END IF; INSERT INTO itens_operacoes (codigo, cod_operacao, cod_produto, quantidade, vlr_unitario) VALUES (cod, cod_oper, cod_prod, quant, valor); cod := cod + 1; contador := contador + 1; END; END LOOP; END; END LOOP; RETURN cod; END; $$; SELECT gerarItens();

4.6.2 Funes para consultar registros

A seguinte funo tem como finalidade retornar os ttulos a receber em aberto, em um determinado perodo de tempo, que deve ser informado nos parmetros de entrada da funo.
-- Criar um tipo para retornar na funo CREATE TYPE type_titulos AS (codigo integer, cod_operacao integer, operacao descricao, cod_pessoa integer, nome_pessoa nome, data_vencimento date, valor valor); /* Funo para retornar os ttulos a receber em aberto com data de vencimento em determinado perodo. * @param data_inicial - Data de incio dos ttulos pesquisados. * @param data_final - Data final dos ttulos pesquisados. * @return - Retorna lista com ttulos em aberto no perodo pesquisado. * Autor: Bruno E. Fuhr */ CREATE OR REPLACE FUNCTION obter_titulos_a_receber(data_inicial date, data_final date) RETURNS SETOF type_titulos LANGUAGE plpgsql AS $$ DECLARE titulos type_titulos; BEGIN FOR titulos IN SELECT cod_titulo, cod_operacao, operacao, cod_pessoa, nome_pessoa, data_vencimento, cast(valor as decimal(9,2)) FROM titulos_a_receber WHERE data_vencimento BETWEEN $1 AND $2 LOOP RETURN NEXT titulos; END LOOP; RETURN; END; $$;

4.6.3 Funes para atualizar registros Para o clculo dos preos dos produtos, foi criada uma funo que, conforme as configuraes definidas pelo usurio, calcula o preo de entrada e o preo de sada dos produtos. As configuraes definidas pelo usurio so a taxa percentual do preo de saida sobre o preo de entrada e o perodo de operaes que ser utilizado para o clculo dos valores.
/* * Funo para calcular os valores dos produtos. * Autor: Bruno E. Fuhr */ CREATE OR REPLACE FUNCTION calcular_valores_produtos() RETURNS integer LANGUAGE plpgsql AS $$ DECLARE prod refcursor; tx_vlr_saida numeric(9,2); periodo integer; cod_prod integer; vlr_entrada numeric(9,2); vlr_saida numeric(9,2); BEGIN

SELECT INTO tx_vlr_saida CAST(valor as numeric(9,2)) FROM configuracoes WHERE identificacao = 'TAXA_PRECO_VENDA'; tx_vlr_saida := tx_vlr_saida/100 + 1; SELECT INTO periodo CAST(valor as integer) * 30 FROM configuracoes WHERE identificacao = 'PERIODO_CALCULO_PRECOS'; OPEN prod FOR SELECT I.cod_produto, CAST(SUM(I.quantidade * I.vlr_unitario)/SUM(I.quantidade) as numeric(9,2)) FROM itens_operacoes I LEFT JOIN operacoes_entrada O ON (I.cod_operacao = O.cod_operacao) WHERE O.data_operacao BETWEEN current_date - periodo AND current_date GROUP BY I.cod_produto; FETCH prod INTO cod_prod, vlr_entrada; WHILE FOUND LOOP IF ( vlr_entrada > 0 ) THEN BEGIN vlr_saida := vlr_entrada * tx_vlr_saida; UPDATE produtos_valores SET valor_entrada = vlr_entrada, valor_saida = vlr_saida WHERE cod_produto = cod_prod; END; END IF; FETCH prod INTO cod_prod, vlr_entrada; END LOOP; CLOSE prod; RETURN 1; END; $$;

4.7 Consultas
Para se obter as informaes necessrias para o gerenciamento do negcio, foram elaboradas algumas consultas base de dados, que sero apresentadas a seguir: Consulta 1) Consultar o saldo devedor das pessoas. O objetivo desta consulta fornecer ao gerente do negcio uma lista com os valores de cada pessoa que possui algum titulo em aberto no sistema. Esta lista formada pelo cdigo e nome da pessoa e seu saldo em aberto (soma dos valores dos titulos em aberto).
SELECT P.codigo as cod_pessoa, P.nome as nome_pessoa, SUM(T.valor) as saldo_devedor FROM pessoas P, operacoes O, titulos_a_receber T WHERE T.cod_operacao = O.codigo AND O.cod_pessoa = P.codigo GROUP BY P.codigo, P.nome;

Consulta 2) Consultar nmero de operaes de sada (venda) e o valor (soma dos totais dos itens) destas operaes no ms corrente, para cada vendedor, excluindo as operaes onde o valor for 0. O objetivo desta consulta o monitoramento da equipe de vendas pelo gerente, mostrando os resultados das vendas do ms corrente para cada vendedor. As informaes retornadas por esta pesquisa so: codigo e nome da pessoa, login do usuario, total de vendas no ms, valor total de vendas no ms.
SELECT P.codigo, P.nome, U.usuario, COUNT(O.codigo) as total_vendas, SUM(V.valor) as valor_total_vendas FROM pessoas P LEFT JOIN usuarios U ON (P.codigo = U.cod_pessoa) LEFT JOIN operacoes O ON (U.codigo = O.cod_usuario) LEFT JOIN operacoes_valores V ON (O.codigo = V.cod_operacao) LEFT JOIN tipos_operacoes T ON (T.codigo = O.cod_tipo) WHERE T.natureza = 's' AND DATE_PART('MONTH', O.data_operacao) = DATE_PART('MONTH', current_date) AND DATE_PART('YEAR', O.data_operacao) = DATE_PART('YEAR', current_date) AND V.valor > 0 GROUP BY P.codigo, P.nome, U.usuario ORDER BY total_vendas DESC;

Consulta 3) Consultar a forma de pagamento mais utilizada nas operaes de venda. Esta informao ser importante para auxiliar o gerente a definir sua estratgia de vendas. Ser retornado o cdigo e a descrio da forma de pagamento e o total de operaes de venda realizadas com esta forma de pagamento.

SELECT F.codigo, F.descricao, COUNT(O.codigo) as total FROM formas_pagamento F, operacoes O WHERE F.codigo = O.cod_forma_pgto GROUP BY F.codigo, F.descricao ORDER BY total DESC;

Consulta 4) Consultar valores das operaes por pessoa, a fim de mostrar quais os consumidores que mais gastaram. Retorno da consulta: codigo e nome da pessoa, total de compras efetuadas pelo consumidor (ir somar apenas operaes em que o valor da operao for maior que 0), valor total das compras do consumidor.
SELECT C.cod_pessoa, C.nome_pessoa, COUNT(O.cod_operacao) as total_compras, SUM(V.valor) as valor_total_compras FROM consumidores C LEFT JOIN operacoes_saida O ON (C.cod_pessoa = O.cod_pessoa) LEFT JOIN operacoes_valores V ON (V.cod_operacao = O.cod_operacao) WHERE V.valor > 0 GROUP BY C.cod_pessoa, C.nome_pessoa ORDER BY valor_total_compras DESC;

Consulta 5) Listar os 10 produtos mais vendidos (quantidade) no ms (por exemplo, no ms de setembro). Esta informao ser til para o gerente programar promoes. A lista dever informar o cdigo e descrio do produto, a quantidade vendida no ms pesquisado e a quantidade atual de estoque deste produto.
SELECT P.codigo, P.descricao, SUM(I.quantidade) as qtde_vendida, E.estoque as est_atual FROM produtos P LEFT JOIN produtos_estoque E ON (P.codigo = E.cod_produto) LEFT JOIN itens_operacoes I ON (I.cod_produto = P.codigo) LEFT JOIN operacoes O ON (O.codigo = I.cod_operacao) WHERE O.data_operacao BETWEEN '01/09/2010' AND '30/09/2010' GROUP BY P.codigo, P.descricao, E.estoque ORDER BY qtde_vendida DESC LIMIT 10;

6 CONCLUSO
A partir do desenvolvimento deste banco de dados, foi possvel observar na prtica o comportamento de elementos como tabelas, vises, gatilhos e funes, com a insero, edio, excluso e consulta de registros. Tambm foi observada a importncia de manter a integridade relacional entre as tabelas a fim de manter a relevncia dos dados nelas contidas e a importncia dos ndices na performance de consultas.

Вам также может понравиться