programação de banco de dados

32
Programação de Banco de Dados - parte 1 Este é o primeiro de uma série de artigos relacionado com programação de Banco de Dados. Nos artigos iniciais o enfoque é explicar as tecnologias relacionadas ao acesso a dados voltado para os programadores que não estão acostumados com várias siglas como: OLE DB, ODBC, ADO , com termos como: duas camadas, três camadas. Conceitos Iniciais » Introdução Um banco de dados é usado para armazenar informações estruturadas e organizadas de forma a permitir sua recuperação rápida e eficiente.Existem diversos Modelos de banco de dados como: Em Rede, hierárquico, Relacional e Orientado a Objeto. Os Modelos em Rede e Hierárquico no momento não são mais utilizados, somente em projetos antigos você ainda encontra esses modelos, nesse artigo vamos focar o Modelo Relacional que é o modelo usado no momento. O modelo Orientado a Objeto ainda em estudo e com certeza o modelo do futuro (no último artigo falarei um pouco desse modelo). No Modelo Relacional a informação é dividida em tabelas, e cada tabela representa entidades, desta forma dividimos as informações em porções onde as entidades se relacionam.As tabelas possuem atributos (campos) que são as colunas, as linhas são os registros (dados).Os relacionamentos permitem que os usuários combinem informações de várias tabelas através de chaves primárias e chaves estrangeiras ou secundárias. O SGBD (Sistema Gerenciador de Banco de Dados) é responsável em manter a integridades dos dados onde o programador pode definir algumas regras outras possui definição default.Os SGBD tem sete características operacionais elementares sempre observadas, que passaremos a listar: Característica 1: Controle de Redundâncias - A redundância consiste no armazenamento de uma mesma informação em locais diferentes, provocando inconsistências. Em um Banco de Dados as informações só se encontram armazenadas em um único local, não existindo duplicação descontrolada dos dados. Quando existem replicações dos dados, estas são decorrentes do processo de armazenagem típica do ambiente Cliente-Servidor, totalmente sob controle do Banco de Dados. Característica 2: Compartilhamento dos Dados - O SGBD deve incluir software de controle de concorrência ao acesso dos dados, garantindo em qualquer tipo de situação a escrita/leitura de dados sem erros. Característica 3: Controle de Acesso - O SGDB deve dispor de recursos que possibilitem selecionar a autoridade de cada usuário. Assim um usuário poderá realizar qualquer tipo de acesso, outros poderão ler alguns dados e atualizar outros e outros ainda poderão somente acessar um conjunto restrito de dados para escrita e leitura. Característica 4: Interfaceamento - Um Banco de Dados deverá disponibilizar formas de acesso gráfico, em linguagem natural, em SQL ou ainda via menus de acesso, não sendo uma "caixa-preta" somente sendo passível de ser acessada por aplicações.

Upload: api-3704649

Post on 07-Jun-2015

2.840 views

Category:

Documents


0 download

DESCRIPTION

Apostila de programação de banco de dados. Agosto/2007.

TRANSCRIPT

Page 1: Programação de Banco de Dados

Programação de Banco de Dados - parte 1

Este é o primeiro de uma série de artigos relacionado com programação de Banco de Dados. Nos artigos iniciais o enfoque é explicar as tecnologias relacionadas ao acesso a dados voltado para os programadores que não estão acostumados com várias siglas como: OLE DB, ODBC, ADO , com termos como: duas camadas, três camadas.

Conceitos Iniciais

» Introdução

Um banco de dados é usado para armazenar informações estruturadas e organizadas de forma a permitir sua recuperação rápida e eficiente.Existem diversos Modelos de banco de dados como: Em Rede, hierárquico, Relacional e Orientado a Objeto.

Os Modelos em Rede e Hierárquico no momento não são mais utilizados, somente em projetos antigos você ainda encontra esses modelos, nesse artigo vamos focar o Modelo Relacional que é o modelo usado no momento. O modelo Orientado a Objeto ainda em estudo e com certeza o modelo do futuro (no último artigo falarei um pouco desse modelo).

No Modelo Relacional a informação é dividida em tabelas, e cada tabela representa entidades, desta forma dividimos as informações em porções onde as entidades se relacionam.As tabelas possuem atributos (campos) que são as colunas, as linhas são os registros (dados).Os relacionamentos permitem que os usuários combinem informações de várias tabelas através de chaves primárias e chaves estrangeiras ou secundárias.

O SGBD (Sistema Gerenciador de Banco de Dados) é responsável em manter a integridades dos dados onde o programador pode definir algumas regras outras possui definição default.Os SGBD tem sete características operacionais elementares sempre observadas, que passaremos a listar:

Característica 1: Controle de Redundâncias - A redundância consiste no armazenamento de uma mesma informação em locais diferentes, provocando inconsistências. Em um Banco de Dados as informações só se encontram armazenadas em um único local, não existindo duplicação descontrolada dos dados. Quando existem replicações dos dados, estas são decorrentes do processo de armazenagem típica do ambiente Cliente-Servidor, totalmente sob controle do Banco de Dados.

Característica 2: Compartilhamento dos Dados - O SGBD deve incluir software de controle de concorrência ao acesso dos dados, garantindo em qualquer tipo de situação a escrita/leitura de dados sem erros.

Característica 3: Controle de Acesso - O SGDB deve dispor de recursos que possibilitem selecionar a autoridade de cada usuário. Assim um usuário poderá realizar qualquer tipo de acesso, outros poderão ler alguns dados e atualizar outros e outros ainda poderão somente acessar um conjunto restrito de dados para escrita e leitura.

Característica 4: Interfaceamento - Um Banco de Dados deverá disponibilizar formas de acesso gráfico, em linguagem natural, em SQL ou ainda via menus de acesso, não sendo uma "caixa-preta" somente sendo passível de ser acessada por aplicações.

Característica 5: Esquematização - Um Banco de Dados deverá fornecer mecanismos que possibilitem a compreensão do relacionamento existentes entre as tabelas e de sua eventual manutenção.

Característica 6: Controle de Integridade - Um Banco de Dados deverá impedir que aplicações ou acessos pelas interfaces possam comprometer a integridade dos dados.

Característica 7: Backups - O SGBD deverá apresentar facilidade para recuperar falhas de hardware e software, através da existência de arquivos de "pré-imagem" ou de outros recursos automáticos, exigindo minimamente a intervenção de pessoal técnico.

OBS: O SQL é uma linguagem universal de definição de base de dados e manipulação de dados. SQL Server , MySql são SGBD.

Page 2: Programação de Banco de Dados

» OLE DB / ODBC / ADO

O OLE DB é uma camada que está situada no topo do banco de dados. O ADO, por sua vez, está no topo do OLE DB e oferece uma visão simplificada do banco de dados. Como cada BD expõe sua funcionalidade com uma série de funções próprias API (Application Programming Interface) para acessar cada BD pela interface nativa você tem de aprender características do BD (baixo nível).Para desenvolver aplicativos que conversem com dois bancos de dados diferentes (SQL Server e Oracle, por exemplo) você teria que conhecer duas API's diferentes e suas peculiaridades, a não ser que você use o OLE DB e o ADO.

O OLE DB oferece uma visão unificada de diferentes fornecedores de dados.Cada BD possui sua própria série de fornecedores de serviços OLE DB, que fornecem uma visão uniforme do BD. O ADO esconde as peculiaridades de cada BD e fornece aos desenvolvedores uma visão conceitual simples do BD em uso.

A diferença entre ADO e OLE DB é que o OLE DB permite que você tenha maior controle sobre o processo de acesso de dados, onde usa uma interface de baixo nível. O OLE DB utiliza ponteiros e outros mecanismos do C++, tornando substancialmente mais difícil que o ADO.O ADO oferece uma visão simplificada e de alto nível para o acesso a BD.

Você também pode acessar o BD por meio de ODBC, que é similar ao OLE DB, porém é uma tecnologia antiga , e não há razão para usar drivers ODBC. Muitos conhecem DAO e RDO, essas são tecnologias antigas de acesso a BD por meio de ODBC e são equivalentes ao ADO.

» ADO

Veremos uma visão geral do objeto ADO.Um aplicativo cliente realiza o seguinte:

Conexão com banco de dados. Executa comandos por meio do banco de dados. Recupera informações do banco de dados.

Os objetos básicos do ADO que correspondem a essas operações são chamados de Connection, Command e Recordset. O objeto Connection representa uma conexão com o banco de dados.Você especifica o banco de dados que deseja conectar e chame o método Open. Uma vez que você estabeleceu uma conexão com o BD, os comandos podem ser executados. Um comando pode ser uma instrução SQL ou o nome de um procedimento armazenado.Para executar uma instrução SQL ou um procedimento armazenado, você deve configurar um objeto Connection e depois chamar seu método Execute para executar o comando.O objeto Command contém a instrução SQL ou o nome do procedimento armazenado, bem côo os argumentos necessários.Se o comando recupera informações os resultados serão mantidos em um objeto Recordset onde poderá acessa-los dentro do seu aplicativo por meio dos métodos e das propriedades do Recordset. Nos próximos artigos falaremos detalhadamente sobre o objeto ADO. Mas antes veremos a Arquitetura Cliente / Servidor onde abordaremos o Modelo de Duas e Três camadas.

Programação de Banco de Dados - parte 2

Este é o segundo artigo relacionado com programação de Banco de Dados. No primeiro artigo o enfoque foi explicar as tecnologias relacionadas ao acesso a dados. Neste segundo artigo voltaremos nossa atenção para a arquitetura cliente/servidor. Se você está desenvolvendo aplicativos de banco de dados para executar em uma rede local, a arquitetura cliente/servidor é adequada para esse trabalho.

Arquitetura Cliente/Servidor.

A arquitetura cliente/servidor possui uma premissa simples: computadores diferentes executam tarefas diferentes e cada computador pode se otimizado para uma tarefa em particular.Em um ambiente de rede, o SGBD fica em uma única máquina.Contudo, muitos aplicativos acessam o banco de dados e todos os clientes fazem solicitações ao mesmo banco de dados.O programa que aceita e trabalha essas solicitações é o SGBD, e a máquina na qual o SGBD está sendo executado é o servidor de dados.

O Modelo de Duas Camadas.

Page 3: Programação de Banco de Dados

A primeira camada de um aplicativo cliente/servidor é a camada cliente que é executada no cliente.Essa camada contém o aplicativo que interagem com o usuário e usualmente são aplicativos em VB.Você também pode construir camadas clientes que são executadas em um navegador - são páginas Web que possuem controles semelhantes ao controles básicos do VB e possibilitam ao usuário interagir com o banco de dados.

O aplicativo cliente solicita dados de um banco de dados e exibe-os em um ou mais formulários.Um vez que os dados estão no computador cliente, seu aplicativo pode processa-los.O computador cliente é inteiramente capaz de manipular os dados localmente, sem que o servidor se envolva no processo.Se o usuário edita os campos, o aplicativo pode atualizar o banco de dados sem problemas.A comunicação entre o cliente e o servidor ocorre por meio do ADO, que torna mais simples o processo de manipulação dos dados.

A segunda camada é servidor de bando de dados, ou SGBD. Essa camada manipula um objeto muito complexo, o banco de dados , e oferece uma visão simplificada deste por meio do OLE DB e ADO.O trabalho do servidor é extrair os dados solicitados de uma tabela e fornece-los ao cliente na forma de um cursor, ou seja, ele simplesmente transmite um cursor ao cliente para que este processe a com termos como: duas camadas, três camadas.

Na segunda camada é possível através de procedimentos armazenados executar as operações no lado do SGBD, pela divisão do trabalho entre cliente e servidores, permitimos que cada aplicativo faça o melhor. O SGBD é executados em uma das máquinas mais rápidas da rede, os clientes não precisam ser poderosos.

No modelo de 2 camadas existe a possibilidade de deixar do lado do Servidor parte ou toda a regra do negócio.Essa metodologia foi e ainda é muito usado. Para se dizer que se trabalha em 2 camadas a camada cliente possui um software e a camada servidor também é um software, neste caso software conversa com software.No caso do Access , mesmo colocando em uma máquina na rede sendo o servidor e os aplicativos acessando o Access não seria modelo de 2 camadas pois o Access não é um SGBD , não existe a comunicação software x software. Quem efetua essa comunicação é o driver.O aplicativo cliente efetua a solicitação e o "driver" que se encarrega de atender. O SQL Server, My SQL , Oracle são SGBD.

No entanto muitos consideram o Access um SGBD pelo fato de trazer algumas características de um SGBD como controle de concorrência, mas ele não é um banco cliente/servidor.

O MODELO DE 3 CAMADAS

O modelo de 3 camadas possui uma arquitetura muito eficiente para aplicativos de bando de dados, mas nem sempre é a melhor escolha.Muitos programadores desenvolvem aplicativos de duas camadas que são executados em pequenas redes.

Em 2 camadas o cliente conversa diretamente com o servidor. O papel do servidor do banco é acessar e atualizar os dados. O resto é deixado para o cliente.Se encontra aplicativo onde é deixado toda a regra do negocio do lado do cliente, toda a regra do negócio do lado do servidor ou então dividido entre cliente e servidor.

Vamos analisar essas 3 possibilidades de implementação em 2 camadas.

Regra do negócio do lado do cliente: uma vez que regras do negócio refletem práticas comerciais, elas mudam com muita freqüência. Novas regras são introduzidas, as existentes são revisadas e isso significa que o código que as implementam está sujeito a alterações freqüentes. Se implementar regras do negócio no cliente , você deve distribuir os novos executáveis para as estações de trabalho e certificar-se de que todos os usuários da rede estão usando a última versão do software cliente.

Regra do negócio do lado do servidor: se as regras do negócio são implementadas no servidor, você não precisa redistribuir o aplicativo, mas atribui uma carga adicional ao servidor.

Regra do negócio tanto no servidor com no cliente: desta forma divide o processamento entre cliente e servidor, mas no entanto fica segmentado a regra do negócio trazendo assim maior dificuldade em atualizações.

Page 4: Programação de Banco de Dados

Isso nos leva, naturalmente para introdução de uma 3 camada, a camada intermediaria.A camada intermediaria é um objeto que se situa entre o aplicativo cliente e o servidor.Trata-se de uma classe ou várias classes que expõe vários métodos e isola o cliente do servidor. A principal vantagem da camada intermediaria é que ela isola o cliente do servidor. O cliente já não acessa o bando de dados.Em vez disso, ele chama os métodos expostos pelos objetos na camada intermediaria.Um aplicativo cliente eventualmente adicionará um novo cliente ao banco, mesmo essa simples operação requer alguma validação.Um aplicativo bem estruturado implementa essas operações na camada intermediária. O aplicativo cliente não precisa saber como adicionar um novo cliente, basta chamar a função que efetua o cadastro passando os valores como argumentos. O modelo de 3 camadas divide os componentes de um aplicativo em 3 categorias:

Camada de Apresentação: Este programa é executado no cliente e interage com o usuário.Você usualmente desenvolvera aplicativos para a camada de apresentação e esses aplicativos serão chamados freqüentemente de serviços do usuário.

Camada de Aplicação: conhecida como camada de regras do negócio, está camada contém a lógica do aplicativo.Isso simplifica o acesso do cliente ao banco de dados por meio do isolamento do serviço de usuários do bando de dados.Essa camada é projetada antes que você comece a codificar o aplicativo cliente.

Camada de Dados: esta camada esta no servidor de bando de dados que atende as solicitações feitas pelos clientes.O servidor do banco de dados deve atualiza-lo e ao mesmo tempo proteger sua integridade.

É comum encontrar modelos de 3 camadas sendo uma camada cliente, um servidor Web e um servidor de banco de dados, ficando a regra do negócio divida ou centralizada em uma das camadas.Dessa forma surgiu o modelo de 4 camadas onde teria o lado cliente, servidor Web, servidor de banco de dados e servidor com a regra do negócio.Esse modelo não é ainda muito aplicado e pouco necessário, até mesmo o de 3 camadas com servidor de regras do negócio é pouco aplicado e necessário.

O ACCESS E APLICATIVOS CLIENTE/SERVIDOR O Access não é um servidor de bando de dados.Quando você contata o Access e abre uma tabela, a tabela inteira é carregada para a memória do computador cliente.Se houver 5 usuários na rede e todos estiverem acessando a mesma informação, então cinco copias das mesmas tabelas estarão nos clientes. Uma das diferenças mais importantes entre o Access e o SQL Server é o modo como eles lidam com a concorrência. O SQL Server mantém uma única copia dos dados.Como muitos clientes precisam passar pelo SGBD, o SQL Server sabe quando um registro esta sendo editado e impede que outros usuários consigam excluir ou até mesmo ler o mesmo registro.O Access deve comparar as alterações efetuadas no cliente para o original e depois decidir se outros usuários podem ou não acessar uma linha.Se um usuário abre uma tabela e seleciona uma linha para editar, nenhum outro usuário pode editar a mesma linha..Dessa forma a linha permanecerá bloqueada indefinidamente.A medida que o numero de usuários aumenta, a sobrecarga torna-se insuportável e então é hora de trocar o bando para SQL Server. O Access 2000 pode ser usado para desenvolver aplicativos cliente/servidor, mas este recurso do Access é baseado na tecnologia do SQL Server.Através do componente MSDE que é um mecanismo de dados cliente/sevidor. O MSDE é totalmente compatível com o SQL Sever; ele se baseia-se no mesmo mecanismo de dados do SQL Server, porém é indicado para pequenos grupos de trabalho.Você pode usar o MSDE para desenvolver aplicativos e posteriormente se necessário migrar para SQL Server alterando somente as informações de conexão. Antes de prosseguirmos falaremos sobre a linguagem SQL mas no próximo artigo.

Programação de Banco de Dados - parte 3

Este é o terceiro artigo relacionado com programação de Banco de Dados, sairemos um pouco de teoria e vamos abordar mais a prática explicando a linguagem SQL. No segundo artigo o enfoque foi explicar a arquitetura cliente servidor com os modelos de 2 e 3 camadas.

SQL (Structured Query Language)

Quando os Bancos de Dados Relacionais estavam sendo desenvolvidos, foram criadas linguagens destinadas à sua manipulação. O departamento de Pesquisa da IBM desenvolveu a SQL como forma de interface para o sistema de BD relacional denominado SYSREM 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.

Page 5: Programação de Banco de Dados

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. Com exemplo de comandos da classe DML temos os comandos Select, Insert, Update e Delete.

Um 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 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 da linguagem SQL é a sua 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 garante por si mesmo a integridade das relações existentes entre as tabelas e seus índices.

» COMANDOS SQL

Comando Descrição

SELECT Recupera dados do Banco de Dados

INSERTUPDATEDELETE

Insere novas linhas, altera linhas existentes e remove linhas de tabelas do banco de dados, respectivamente. Estes comandos são conhecidos como comandos DML (Data Manipulation Language).

CREATEALTERDROPRENAMETRUNCATE

Cria, altera e remove objetos do banco de dados. São conhecidos como comandos DDL (Data Definition Language).

COMMITROLLBACKSAVEPOINT

Gerenciam as modificações realizadas pelos comandos DML. As modificações efetuadas pelos comandos DML podem ser agrupadas em transações lógicas.

GRANTREVOKE

Atribuem e removem direitos de acesso ao banco de dados e aos objetos a ele pertencentes. São conhecidos como comandos DCL (Data Control Language).

» DML ( Data Manipulation Languagem)

Veremos agora os comandos SQL DML destinados a manipulação dos dados.Comandos:

COMANDO SELECT

Page 6: Programação de Banco de Dados

Sintaxe: Select <campos da tabela> From <nome da tabela> Where <condição>

Exemplo 1: Selecionar linhas de uma tabela

SELECT NUMERO, NOME FROM EMPREGADOS;

Exemplo 2: Utilizando a cláusula DISTINCT para suprimir linhas duplicatas.

SELECT DISTINCT CARGO FROM EMPREGADOS;

Exemplo 3: Utilizando a cláusula DISTINCT com várias colunas.

SELECT DISTINCT CARGO, NUMERO_DEPT FROM EMPREGADOS;

Exemplo 4: Utilizando a cláusula * para listar todas as colunas da tabela.

SELECT * FROM EMPREGADOS

Exemplo 5: Utilizando operadores aritméticos (+, -,*, / ) na cláusula Select.

SELECT NOME, SALARIO * 12, DT_ADMISSAO FROM EMPREGADOS;

Exemplo 6: Utilizando Alias.

SELECT NOME, SALARIO * 12 AS SAL_ANUAL,DT_ADMISSAO FROM EMPREGADOS;OUSELECT NOME, SALARIO * 12 "SAL ANUAL", DT_ADMISSAO FROM EMPREGADOS;

Exemplo 7: Utilizando operador de concatenação.

SELECT NOME||' '||SOBRENOME FROM EMPREGADOS;

Como Ordenar e Limitar as Linhas Selecionadas

Exemplo 1: Ordenando as linhas selecionadas com a cláusula ORDER BY

SELECT NOME, SALARIO FROM EMPREGADOS ORDER BY SALARIO;OU SELECT NOME, SALARIO FROM EMPREGADOS ORDER BY SALARIO DESC;

Obs: Na ordenação ascendente, valores NULOS aparecem no final.

Exemplo 2: Ordenando pela posição da coluna selecionada

SELECT NOME, SALARIO * 12 FROM EMPREGADOS ORDER BY SALARIO * 12;OUSELECT NOME, SALARIO * 12 FROM EMPREGADOS ORDER BY 2;

Exemplo 3: Selecionando apenas os empregados lotados no departamento 20.

SELECT NOME, NUMERO_DEPT, SALARIO FROM EMPREGADOS WHERE NUMERO_DEPT = 20 ORDER BY SALARIO;

Exemplo 4: Selecionando apenas o empregado denominado SMITH.

SELECT NOME, NUMERO_DEPT, SALARIO FROM EMPREGADOS WHERE NOME = 'CELIO';

Exemplo 5: Selecionando com operadores lógicos.

Page 7: Programação de Banco de Dados

SELECT NOME, NUMERO_DEPT, SALARIO FROM EMPREGADOS WHERE SALARIO > 1000;

Observações:

1. Operadores para comparações lógicas:   =   >   >=   <=   <> 2. Outros comparadores:

BETWEEN ... AND ... ou NOT BETWEEN

IN (Lista) ou NOT IN

LIKE ou NOT LIKE

IS NULL ou IS NOT NULL

3. Operadores lógicos: ANDORNOT

Exemplo 6: Selecionando linhas com BETWEEN ... AND ...

SELECT NOME, DT_ADMISSAO FROM EMPREGADOSWHERE DT_ADMISSAO BETWEEN '28-SEP-90' AND '30-JAN-91';

Exemplo 7: Selecionando linhas com a cláusula IN.

SELECT NOME, NUMERO_DEPT, SALARIO FROM EMPREGADOSWHERE NUMERO_DEPT IN (10, 20) ORDER BY NUMERO_DEPT, SALARIO;

Exemplo 8: Selecionando linhas com a cláusula LIKE.

SELECT NOME, SALARIO FROM EMPREGADOS WHERE NOME LIKE 'S%'ORDER BY NOME;OUSELECT NOME, SALARIO FROM EMPREGADOS WHERE NOME NOT LIKE '%I%'ORDER BY NOME;OUSELECT NOME, SALARIO FROM EMPREGADOS WHERE NOME LIKE '_A%';

Observações:

- "%" representa nenhum ou muitos caracteres.- "_" representa um único caracter.

Exemplo 9: Selecionando linhas com a cláusula IS NULL.

A coluna Num_supervisor contém o número do empregado que supervisiona o empregado corrente.

SELECT NUMERO, NOME, CARGO, NUM_SUPERVISOR FROM EMPREGADOS;

Com esta Query recuperamos o único empregado da empresa que não é gerenciado por ninguém, isto é, o Presidente da empresa.

SELECT NOME, CARGO, NUM_SUPERVISOR FROM EMPREGADOS WHERE NUM_SUPERVISOR IS NULL;

Page 8: Programação de Banco de Dados

Observação: O resultado da cláusula Where abaixo é sempre falso pois um valor nulo não pode ser igual ou diferente de outro valor, mesmo que este outro valor seja nulo. Se valores nulos forem comparados por operadores que não o "IS NULL" o resultado será sempre falso.

SELECT NOME, CARGO, NUM_SUPERVISOR FROM EMPREGADOS WHERE NUM_SUPERVISOR = NULL;

Exemplo 10: Selecionando linhas com operadores lógicos.

SELECT NOME, SALARIO, NUMERO_DEPT FROM EMPREGADOS WHERE SALARIO >= 3000 AND (NUMERO_DEPT = 10 OR NUMERO_DEPT = 30);

Funções Aplicadas a Linhas

Há dois tipos de funções:

- Funções de linhas- Funções de grupos

Um função de linha retorna um resultado por linha da tabela acessada. Já uma função de grupo retorna um resultado por grupo de registros.

Exemplos de Funções de Linha:

- LOWER ('UFF') » uff- UPPER ('uff') » UFF- INITCAP ('UNIVERSIDADE FEDERAL') » Universidade Federal- CONCAT ('String1', 'String2') » String1String2- SUBSTR ('String', 1, 3) » Str- LENGTH ('UFF') » 3- NVL (SAL, 0) » Se SAL for NULO seu valor será convertido para zero. - ROUND (78.731, 2) » 78.73 (Até 4 p/ baixo, Acima de 4 p/ cima)- ROUND (78.731, 0) » 79- TRUNC (78.731, 2) » 78.73- TRUNC (78.731) » 78 - MOD (100, 30) » 10

Exemplo 1: Utilização da função UPPER em uma sentença SQL.

SELECT NOME, SALARIO, NUMERO_DEPT FROM EMPREGADOS WHERE UPPER (NOME) = 'CELIO';

Exemplo 2: Utilização das funções SUBSTR e LENGTH em uma sentença SQL.

SELECT NOME, LENGTH (NOME) FROM EMPREGADOS WHERE SUBSTR (NOME, 1, 3) = 'CEL';

Como selecionar dados de mais de uma tabela

Para se exibir dados de mais de uma tabela, através de um comando SQL, é preciso definir condições de junção. (Joins)

Os joins geralmente ocorrem entre valores de chave primária e de chave estrangeira. Tipos de Joins:

Equijoin Non-equijoin Outer join Self Join Set operators

Um produto cartesiano geralmente ocorre quando a condição de junção é omitida ou inválida. Para evitar produtos cartesianos é preciso incluir, na cláusula Where, condições de junção válidas.

Page 9: Programação de Banco de Dados

Exemplo 1:Uma junção simples entre a Tabela de Empregados (Emp) e a tabela de Departamentos (Dept). SELECT EMPREGADOS.NOME, NUMERO_DEPT, DEPARTAMENTOS.NOME FROM EMPREGADOS, DEPARTAMENTOS WHERE EMPREGADOS.NUMERO_DEPT = DEPARTAMENTOS.NUMERO;

Obs: Haverá um ganho de desempenho e de clareza se você sempre qualificar as colunas com o nome das tabelas às quais elas pertencem. Exemplo 2: Uma junção simples entre a Tabela de Empregados e a tabela de Departamentos considerando apenas aqueles empregados que ganham mais de 2500,00. SELECT EMPREGADOS.NOME, EMPREGADOS.NUMERO_DEPT, DEPARTAMENTOS.NOME FROM EMPREGADOS, DEPARTAMENTOS WHERE EMPREGADOS.NUMERO_DEPT = DEPARTAMENTOS.NUMERO AND EMPREGADOS.SALARIO > 2500; OUSELECT E.NOME, E.NUMERO_DEPT, D.NOME FROM EMPREGADOS E, DEPARTAMENTOS D WHERE E.NUMERO_DEPT = D.NUMERO AND E.SALARIO > 2500;

Exemplo 3: Uma junção entre a tabela de Empregados, a tabela de Departamentos e a tabela de Dependentes. SELECT E.NOME, E.NUMERO_DEPT, DPT.NOME, DEP.NOME FROM EMPREGADOS E, DEPARTAMENTOS DPT, DEPENDENTES DEP WHERE E.NUMERO_DEPT = DPT.NUMERO AND E.NUMERO = DEP.NUMERO_EMP;

Funções de Grupo

Funções de grupo operam com um conjunto de linhas para dar um resultado por grupo de linhas. Um conjunto de linhas pode ser uma tabela inteira ou linhas desta tabela divididas em grupos.

Funções de grupo podem aparecer tanto na cláusula Select quanto na cláusula Having.

A cláusula Group By divide as linhas de uma ou mais tabelas em grupos de linhas.

A cláusula Having seleciona os grupos que serão aceitos.

Funções de Grupo Existentes:

AVG COUNT MAX MIN STDDEV SUM VARIANCE

Observações: A cláusula Distinct pode ser utilizada para que sejam considerados apenas valores não duplicatas. Todas as funções de grupo ignoram valores nulos. Para substituir um valor nulo por outro valor utilize a função NVL.

Exemplo 1: Utilização de funções de grupo, considerando todas as linhas de uma tabela um único grupo. SELECT AVG(SALARIO), MAX(SALARIO), MIN(SALARIO), SUM(SALARIO) FROM EMPREGADOS;OUSELECT MIN(NOME), MAX(NOME) FROM EMPREGADOS;

Exemplo 2: Um único grupo definido através da cláusula Where. SELECT AVG(SALARIO), MAX(SALARIO), MIN(SALARIO), SUM(SALARIO) FROM EMPREGADOS WHERE CARGO LIKE 'VEND%';

Exemplo 3: Utilização da função COUNT para contar o número de empregados lotados no departamento número 10. SELECT COUNT(*) FROM EMPREGADOS WHERE NUMERO_DEPT = 10;

Exemplo 4: Utilização da função COUNT para contar o número de empregados que possuem percentual de comissão diferente de nulo.

Page 10: Programação de Banco de Dados

SELECT COUNT(PERC_COMISSAO) FROM EMPREGADOS;

Exemplo 5: Utilização da função COUNT para contar o número de empregados na tabela. SELECT COUNT(NVL(PERC_COMISSAO, 0)) FROM EMPREGADOS;

Observações: COUNT(*) conta o número de linhas na tabela.COUNT(PERC_COMISSAO) conta o número de linhas com percentual de comissão diferente de nulo.COUNT(NUMERO) conta o número de linhas na tabela uma vez que a coluna NUMERO é a chave primária da tabela e toda chave primária não pode conter valores nulos.

A cláusula Group By Exemplo 6: Utilização da cláusula GROUP BY e da função COUNT para se contar quantos empregados estão lotados em cada departamento. SELECT NUMERO_DEPT, COUNT(*) FROM EMPREGADOS GROUP BY NUMERO_DEPT;

Observações: Qualquer coluna incluída na cláusula SELECT, se não estiver em uma função de grupo, deverá constar da cláusula GROUP BY. Com a cláusula WHERE é possível excluir determinadas linhas dos grupos. Por default as linhas são ordenadas ascendentemente conforme a lista de colunas especificada na cláusula GROUP BY. Para modificar este comportamento é preciso utilizar a cláusula ORDER BY.

Exemplo 7: Utilização da cláusula Group By, da função COUNT e de um JOIN para se contar quantos empregados estão lotados em cada departamento. SELECT D.NOME "DEPARTAMENTO", COUNT(*) "QTD" FROM EMPREGADOS E, DEPARTAMENTOS DWHERE E.NUMERO_DEPT = D.NUMERO GROUP BY D.NOME;

Exemplo 8: A query abaixo está correta? A intenção é listar o número dos departamentos seguido da média salarial. No entanto, deseja-se listar apenas aqueles departamentos cuja média salarial é superior a 2000. SELECT NUMERO_DEPT, AVG(SALARIO) FROM EMPREGADOS WHERE AVG(SALARIO) > 2000 GROUP BY NUMERO_DEPT;

A cláusula Having Para se restringir a inclusão de grupos não se pode utilizar a cláusula WHERE. A cláusula WHERE deve ser utilizada para se restringir a inclusão de linhas em um grupo. Para se omitir a inclusão de grupos inteiros do resultado de uma query deve-se utilizar a cláusula HAVING.

Exemplo 9: A utilização da cláusula HAVING para listar o número dos departamentos seguido da média salarial de seus empregados. No entanto, deseja-se listar apenas aqueles departamentos cuja média salarial é superior a 2000. SELECT NUMERO_DEPT, AVG(SALARIO) FROM EMPREGADOS GROUP BY NUMERO_DEPT HAVING AVG(SALARIO) > 2000;

Exemplo 10: A utilização da cláusula GROUP BY para listar a quantidade de empregados por departamento/cargo. Isto é, grupos dentro de grupos. Não deve ser exibido Número de Departamento NULO. SELECT NUMERO_DEPT, CARGO, COUNT(*) FROM EMPREGADOS GROUP BY NUMERO_DEPT, CARGO HAVING NUMERO_DEPT IS NOT NULL;

As cláusulas do comando Select são avaliadas na seguinte ordem:

Se o comando SQL contém a cláusula WHERE, o SGBD seleciona as linhas candidatas.O SGBD identifica os grupos especificados pela cláusula GROUP BY.A cláusula HAVING restringe os grupos resultantes que não estão de acordo com os critérios especificados nesta cláusula.

A recuperação de dados com subconsultas (Subqueries)

Uma subconsulta é um comando SELECT embutido em uma cláusula de outro comando SQL.

Page 11: Programação de Banco de Dados

Quando e como utilizar:

Escreva subconsultas para recuperar dados baseados em critérios desconhecidos.Pode ser muito útil quando se necessita selecionar linhas de uma tabela com uma condição que depende dos dados que estão na própria ou em outra tabela.Subconsultas não podem conter a cláusula ORDER BY.Duas classes de operadores de comparações são utilizadas em subconsultas:Operadores de uma única linha: >, =, >=, <, <=, <>Operadores de multiplas linhas: IN e NOT IN.Como uma subconsulta é processada?Primeiramente é executado o comando SELECT aninhado.Em seguida o resultado é utilizado em uma condição da consulta principal.

Exemplo 1: A utilização de uma subconsulta aninhada para recuperar o nome e salário de todos os empregados que trabalham no mesmo departamento que o JOSE trabalha.

SELECT NOME, SALARIO FROM EMPREGADOS WHERE NUMERO_DEPT = (SELECT NUMERO_DEPTFROM EMPREGADOS WHERE NOME = 'JOSE');

Exemplo 2: A utilização de uma subconsulta aninhada para recuperar o nome e salário de todos os empregados que ganham mais do que a média salarial da empresa.

SELECT NOME, SALARIO FROM EMPREGADOS WHERE SALARIO > (SELECT AVG(SALARIO) FROM EMPREGADOS);

Exemplo 3: A utilização de uma subconsulta aninhada para recuperar o nome, número do departamento e salário de todos os empregados que trabalham no departamento situado no RIO ou no departamento denominado VENDAS.

SELECT NOME, NUMERO_DEPT, SALARIO FROM EMPREGADOS WHERE NUMERO_DEPT = (SELECT NUMERO FROM DEPARTAMENTOS WHERE LOCAL = 'RIO' OR NOME = 'VENDAS');

Exemplo 4: A utilização de uma subconsulta aninhada para recuperar o nome, número do departamento e salário de todos os empregados que trabalham no departamento situado no RIO ou no departamento denominado VENDAS.

Correção da query anterior com a utilização da cláusula IN uma vez que esta subconsulta retorna mais de uma linha.

SELECT NOME, NUMERO_DEPT, SALARIO FROM EMPREGADOS WHERE NUMERO_DEPT IN (SELECT NUMERO FROM DEPARTAMENTOS WHERE LOCAL = 'RIO' OR NOME = 'VENDAS');

Exemplo 5: A utilização de uma subconsulta aninhada para recuperar o número do departamento e sua média salarial. Devem ser recuperados apenas os departamentos cuja média salarial é maior do que a média salarial do departamento número 30.

SELECT NUMERO_DEPT, AVG(SALARIO) FROM EMPREGADOS GROUP BY NUMERO_DEPT HAVING AVG(SALARIO) >= (SELECT AVG(SALARIO) FROM EMPREGADOS WHERE NUMERO_DEPT = 30);

A recuperação de dados com subconsultas correlacionadas

No exemplo abaixo a subconsulta é executada uma vez para cada linha da tabela de empregados na consulta mais externa.

Exemplo 1: A utilização de uma subconsulta correlacionada para recuperar o nome dos empregados que trabalham no projeto numero 2.

SELECT NOME FROM EMPREGADOS WHERE 2 IN ( SELECT NUMERO_PROJ FROM TRABALHAM WHERE NUMERO_EMP = E.NUMERO);

Page 12: Programação de Banco de Dados

Exemplo 2: A mesma query acima sem a utilização de subconsulta correlacionada.

SELECT NOME FROM EMPREGADOS E, TRABALHAM T WHERE E.NUMERO = T.NUMERO_EMP AND T.NUMERO_PROJ = 2;

Quantificador Existencial

Exists representa o quantificador existencial, uma noção emprestada da lógica formal. Em SQL, um predicado existencialmente quantificado é representado pela expressão da forma EXISTS (SELECT * FROM ... ).

Essa expressão será verdadeira se o resultado do cálculo da subconsulta representado por "SELECT * FROM ..." não estiver vazio, isto é, se existir pelo menos um registro na tabela FROM da subconsulta que satisfaz a condição WHERE dessa mesma subconsulta.

Qualquer consulta que utilize IN pode alternativamente ser formulada com EXISTS, porém o inverso não é verdadeiro.

Exemplo 1: Obter o nome dos empregados que trabalham no projeto nº 2.

SELECT NOME FROM EMPREGADOS E WHERE EXISTS (SELECT * FROM TRABALHAM WHERE NUMERO_EMP = E.NUMERO AND NUMERO_PROJ = 2);

OU

SELECT NOME FROM EMPREGADOS E, TRABALHAM T WHERE E.NUMERO = T.NUMERO_EMP AND T.NUMERO_PROJ = 2;

Exemplo 2: Obter o nome dos empregados que não trabalham no projeto nº 2.

SELECT NOME FROM EMPREGADOS E WHERE NOT EXISTS (SELECT * FROM TRABALHAM WHERE NUMERO_EMP = E.NUMERO AND NUMERO_PROJ = 2);

OU

SELECT NOME FROM EMPREGADOS MINUS SELECT NOME FROM EMPREGADOS E, TRABALHAM T WHERE T.NUMERO_EMP = E.NUMERO AND T.NUMERO_PROJ = 2;

União (Union e Union All)

Linhas duplicatas são eliminadas do resultado de uma união a não ser que o operador UNION inclua explicitamente o quantificador ALL. Assim, no exemplo nº 1, o projeto nº 3 é selecionado em ambos os SELECTS, mas só aparece uma vez no resultado final.

Já o exemplo nº 2 retornará os números de projeto 2, 3 e 3.

Qualquer número de SELECTS pode ser unido pelo UNION.

Quando sabemos que não haverá elementos duplicados no resultado é conveniente utilizarmos UNION ALL para que o sistema não seja forçado a eliminar duplicidades, desnecessariamente.

Exemplo 1: Obter o número dos projetos que, ou se iniciaram após 31-JUL-97, ou possuem o empregado 7566 nele trabalhando. União sem repetição.

SELECT NUMERO FROM PROJETOS WHERE DT_INICIO > '31-JUL-97' UNION SELECT NUMERO_PROJ FROM TRABALHAM WHERE NUMERO_EMP = 7566;

Exemplo 2: Obter o número dos projetos que, ou se iniciaram após 31-JUL-97, ou possuem o empregado 7566 nele trabalhando. União com repetição.

Page 13: Programação de Banco de Dados

SELECT NUMERO FROM PROJETOS WHERE DT_INICIO > '31-JUL-97' UNION ALL SELECT NUMERO_PROJ FROM TRABALHAM WHERE NUMERO_EMP = 7566;

Exemplo 3: A possibilidade de incluirmos constantes numa cláusula SELECT é freqüentemente útil quando a cláusula UNION é utilizada. Por exemplo, para indicar qual das duas condições WHERE foi atendida para a inclusão do elemento no resultado final.

SELECT NUMERO, 'DT_INICIO > 07-JAN-90' CONDIÇÃO FROM PROJETOS WHERE DT_INICIO > '07-JAN-90' UNION ALL SELECT NUMERO_PROJ, 'NUMERO_EMP = 7566' FROM TRABALHAM WHERE NUMERO_EMP = 7566;

Resultado:

NUMERO CONDIÇÃO------------ --------------------- 2 DT_INICIO > 07-JAN-90 3 DT_INICIO > 07-JAN-90 4 DT_INICIO > 07-JAN-90 3 NUMERO_EMP = 7566No próximo artigo vamos continuar a falar sobre os comandos SQL DML (Insert, Delete e Update).

Programação de Banco de Dados - parte 4

Este é o quarto artigo relacionado com programação de Banco de Dados, neste artigo vamos continuar abordar os comandos SQL. No terceiro falamos mais do comando SELECT agora vamos falar sobre os demais comandos fechando o assunto SQL.

Achei que no terceiro artigo ficou faltando falar melhor na recuperação de dados de várias tabelas (JOINS) vamos então fechar o SELECT com esse assunto.

JOINS

A cláusula WHERE permite que você conecte duas ou mais tabelas, com base nos valores de duas colunas nas duas tabelas.A cláusula WHERE, no entanto, deve ser usada para expressar restrições envolvendo uma ou mais tabelas, e não para conectar tabelas, embora seja comum fazermos isso. O método apropriado para vincular tabelas é a operação JOIN.

Vou citar 2 exemplos onde ocorre problemas ao usar a clausula WHERE em junções:

Exemplo 1: Consideremos duas Tabelas uma Tabela FUNCIONARIOS (idfuncionario,nome) e outra DEPENDENTES (idfuncionario,nome,grauparentesco). Onde o idfuncionario na tabela FUNCIONARIOS é a chave primária e na tabela DEPENDENTES é a chame estrangeira, a chave primária da tabela DEPENDENTES seria a concatenação de idfuncinario + nome. Sendo que a tabela DEPENDESTES é tabela fraca de FUNCIONARIOS ( isso quer dizer que só existe um registro em Dependentes a partir da tabela funcionário, isso também ocorre quando na chave primaria da tabela participa a chave primária de outra tabela), bem voltando ao caso, suponha que queremos retornar todos os funcionários e caso o funcionário tenha dependente retornamos também. A consulta com WHERE ficaria assim

SELECT F.Idfuncionario , F.nome,D.Nome From FUNCIONARIOS as F, DEPENDENTES as D Where F.Idfuncionario= D.Idfuncionario

Bem nesta consulta somente iria retornar os funcionários que possuem dependentes, os que não tivessem dependentes ficaria de fora.

Exemplo 2: Consideremos ainda a tabela FUNCIONARIO e outra tabela TELFUNCIONARIO(idfuncionario,numero), muito comum , pois o campo telefone é multivalorado ( permite vários telefones) por isso foi criado uma tabela somente para os telefones. Bem neste caso temos o mesmo problema os funcionários sem telefone não iriam ser retornados usando a clausula WHERE.

Page 14: Programação de Banco de Dados

A operação JOIN combina colunas de duas tabelas se as linhas possuírem campos de correspondência. Sua sintaxe é:

FROM tabela1 INNER JOIN tabela2 ON tabela1.col = tabela2.colAs duas colunas não precisam ser correspondidas com o operador igual, embora este seja o método mais comum de correspondência de várias tabelas.Você pode usar qualquer um dos operadores relacionais ( >,>=,<,<= e <>). Além disso você pode combinar várias retrições com operadores lógicos.Por exemplo: FROM tabela1 INNER JOIN tabela2 ON tabela1.col1 = tabela2.col1 AND tabela1.col2 <> tabela2.col2

TIPOS DE JUNÇÕES O SQL suporta dois tipos de junções: INNER JOIN esta junção retorna todos os pares com correspondentes de linhas nas duas tabelas e descartam as linhas sem correspondentes de ambas as tabelas. OUTER JOIN esta junção retorna todas as linhas normalmente retornadas pela operação INNER JOIN, mas as linhas da tabela esquerda ou da direita que não atendam à condição. CROSS JOIN incluímos cada uma das combinações de todas as linhas entre as tabelas. Na sintaxe MS-SQL Server, são comparadas as tabelas por uma coluna específica para cada tabela (chave estrangeira), linha por linha, e são listadas as linhas em que a comparação é verdadeira.

INNER JOIN Considere as tabelas: CLIENTE: Cod_cliente, Nome,EndereçoPEDIDO: Num_Pedido,Prazo_Entrega Cod_Cliente, Cod_Vendedor,DataITEMPEDIDO: num_pedido,Cod_produto,QuantidadePRODUTO: Cód_produto,Descrição,Unidade,ValUnidade.VENDEDOR: Cód_Vendedor,Nome, Comissão,Salario

Problema: ver os pedidos de cada cliente:

SELECT Cliente.nome,Pedido.cod_cliente,pedido.num_pedidoFROM Cliente INNER JOIN Pedido ON Cliente.Cod_cliente = Pedido.Cod_cliente

Problema: Mostre os clienter (ordenados) que têm prazo de entrega maior que 15 dias para o produto "ARROZ" e sejam do Rio de Janeiro.

SELECT Cliente.NomeFROM Cliente INNER JOIN PedidoON Cliente.Cod_cliente=Pedido.Cod_ClienteINNER JOIN ItemPedidoON pedido.num_pedido = itempedido.num_pedidoINNER JOIN ProdutoON itempedido.Cód_produto= Produto.Cod_ProdutoWHERE Pedido.Prazo_Entrega > 15 ANDProduto.Descrição='ARROZ' ANDCliente.UF = 'RJ'ORDER BY Cliente.Nome

Problema: Mostre todos os vendedores que venderam chocolate em quantidade superior a 5 Kg.

SELECT DISTINCT Vendedor.NomeFROM Vendedor INNER JOIN PedidoON Vendedor.Cod_Vendedor=Pedido.Cod_VendedorINNER JOIN ItemPedidoON pedido.num_pedido = itempedido.num_pedidoINNER JOIN ProdutoON itempedido.Cód_produto= Produto.Cod_ProdutoWHERE Quantidade > 5 ANDProduto.Descrição='CHOCOLATE'ORDER BY Vendedor.Nome

Problema: Quantos clientes da cidade do Rio de Janeiro e de Niterói tiveram seus pedidos tirados pelo vendedor 'PAULO' fez no mês de janeiro.

Page 15: Programação de Banco de Dados

SELECT cidade,COUNT (nome_cliente), FROM Cliente INNER JOIN PedidoON Cliente.Cod_Cliente=Pedido.Cod_ClienteINNER JOIN VendedorON pedido.Cód_Vendedor = vendedor.Cód_VendedorWHERE Cidade In('Rio de Janeiro','Niteroi') ANDData BETWEEN #01/01/2004# AND #31/01/2004#GROUP BY Cidade

OUTER JOIN

É a seleção em que são restritas as linhas que interessam em uma tabela, mas são consideradas todas as linhas de outra tabela.

Ou seja, queremos ver quais linhas de uma tabela estão relacionadas com a outra tabela e quais as linhas não estão.

Poderíamos dizer, que queremos ver quais clientes tem pedidos e quais clientes não tem pedidos.

Um OUTER JOIN somente pode ser realizado entre duas tabelas, não mais que duas tabelas.

O Outer Join possui 3 tipos:

LEFT OUTER JOIN - são incluidas todas as linhas da primeira tabela na expressão.

RIGHT JOIN - são incluídas todas as linhas da segunda tabela na expressão.

FULL OUTER JOIN - são incluidas todas as linhas de ambas as tabelas, as que satisfazem a expressão e as que não satisfazem.

INSERT, UPDATE E DELETE

Adicionado Registro na Tabela - INSERT

Sintaxe: INSERT INTO nome Tabela (nome das colunas ) VALUES ( valores )

Exemplo:

INSERT INTO Clientes (nome,endereco) VALUES ('LUCIANA', 'AV ATLANTICA').Podemos omitir a lista dos nomes das colunas, neste caso a lista de valores deve estar na mesma ordem que na tabela no banco, e a tabela não pode ter nenhum campo AutoNumeric, pois não pode ser omitido nenhum valor. Outro mecanismo para passar valores de colunas para a instrução INSERT é seleciona-las de outra tabela. Exemplo: INSERT INTO PhoneBook Select ContactName,Phone,Fax From Customers.Esse tipo de inserção permite a inclusão de várias linhas de uma só vez.

Alterando Registros - UPDATE Sintaxe: UPDATE nome_tabela SET coluna1=valor1, coluna2=valor2... Where condição Problema: Alterar o valor unitário do produto 'parafuso' UPDATE ProdutoSet val_unit = 2.00Where Descrição= 'parafuso'Problema: atualizar o salario fixo de todos os vendedores em 30% mais bonificação de 100 UPDATE VendedorSet Salário = (Salário * 1.30) + 100Neste comando não foi usado a clausula WHERE neste caso todos os registros da tabela Vendedor foram atualizados. Problema: Acrescentar 2,5% ao preço dos produtos que estejam abaixo da média dos preços.

Page 16: Programação de Banco de Dados

UPDATE ProdutoSet Val_Unit = Val_Unit * 1.25Where Val_Unit < (Select AVG(Val_unit) From Produto)

Apagando Registros - DELETE Sintaxe: DELETE From nome_tabela Where condição. Exemplo: DELETE FROM Cliente Where IdCliente = 1. Se omitir a clausula WHERE todos os registros da tabela são deletados. OBS: Tanto no comando UPDATE como no DELETE na clausula WHERE pode-se usar SELECT com todos as suas possibilidades. Terminamos aqui de falar sobre os comandos DML, passaremos agora a abordar os comandos DDL mais precisamente o comando CREATE TABLE.

CRIAÇÃO DE TABELAS - CREATE TABLE Estruturas de dados que podem ser criadas com um SGBD.

Estruturas de Dados Descrição

Tabela Armazena dados.

Visão Representa logicamente subconjuntos de dados de uma ou mais tabelas.

Seqüência Gera valores de chaves primárias.

Índice Melhora o desempenho de algumas consultas.

Tabelas Uma tabela pode ser criada a qualquer momento. Não é necessário especificar seu tamanho, no momento da sua criação, embora seja possível. A estrutura de uma tabela pode ser modificada a qualquer momento, sem a necessidade de se tirar

o banco do ar. Quando uma tabela é criada sua definição é armazenada no dicionário de dados. Para se poder criar tabelas é preciso ter o privilégio de CREATE TABLE e o direito de utilizar algum

espaço em disco, alocado para o banco de dados.

Quem concede estes direitos para os usuários do banco é o Administrador de Banco de Dados. (DBA)

Comando Create Table

Exemplo:

CREATE TABLE FORNECEDORES(NUMERO NUMBER(2) PRIMARY KEY,NOME VARCHAR2(25) NOT NULL,TELEFONE CHAR(7),ENDERECO VARCHAR2(20),VALOR_FORNEC NUMBER (8,2));

Observações: - O nome de uma tabela deve começar por uma letra.- Pode ter até 30 caracteres.- Deve conter apenas: A-Z, a-z, 0-9, _, $ e #.- Não pode ter o mesmo nome de qualquer outro objeto existente no esquema do usuário.

Tipos de Dados - NUMBER- NUMBER(p,s)- DATE- CHAR(s)- VARCHAR2(s)- LONG

Page 17: Programação de Banco de Dados

Tipos de Constraints - PRIMARY KEY- FOREIGN KEY- NOT NULL- UNIQUE- CHECK Observações:

- É possível criar uma constraint após a criação da tabela.- Uma constraint pode ser definida a nível de coluna ou a nível de tabela.- Constraints são armazenadas no Dicionário de Dados e podem ser facilmente recuperadas se

possuírem nomes razoáveis. Como dar Nome às Constraints

Exemplo 1: Constraints Primary Key e Not Null. CREATE TABLE FORNECEDORES(NUMERO NUMBER(2)

CONSTRAINT FORNECEDORES_NUMERO_PK PRIMARY KEY,NOME VARCHAR2(25)

CONSTRAINT FORNECEDORES_NOME_NN NOT NULL,TELEFONE CHAR(7)

CONSTRAINT FORNECEDORES_TELEFONE_NN NOT NULL,ENDERECO VARCHAR2(20),VALOR_FORNEC NUMBER (8,2));

Exemplo 2: Constraints Primary Key e Not Null. CREATE TABLE DEPARTAMENTOS(NUMERO NUMBER(2)

CONSTRAINT DEPARTAMENTOS_NUMBER_PK PRIMARY KEY,NOME VARCHAR2(14)

CONSTRAINT DEPARTAMENTOS_NOME_NN NOT NULL,LOCAL VARCHAR2(13));Exemplo 3: Constraint Check e Integridade Referecial com a própria tabela de Empregados e com a tabela de Departamentos. CREATE TABLE EMPREGADOS

(NUMERO NUMBER(4) CONSTRAINT EMPREGADOS_NUMBER_PK PRIMARY KEY,

NOME VARCHAR2(10),SOBRENOME VARCHAR2(10),CPF CHAR(11) CONSTRAINT EMPREGADOS_CPF_UN UNIQUE,

CARGO VARCHAR2(9), NUM_SUPERVISOR NUMBER(4) CONSTRAINT EMP_EMP_NUM_SUPERVISOR_FK REFERENCES EMPREGADOS (NUMERO), DT_ADMISSAO DATE, SALARIO NUMBER(7,2), PERC_COMISSAO NUMBER(4,2)

CONSTRAINT EMPREGADOS_PERC_COMISSAO_CK CHECK (PERC_COMISSAO IN (10, 12.5, 15, 17.5, 20)),

NUMERO_DEPT NUMBER(2) CONSTRAINT EMPR_DEPARTAMENTOS_NUMERO_DEPT_FK REFERENCES DEPARTAMENTOS (NUMERO)

ON DELETE CASCADE);

Exemplo 4: CREATE TABLE DEPENDENTES

(NUMERO_EMP NUMBER(4) CONSTRAINT DEPENDENTES_EMP_NUMERO_EMP_FK REFERENCES EMPREGADOS (NUMERO),NUM_ORDEM NUMBER(2),NOME VARCHAR2(10),

CONSTRAINT DEPENDENTES_NUM_EMP_NUM_ORD_PK PRIMARY KEY(NUMERO_EMP, NUM_ORDEM));

Page 18: Programação de Banco de Dados

Observações sobre a Constraint Primary Key: - A constraint Primary Key é uma combinação das constraints Unique e Not Null.- Um índice único é automaticamente criado.

Observações sobre a Constraint Unique: - Designa uma coluna ou uma combinação de colunas de tal forma que duas linhas não possam ter o

mesmo valor.- Valores nulos são aceitos.- Automaticamente é criado um índice único para a(s) coluna(s) especificada(s).

Observações sobre a Constraint Foreign Key: - Estabelece um relacionamento com a chave primária ou única da mesma ou de outra tabela.- Deve referenciar um valor existente na tabela pai ou ser nulo.- Chaves estrangeiras são baseadas em dados e são puramente lógicas, isto é, não são ponteiros

físicos.- Uma chave estrangeira, parte de uma chave primária, não pode ser nula pois uma chave primária

não pode ser nula, nem parcialmente nula.- Havendo a cláusula ON DELETE CASCADE, uma deleção na tabela pai causa a deleção das linhas

relacionadas na tabela filho.

Outras Formas de se Validar uma Restrição de Integridade - Triggers- Procedimentos ou funções armazenados no servidor de banco de dados- Através do código na própria aplicação.

Como Criar uma Tabela Através de uma Subconsulta CREATE TABLE EMPREGADOS_VENDAS AS SELECT * FROM EMPREGADOS WHERE CARGO = 'VENDEDOR';Observação: - A tabela Empregados_Vendas é criada contendo todos os empregados no cargo de vendedores.- Apenas a constraint NOT NULL é copiada. Bem o assunto SQL não termina aqui, não abordamos os comando DCL responsável pelo acesso e permissão de usuários.Também não falamos sobre Trigers, Procedures, Function e View. Devido a pedidos para falarmos logo do componente ADO nos próximos artigos vamos "cair" em cima da prática com acesso a banco de dados pelo ADO, com exemplos de códigos realizando: consultas, inserções, deleções, alterações, transações, carregamento de listas, controle de concorrência, backup e etc, enfim tudo com exemplos e feito via código, não usarei componentes para acesso como o Data Control, que considero muito ruim e limitado.Até a próxima.

Programação de Banco de Dados - parte 5

Este é o quinto artigo e vamos abordar o componente ADO. Não falaremos de tudo que a biblioteca ADO oferece, mas com o que vai exposto será possível desenvolver aplicações completas que interagem com banco.

ADO

Agora chegou o momento de entrar realmente na programação de banco de dados. Neste artigo exploraremos o componente ADO ( Active Dta Objects - Objeto de Dados Ativos).

O ADO é um componente para acesso a bancos de dados.Ele expõe alguns objetos muito flexíveis que expõem suas próprias propriedades, métodos e eventos.

Para usar objetos ADO em um aplicativo, você deve primeiro adicionar uma referencia ao componente ADO.Inicie um projeto Standard EXE e depois selecione Project->References.Na janela References, localizeMicrosoft ActiveX Data Objects 2.x library e marque a sua caixa de seleção.

Page 19: Programação de Banco de Dados

A utilização do ADO basicamente consiste em declarar 2 variáveis.Uma responsável unicamente pela conexão, e a outra pelas consultas do banco e para isso usamos duas sub-classes da classe ADO que são "Connection" e "Recordset" respectivamente.

Existem diversas formas de se trabalhar com o ADO, já vi vários códigos usando ADO e de forma diferente.Vou mostrar nesse artigo a forma mais simples considerada por mim de usar o ADO.

Bem na programação com Banco de Dados consistem basicamente em:

Abrir Conexão com Banco. Executar consultas, Inserções, Alterações e Deleções. Fechar Conexão com Banco.

Neste caso vamos ver cada passo desse processo.Neste artigo não vamos abordar a execução de trigger ou de procedimentos armazenados que tem parâmetros para serem executados.

Declaração das Variáveis do ADO Neste caso basta declarar uma única variável de conexão e uma única variável de consulta (Recordset). Declare as variáveis do banco em um Modulo da seguinte forma:Public pVarConBanco as New ADODB.Connection (Variável de conexão)Public pVarRegBanco as New ADODB.Recordset (Variável de Consulta) Além de efetuar a conexão a variável do tipo ADODB.Connection (abordada a partir de agora somente por Connection) também executa comandos SQL com exceção do comando SELECT, pois essa variável não é do tipo Collection, não tem propriedades para tratamento de dados.No entanto não vamos usar a variável Connection para execução de comandos SQL, a variável connection somente será usada para a conexão com o banco.

Conexão com o Banco (CONNECTION) Pela propriedade "ConnectonString do objeto connection informa a string de conexão que difere de banco para banco. Neste caso um projeto bem planejado a migração de um banco para um mais potente é extremamente fácil, bastando mudar um linha de código que é a string de conexão. String de Conexão para Access

pVarConBanco.ConnectionString = _"provider = microsoft.jet.oledb.4.0;" & _"data source=" + PathBanco + NomeBanco + ";jet oledb:database password=" + SenhaBanco

É usado o Jet 4.0 que da suporte para o Access 2000 e para os demais. (Não sei se da suporte para o Access XP)

As variáveis são o seguinte: PathBanco = ao caminho do banco de dados.NomeBanco= ao nome da banse de dados.SenhaBanco= senha do banco de dados.

OBS: Caso o banco não seja protegido por senha basta colocar: pVarConBanco.ConnectionString = _"provider = microsoft.jet.oledb.4.0;" & _"data source=" + PathBanco + NomeBanco

Após informa a string de conexão basta chamar o evento OPEN que estabelece a conexão com o banco. pVarConBanco.Open

Não é possível abrir duas conexões ao mesmo tempo usando a mesma variável de connection. Para fechar a conexão com o banco: pVarConBanco.Close

Neste caso o evento Close apenas fecha a conexão com o banco, no entanto a variável continua na memória.Neste caso você pode usar Set pVarConBanco= Nothing para liberar da memória a variável.Não aconselho a fechar o banco somente usando Set Nothing. Falaremos somente isso sobre a classe Connection, sendo que essa classe possui diversos outros comandos e especificações de conexão principalmente para banco cliente servidor no entanto para um

Page 20: Programação de Banco de Dados

primeira visão isso é o suficiente para criação de aplicações que usem o Banco Access , que vai ser o banco usado nesses artigos.

Uma função de conexão com banco de dados pode ser implementada dessa forma: Public Function (ByVal NomeBanco As String,ByVal Endereco_Banco As String,ByVal Senha_Banco As String) As Boolean'Rotina generica que conecta e abre o banco em ADOOn Error GoTo T_Erro Conexao_Banco = False pVarConBanco.ConnectionString = _ "provider = microsoft.jet.oledb.4.0;" & _ "data source=" + Endereco_Banco + NomeBanco + ";jet oledb:database password=" + Senha_Banco pVarConBanco.Open Conexao_Banco = True Exit FunctionT_Erro: MSG_ERRO "Conexao_Banco" EndEnd Function

Onde recebe o nome, caminho e senha do banco retornando verdadeiro caso a conexão seja sucedida.Dessa forma você pode criar um modulo único com as declarações das variáveis Connection e Recordset e com a função de conexão e usar em todos os seus projetos. Na chamada da função caso retorne False você pode abortar a execução do programa com Unload ou END. No tratamento de erro fiz um procedimento chamado MSG_ERRO que uso em todos os tratamento de erros de minhas aplicações, onde tem como parâmetro o nome do procedimento.

Public Sub MSG_ERRO(Procedimento As String)MsgBox "O seguinte erro aconteceu : " + Str(Err) + Chr(10) + Error(Err) + Chr(10) + "Comunique ao Suporte Técnico." + Chr(10) + "Rotina " + Procedimento, vbCritical, CabecalhoEnd Sub

Manipulando o Banco de Dados (RECORDSET) Através da variável do tipo Recordset podemos manipular banco de dados.Pelo evento "OPEN" é possível executar qualquer comando SQL. Ao usar o Recordset na verdade esta se criando um cursor no banco responsável pela manipulação e recuperação dos dados. Se utilizar somente o evento "Open" sem especificar suas propriedades então todas as propriedades serão default e o código funciona normalmente.Mas se tratando de manipulação do banco é necessário criar o cursor certo para cada tipo de comando SQL e para que e como você vai manipular os dados de retorno.Para aplicações multiusuario o controle de concorrência se da pela configuração dessas propriedades. Antes de começarmos a ver a pratica da classe Recordset vamos ver suas propriedades.

Propriedades do Cursor

CursorLocation

Define em qual lado será aberto o cursor, se do lado cliente ou do lado do servidor.Neste caso válido somente para banco cliente servidor. Ao abrir um cursor ao lado do cliente as linhas qualificadas são movidas do servidor para o cliente, e a manipulação dos dados fica a cargo da maquina cliente.Tirando parte do processamento do lado do servidor.Isso é bastante importante tratando de aplicações onde se manipulam grandes quantidade de dados e para as consultas em que necessitam de grande processamento, dessa forma você pode manipular o processamento do servidor para não sobrecarrega-lo

pVarRegBanco.CursorLocation = adUseServer (definido do lado do servidor).pVarRegBanco.CursorLocation =adUseClient (definido do lado do cliente).

OBS: No access a maior parte do processamento se da ao lado do servidor independente da propriedade CursorLocation, pois o Access não é banco cliente servidor.Com isso aplicações em rede com Access dependendo do fluxo de acesso não são aconselháveis, pois o fluxo de dados na rede é grande podendo

Page 21: Programação de Banco de Dados

comprometer a banda de rede.Mas isso se for um número muito alto de dados. Mesmo assim a definição do CursorLocation no lado do Servidor é importante mesmo para o Access devido ao controle de concorrência visto a seguir.

CursorType

Propriedade que define o tipo de cursor a ser aberto:

AdOpenDynamic = melhor tipo de cursor e também o mais caro (exige mais do servidor para mante-lo). Consulta abertas com esse tipo de cursor as linhas do banco não são lidas e sim acessadas dessa forma é possível pegar atualizações, deleções e INSERÇÕES de outros usuários. O Access não dá suporte para esse tipo de cursor.

AdOpenForwardOnly = este cursor é somente de avanço e também o cursor default(caso você não especifique o tipo de cursor esse será definido automaticamente).Este cursor não permite retornar nas linhas acessadas só pode ser percorrido para frente.

AdOpenKeyset = este cursor associa um número para cada linha acessada, ao ser solicitado a linha ele acessa o banco, dessa forma com esse cursor é possível pegar alterações e deleções numa aplicação multiusuario.Esse seria o melhor cursor para o Access.

adOpenStatic = este cursor efetua uma copia do banco como se fosse uma foto (snapshot). Não pega alterações nem deleções.

Controle de Concorrência (LockType)

Propriedade que define o tipo de bloqueio do registro:

AdLockReadOnly= Use este tipo de bloqueio para abrir um cursor somente leitura.Neste caso não será possível alterar ou deletar o registro.Normalmente este cursor é utilizado somente para exibir os dados para o usuário.

AdLockOptimistic= Esta é a técnica mais comum de bloqueio.O Banco de dados coloca um bloqueio na(s) linha(s) enquanto a(s) atualiza.

AdLockPessimistic= Esta é a forma mais rígida de controle de concorrência.A linha é bloqueada enquanto o cursor estiver aberto.

AdLockBatchOptimistic= Alguns aplicativos podem descarregar um conjunto de registro para o cliente, cortar a conexão com o servidor, atualizar várias linhas e depois tentar gravar todas as alterações no banco de dados estabelecendo nova conexão.Este método é usado com conjuntos de registros desconectados.

O controle de concorrência determina o que acontecerá quando dois usuários tentarem atualizar a mesma linha ao mesmo tempo.No entanto não basta configurar as propriedades do cursor para construir aplicações multiusuarios, primeiro deve ter a política de concorrência do aplicativo.Antes de iniciar um projeto multiusuário deve-se traçar a estratégia de concorrência, primeiro verificar se existe a concorrência ou se o sistema é somente para consulta (o que é pouco provável) deva forma após essa avaliação analisar o tipo de cursor que melhor atenda a sua concorrência.

Por exemplo:

Dois usuários acessam o mesmo registro numa interface que é possível alterar o registro.Neste caso definindo de forma precisa os cursores somente um usuário vai conseguir alterar, caso isso seja ao mesmo tempo ou então o primeiro usuário altera, e o segundo quando for alterar vai ser a partir dos dados iniciais (sem a alteração do primeiro usuário), ou seja, não existe política de concorrência e um aplicativo assim seria uma "Torre de Babel".

O que poderia ser feito acima seria abrir o cursor com um bloqueio pessimista, ou seja, a linha acessada fica bloqueada enquanto estiver aberto o cursor. Dessa forma somente um usuário iria ter acesso ao

Page 22: Programação de Banco de Dados

registro para editá-lo.Mas esse tipo de bloqueio é perigoso, caso o usuário abra o registro e depois vai tomar um cafezinho o registro fica preso para todos os demais usuários.

Uma solução que proponho para um caso assim seria fazer uma interface de visualização do registro, com um botão para alterar o registro abrindo assim a janela que permite alterar.Dessa forma o registro no banco teria um campo que indicaria se o registro está sendo editado ou não.Assim se dois usuários ao mesmo tempo tentarem editar o mesmo registro somente para um deles a tela de edição será aberta, para o outro teria uma mensagem de bloqueio que pode ser tratada com uma mensagem amigável tipo: Registro sendo editado no momento. Com essa solução o registro não fica bloqueado para leitura.

Para entender melhor, suponha um sistema com duas janelas.Na primeira mostra em uma listview todos os clientes cadastrados, então ao selecionar um cliente abre outra janela com os dados desse cliente.Normalmente ao visualizar esses dados o programador aproveita a mesma janela para alterações colocando um botão "Alterar". Se neste caso ao abrir o cursor para carregar os dados do cliente for um cursor com bloqueio pessimista o registro ficará bloqueado inclusive para leitura, pois não será possível abrir dois cursores pessimista para o mesmo registro.Por isso deve-se tomar cuidado ao usar cursores pessimista.

Para um caso desse tipo, basta o programador mudar os tipos de cursores, não seria necessário alterar a interface. Quando o usuário selecionar o registro na primeira janela abre um cursor somente leitura, carrega todos os campos e fecha o cursor. No botão "Alterar" abre o cursor novamente neste caso com bloqueio otimista efetua a alteração e fecha o cursor.Assim o registro praticamente não ficaria bloqueado, somente no instante do UPDATE.

Nos próximos artigos vou colocar exemplos de códigos explicados, abaixo posto um exemplo simples somente para não ficarmos só na teoria.

Em Modulo

Public Const pConsNomeBanco As String = "Banco.mdb" 'Nome do Banco de DadosPublic Const pConsSenhaBanco As String = "minhasenha" 'Senha do Banco de DadosPublic pVarConBanco as New ADODB.ConnectionPublic pVarRegBanco As New ADODB.RecordsetPublic pVarPathBanco As String 'Caminho do Banco de DadosNa função Main ou no Load do primeiro Form da aplicação If Not Conexao_Banco(pConsNomeBanco,pVarPathBanco,pConsSenhaBanco) Then End

Exemplo para Leitura:With pVarRegBanco .CursorLocation = adUseServer .Open "Select * from Grupo_Produto order by IdGrupo",pVarConBanco, adOpenStatic, adLockReadOnlyEnd With

Primeiro define se o cursor será do lado cliente ou do servidor.Na segunda linha pelo evento OPEN coloca o comando SQL, depois o variável de conexão seguido do Tipo do cursor e do Tipo de bloqueio usado. Esse tipo de consulta seria para carregar um Grid.No termino de carregar o Grid deve fechar o cursor. OBS: Evite ao máximo ficar com o cursor aberto, sempre tenha o controle de abrir e fechar o cursor, manter cursor aberto além de caro para o servidor pode numa queda de luz aumenta as chances de corromper a base de dados. Exemplo para Update:

With pVarRegBanco .CursorLocation = adUseServer.Open "Select IdMesa From ContaMesa where IdMesa=" & RegSelecionado & "", pVarConBanco, adOpenStatic, adLockOptimistic If Not .EOF Then'Se retorna verdadeiro então não achou o registro .MoveFirst 'Posiciona para o primeiro registro retornado Do While Not (.EOF) 'Enquanto não chegar no final !IdMesa = 0 ' Efetua a alteração de IdMesa para 0 .Update 'Efetua o Update para o registro acessado

Page 23: Programação de Banco de Dados

.MoveNext 'Avança com o cursor. Loop End If .Close 'Fecha o cursorEnd With

Repare que neste exemplo o tipo do bloqueio foi adLockOptimistic pois é para efetuar alterações.Essa é apenas uma forma de alterar registro pelo ADO, poderia simplesmente colocar a instrução SQL UPDATE para isso, no entanto caso a instrução UPDATE não encontrar o registro não acontece nada, nem mensagem de erro.Fazendo a alteração igual ao exemplo acima é possível saber se te fato houve ou não alteração.O código acima apenas trata o erro se não achar o registro, mas caso o registro não seja achado não retorna uma mensagem para o usuário. O mesmo problema ocorre no caso da Deleção, se for através da instrução SQL , caso o registro não exista não ocorre nada.Por isso eu não uso as instruções UPDATE e DELETE do SQL, somente uso SELECT e INSERT.As alterações e deleções faço através das propriedades do ADO Exemplo de Deleção:

With pVarRegBanco .CursorLocation = adUseServer .Open "Select IdMesa From Mesa where IdMesa=" & RegSelecionado & "", pVarConBanco, adOpenStatic, adLockOptimistic .Delete adAffectCurrent .Close End With

A propriedade adAffectCurrente seria deletar o cursor acessado.Caso a consulta possa retornar mais de uma registro faça um Loop como o do exemplo da alteração colocando .Delete adAffectCurrente no lugar do .Update. Outro detalhe as consultas SQL não foram abertas usando o curinga (*), se utilizar o curinga não tem problema o código funcionária da mesma forma, no entanto iria retornar campos desnecessário, resultando maior trafego na rede sem necessidade.Por isso evite abrir cursores com curinga (*) desnecessariamente, use o curinga quando de fato for para retornar todos os campos de um registro, como por exemplo, exibir um registro para o usuário. Um Exemplo de Inserção:

With pVarRegBanco .CursorLocation = adUseServer .Open "Insert Into Mesa values(" & Trim(FTxtIdMesa.text) & "," & CmbFumantes.ItemData(CmbFumantes.ListIndex) & ",'" & Trim(FTxtLugares.text) & "' ,0,1,'" & Trim(TxtLocalizacao.text) & "' )", pVarConBanco.Conection, adOpenStatic, adLockOptimistic End With

Bem simples não? Basta usar o comando SQL, com a atenção para o tipo de bloqueio, neste caso "sempre"o otimista.Existe outra forma de incluir registro que seria através das propriedades do ADO usando o ADDNEW, no entanto não acho bom usá-lo, pois ele cria um registro no caso com todos os campos com NULL e depois atribui para cada campo os valores (igual ao UPDATE) e no final chama o evento do ADO .UPDATE, ou seja, a inserção pelo ADO ele simplesmente cria um novo registro e depois o altera.Caso a luz acabe justamente quando tiver sendo atribuído os valores aos campos você terá no seu banco um registro com campos NULL mesmo que tenha configurado para o campo não receber nulo.Sendo assim acho muito mais eficaz usar a instrução SQL INSERT para inserir. No próximo artigo continuamos a abordar o ADO com mais exemplos, e também vamos abordar as transações.

Programação de Banco de Dados - parte 6

Este é o sexto artigo sobre Banco de Dados e vamos continuar abordar o componente ADO. No quinto artigo falamos como usar o ADO para conectar ao banco e como consulta, incluir, excluir e atualizar registros. Agora vamos abordar Transações e como implementar isso usando ADO.

Primeiro o que seria uma transação?

Page 24: Programação de Banco de Dados

Uma transação é uma unidade atômica de processamento que inclui uma ou mais operações de leitura ou escrita no banco de dados. Algumas características de transações:

- Atomicidade: como principal característica sua execução tem que ser integral, ou nenhuma parte deve ser executada, ou seja, você utiliza transação quando determinada ação envolve atualização de mais de uma tabela do banco.E para garantir que todas as atualizações sejam feitas utiliza-se transação. Se uma ação pode ser separada em ações menores, então temos duas (ou mais) transações, ou seja, se uma ou mais ações podem falhar sem deixar o banco de dados em estado inconsistente, estas ações não devem ser parte da mesma transação.

- Consistência: A execução de uma transação deve levar ao banco de dados de um estado consistente a outro também consistente. Uma transação é consistente se não violar a integridade do banco de dados. Se a transação tiver êxito ou falhar, ela deve deixar o banco de dados em um estado consistente.Se uma transação falhar, ela precisa desfazer todas as alterações temporárias e deixar o banco de dados no estado em que ele estava antes que a transação iniciou.

- Isolamento: Uma transação não deve tornar suas atualizações visíveis a outras transações antes do seu fim. Uma transação que debita uma conta e credita outra deve ser totalmente transparente. Quando isso é feito, a transação precisa atualizar o banco de dados de uma só vez. Por exemplo, se um usuário solicitar o saldo de uma conta e a mesma está sofrendo uma transação o banco de dados só deve retornar o valor do saldo depois que completar a atualização, assim dessa forma durante a transação algumas linha são bloqueadas.

- Durabilidade: Após o termino de uma transação, suas atualizações não podem ser perdidas por causa de falhas futuras. Se todas as ações forem realizadas com sucesso isso não significa sucesso na transação, pois precisa gravar os dados de volta ao disco. Caso ocorra uma falha no disco a transação não é válida. Então antes que uma transação seja completada ela deve verificar se as alterações foram gravadas com sucesso antes de terminar.

Dessa foram ao utilizar transação você garante que será executado cada linha do código pertencente à transação. Caso ocorra alguma falha durante a execução da transação devem ser canceladas todas as alterações até a ocorrência da falha.Assim você mantém a integridade do banco de dados além da consistência dos dados da sua aplicação.

As transações podem ser divididas em dois tipos: de integridade dos dados e de consistência da ação. Integridade e consistência do banco podem dizer a mesma coisa, mas quando me refiro à integridade dos dados é em relação às regras impostas nos relacionamentos.

Exemplo:

Temos uma tabela VENDA que armazena os dados da venda como: valor, data, caixa e etc. Outra tabela PRODUTOS com os dados dos produtos cadastrados no estoque. E por ultimo uma tabela PRODUTOS VENDIDOS que relaciona a venda com o produto assim:

Tabela VendaIdVenda= 0001Valor= R$ 150,00Caixa= Fulano

Tabela ProdutoIdProduto= 200Valor= R$ 5,00Estoque=100

Tabela ProdutosVendidosIdVenda= 0001IdProduto= 200Qtde=30

Então a integridade seria quebrada caso apaga-se o produto 200 da tabela produto e não propagar a exclusão para a tabela ProdutosVendidos, ou incluir um registro na tabela ProdutosVendidos onde o

Page 25: Programação de Banco de Dados

IdVenda não existe na tabela Venda e a mesma coisa para o IdProduto.E sobre a consistência da ação seria ocorrendo a venda 0001 gravar na tabela ProdutosVendidos os itens da venda e para cada item vendido atualizar o estoque. Sendo que as regras de integridade o SGBD trata para nós sendo transparente. Claro algumas regras de integridade devem ser impostas ao banco sendo por trigger, procedures ou por regras oferecidas diretamente pela interface do banco, como por exemplo: manter a integridade do relacionamento propagando exclusão ou alteração no Access. Não vou abordar as transações de integridade do banco, sendo que podem ser impostas na própria aplicação pelo que vai ser mostrado aqui, no entanto um projeto que deixa do lado da aplicação a integridade referencial do banco tem o banco de dados mal projetado. Vamos então nos preocupar somente com as transações das "regras do negócio". Essas transações podem passar como despercebidas no banco de dados.Isso depende do projeto, caso seja definido que as regras do negócio sejam do lado do banco então as transações seriam através de script's em SQL definidos por trigges e procedures no banco. Aonde a aplicação iria apenas executá-las e aguardar o seu retorno. O ADO nesse caso somente iria "participar" no comando da execução da trigger ou procedure. Existe uma diferença entre manter a integridade do banco e manter as regras do negocio. As regras de integridade do banco devem estar definidas no próprio banco, enquanto as regras do negócio podem ser dividas entre banco ou aplicação, ou então definidas em uma terceira camada, como abordamos no artigo 2. O que vou vamos ver nesse artigo são transações que definem a regra do negócio fora do banco de dados usando ADO. O que é muito simples, pois todas as características de uma transação o ADO juntamente com o SGBD tratam para nós. Para nós basta informar quando se inicia uma transação, o seu fim e no tratamento de erro cancelar a transação. Nossa atenção deve voltar para a analise do problema e verificar para cada ação no banco se envolve ou não uma transação para manter a regra do negócio. Agora chega de teoria e vamos finalmente a prática.

Os comandos de transação são métodos da classe Connection. As ações da transação têm que usar o mesmo objeto (variável da classe connection) que chamou o método de inicio da transação. Conforme abordado no quinto artigo declare a variável connection, exemplo:

'Objeto de Conexão com BancoPublic pVarConBanco As New ADODB.Connection

pVarConBanco.BeginTrans 'Comando de inicio de transaçãopVarConBanco.CommitTrans 'Comando de término de transaçãopVarConBanco.RollbackTrans 'Comando que cancela a transação.Os comandos do ADO para transação se resume nesses. Agora um exemplo de uma transação: Private Function NovaConta(ByVal IdMovimento As Long) As Long 'Retorna Id da Nova Conta(IdVenda) Dim lVarIdVenda As Long On Error GoTo T_Erro pVarConBanco.BeginTrans On Error GoTo T_Transacao With pVarRegBanco .CursorLocation = adUseServer .Open "Insert Into Venda Values(……)", pVarConBanco, adOpenStatic, adLockOptimistic On Error GoTo T_Consulta 'Pega Id da Venda .Open "Select @@Identity From Venda", pVarConBanco, adOpenStatic, adLockReadOnly lVarIdVenda = pVarRegBanco(0) .Close On Error GoTo T_Transacao 'Relaciona Conta com Mesa .Open "Insert into ContaMesa Values(………)", pVarConBanco, adOpenStatic, adLockOptimistic On Error GoTo T_Alteracao 'Altera Status Mesa .Open "Select Status From Mesa Where IdMesa = " & Me.IdMesa & "", pVarConBanco, adOpenStatic, adLockOptimistic

Page 26: Programação de Banco de Dados

!Status = EnStatus.Reservada .Update .Close End With pVarConBanco.CommitTrans Exit FunctionT_Erro: MSG_ERRO "NovaConta" Exit FunctionT_Transacao: Set pVarRegBanco = Nothing pVarConBanco.RollbackTrans MSG_ERRO "NovaConta" Exit FunctionT_Consulta: pVarRegBanco.Close Set pVarRegBanco = Nothing pVarConBanco.RollbackTrans MSG_ERRO "NovaConta"T_Alteração: pVarRegBanco.CancelUpdate Set pVarRegBanco = Nothing pVarConBanco.RollbackTrans MSG_ERRO "NovaConta"End Function

Temos um exemplo completo de uma transação que envolve: - Adicionar uma venda na tabela VENDAS.- Pegar o código autonumerico do registro que acabamos de adicionar.- Inserir esse código da venda na tabela CONTAMESA- Alterar o status da mesa colocando ela como ocupada. Logo para criar uma venda deve ter todas as alterações acima, se uma falhar vai quebrar a regra do negócio. Comentando o código: » pVarConBanco.BeginTrans 'Inicio da transação. Para cada alteração da transação vamos efetuar pela classe Recordset abordada no artigo cinco. » Inclusão do registro na tabela Vendas, repare que o objeto de conexão dessa linha é o mesmo que iniciou a transação. Usando Insert pelo variável Recordset não é necessário fechar o cursor pVarRegBanco.Open "Insert Into Venda Values(……)", pVarConBanco, adOpenStatic, adLockOptimistic» Esta consulta com o campo especial @@Identity vai retornar o código autonumeric do registro que foi adicionado durante esta transação.Esse consulta só funciona se usar transação. pVarRegBanco.Open "Select @@Identity From Venda", pVarConBanco, adOpenStatic, adLockReadOnlylVarIdVenda = pVarRegBanco(0) 'Atribui a variável local o valor retornado pela consultapVarRegBanco.Close 'Fecha o cursor» Aqui fazemos outra inclusão, sendo que agora na tabela ContaMesa, usando o valor da variável lvarIdVenda. PVarRegBanco.Open "Insert into ContaMesa Values(" & lvarIdVenda & ")", pVarConBanco, adOpenStatic, adLockOptimistic» Fazemos agora uma alteração no Status da Mesa na tabela Mesa. A consulta trazendo o registro desejado. PVarRegBanco.Open "Select Status From Mesa Where IdMesa = " & Me.IdMesa & "", pVarConBanco, adOpenStatic, adLockOptimisticPVarRegBanco!Status = EnStatus.Reservada'Atribuição do novo valor ao campo.PVarRegBanco .Update'Confirmar a alteração.PVarRegBanco.Close 'Fecha o cursor.» Por fim confirmamos a alteração.Somente neste ponto que todas as alterações serão confirmadas. pVarConBanco.CommitTransTratamento dos Erros » Ao fazer uma transação deve ter uma atenção maior ao tratamento de erro. Repare que antes de chamar o BeginTrans tenho um tratamento de erro, onde não faz nada somente chama um procedimento padrão que exibe uma mensagem de erro para o usuário. Esse tratamento é necessário caso a conexão com o banco tenha sido perdida.

Page 27: Programação de Banco de Dados

On Error GoTo T_ErropVarConBanco.BeginTrans» Após o BeginTrans temos outro tratamento de erro (T_Transação) , onde colocamos o comando pVarConBanco.RollbackTrans. Não pode colocar esse comando no tratamento T_Erro, pois vai ocorrer um erro runtime, pois não pode chamar RollBack sem ter uma transação iniciada, logo a aplicação vai abortar pois deu erro dentro do tratamento de erro. » Antes da consulta do código autonumeric alteramos novamente a referencia do erro (T_Consulta). Para pode chamar o comando .Close do Recordset. » Depois retornamos o tratamento de erro para T_Transação, pois o próxima ação é um Insert usando a classe recordset. Logo no tratamento de erro dessa ação não pode estar o comando Close senão gera erro runtime. » Depois temos outro tratamento diferenciado antes da atualização do status mesa. Isso para poder cancelar a atualização pelo comando CancelUpdate. Repare que neste tratamento temos também o comando Rollback, pois já foi iniciada a transação e ocorrendo qualquer tipo de erro devemos cancelar. O que dá mais trabalho em uma transação é fazer o tratamento de erro como vocês podem ver, pois a própria transação em si se resume em três comando do ADO. Um comando interessante que vimos foi a consulta usando o campo especial @@Identity, onde retorna o código gerado na inclusão. Sendo que só funciona usando transação. Assim fico por aqui, fechando o assunto transação. Espero que este artigo ajude mais um pouco a vocês. No próximo artigo vou falar como executar triggers e procedures pelo ADO. Até a próxima.