Banco de Dados: Introdução

Podemos entender por banco de dados qualquer sistema que reúna e mantenha organizada uma série de informações relacionadas a um determinado assunto em uma determinada ordem.

A lista telefônica é um exemplo. Nela, percebemos que todos os dados referentes a uma pessoa estão na mesma linha. A isso chamamos registros.

O tipo ou categoria da informação (nome, telefone, etc.) sobre uma pessoa está separada em colunas, as quais chamamos campos.

Um Sistema Gerenciador de Banco de Dados Relacionais (SGBDR) é usado para armazenar as informações de uma forma que permita às pessoas examiná-las de diversas maneiras.

O Gerenciador Relacional de Bancos de Dados do Visual Basic e do Access é o Microsoft Jet. Ele pertence a uma categoria diferente dos gerenciadores tradicionais, como o Dbase e o Paradox, pois possui características em comum com os bancos de dados cliente-servidor. Tais características comuns são:

  • Todas as tabelas, índices, consultas, relatórios e código são armazenados num único arquivo MDB
  • Os campos de data suportam informação de hora
  • Admite o armazenamento permanente de comandos SQL
  • É possível forçar a integridade referencial entre tabelas
  • Os campos suportam valores nulos (Null)

No Dbase/Clipper, banco de dados significa um arquivo que contém a estrutura de dados (campos) e os dados (arquivo padrão DBF). Para o padrão MDB, este conjunto de dados e sua estrutura denomina-se Tabela.

Portanto, aquilo que o Dbase/Clipper considera um banco de dados, o Access e o Visual Basic consideram como uma tabela.

Podemos então definir tabela como um conjunto de dados dispostos em forma de linhas e colunas. Como exemplo, vejamos a tabela de endereços abaixo:

Nome Endereço Telefone
Carlos Lima Bueno Rua Pindamonhangaba , 1200 226-2356
Carlos Lima Buel Rua Voluntários de São Paulo , 2785 224-1078
Carlos Luiz Moraes Rua D. Pedro II , 123 223-0991

As linhas da tabela são os registros (nome, endereço, telefone) e as colunas são os campos. A interseção de uma linha com uma coluna define um atributo representando um valor do campo. Para a tabela representada acima, a interseção da segunda linha com a coluna nome define o valor do campo nome como Carlos Lima Buel.

Para o Access e o Visual Basic, todos os componentes do sistema estão em um único arquivo com extensão MDB. A este “pacote” consideramos o banco de dados, o qual é um conjunto das tabelas nele contidas.

Logo, quando abrimos um arquivo MDB, temos acesso a todos os componentes do sistema: tabelas, consultas, macros, relatórios, etc. A esses componentes chamamos objetos do sistema e em resumo, podemos descrevê-los a seguir:

Tabelas Onde armazenamos as informações que queremos tratar
Consultas Filtram as informações das tabelas e permitem sua visualização.Geralmente são comandos SQL
Formulários São janelas destinadas à edição e visualização dos dados
Relatórios Organizam os dados de tabelas e consultas de uma maneira que possam ser impressos
Macros Rotinas que automatizam determinadas tarefas sem necessidade de programação (utilizadas no Access)
Módulos Armazenam instruções e comandos da linguagem Access Basic/VBA e permitem melhorar e expandir os recursos do sistema

Obs.: Embora o Visual Basic utilize arquivos padrão MDB, formulários, relatórios e módulos são tratados de forma diferente pelo próprio Visual Basic e, nativamente, o Visual Basic não utiliza Macros. Além disso, no Access e Visual Basic, podemos utilizar outros arquivos além dos arquivos MDB, como arquivos DBF do Dbase/Clipper, arquivos do Paradox, do Btrieve, etc.

Os recursos de definição de dados do mecanismo Jet permitem a criação, a modificação e a exclusão de tabelas, índices e consultas. O Jet também aceita a validação de dados em nível de campo e registro. A integridade de dados tem suporte sob a forma de chaves primárias e integridade referencial entre tabelas.

Para manipulação de dados, o Jet admite o uso da SQL e de objetos de acesso aos dados. Esses objetos permitem ao programador manipular informações contidas no banco de dados através da definição das propriedades dos objetos e pela execução dos métodos associados aos objetos. A tabela abaixo relaciona esses objetos e descreve resumidamente suas funções:

Objeto Descrição
DBengine O objeto que referencia o mecanismo de bancos de dados do Microsoft Jet
Workspace Uma área na qual o usuário pode trabalhar com os bancos de dados
Database Uma coleção de informações organizadas em tabelas, juntamente com informações a respeito de índices e relações sobre as tabelas
TableDef Uma definição da estrutura física de uma tabela de dados
QueryDef Uma consulta armazenada de SQL das informações contidas no banco de dados.
Recordset Uma coleção de registros de informações sobre um único tópico
Field Uma única unidade de informações em um banco de dados
Index Uma lista ordenada de registros em um recordset, baseada em um campo chave definido
Relation Informações armazenadas a respeito do relacionamento entre duas tabelas

O poder da SQL

A linguaguem SQL (Structured Query Language) é uma linguagem de alto nível para manipulação de dados dentro do modelo relacional. Seu objetivo é fornecer uma interface de alto nível ao usuário. É uma linguagem não procedural e não cabe ao usuário definir como o gerenciador de banco de dados executará uma tarefa, mas somente o que ele deve fazer.

Uma instrução SQL consiste de três partes:

  • As declarações de parâmetros
  • A instrução manipulativa
  • As declarações de opções

Para termos uma idéia do seu poder, imagine que temos que atualizar o campo valor em 10% de uma tabela com diversos registros. Na abordagem procedural, teríamos os seguintes passos:

  1. Abrir a tabela
  2. Posicionar o ponteiro no início da tabela
  3. Atualizar o campo valor em 10%
  4. Mover o ponteiro para o próximo registro
  5. Continuar a atualização do campo valor até o final da tabela

O código poderia ter o seguinte aspecto:

Dim db as database
Dim tabela as recordset
set db=workspaces(0).Opendatabase(“c:\base.mdb”)
set tabela=db.Openrecordset(“tabela”)
Whilel not tabela.eof

tabela.edit
tabela.valor=tabela.valor*1.10
tabela .update
tabela.movenext

Wend
tabela.close

Agora utilizando uma instrução SQL, teríamos o seguinte trecho de código:

Dim db as Database
Set db=Workspaces(0).Opendatabase(“c:\base.mdb”)
db.execute “UPDATE tabela SET valor=valor*1.10”
db.close

Observe a utilização da instrução SQL UPDATE, bem mais simples, não é?
Então, se você não está utilizando a SQL, está trabalhando muito e seu código sofrendo as consequências.

Veja na tabela abaixo um resumo das cláusulas manipulativas e suas finalidades:

Instrução Função
SELECT Obtém um grupo de registros e insere os registros em um dynaset ou em uma tabela
UPDATE Define os valores dos campos de uma tabela em uma atualização
TRANSFORM Cria uma tabela de resumo, utilizando o conteúdo de um campo como cabeçalho de cada coluna
DELETE FROM Remove registros de uma tabela
INSERT INTO Acrescenta um grupo de registros a uma tabela.

Veja alguns exemplos da instrução SELECT:

1) Seleciona os campos “Primeiro nome” e “Sobrenome” de todos os registros da tabela Empregados.

SELECT [Primeiro nome], [Sobrenome] FROM Empregados

2) Seleciona todos os campos da tabela Empregados. Note o uso parâmetro (*) indicando todos os campos da tabela indicada.

SELECT Empregados.* FROM Empregados

3) Conta o número de registros que têm uma entrada no campo “Código postal” e coloca o título Contagem no topo da coluna.

SELECT Count([Código postal]) AS Contagem FROM Clientes

4) Seleciona os campos “Primeiro nome” e “Sobrenome” de cada registro cujo sobrenome seja Pereira.

SELECT [Primeiro nome], [Sobrenome] FROM Empregados WHERE [Sobrenome] = ‘Pereira’

5) Seleciona os campos “Primeiro nome” e “Sobrenome” para Empregados cujos sobrenomes começam pela letra S.

SELECT [Primeiro nome], [Sobrenome] FROM Empregados WHERE [Sobrenome] Like ‘S*’

FROM – indica as tabelas utilizadas como fonte de dados

WHERE – especifica as condições que os registros devem satisfazer para compor o subconjunto de dados.

ADO – Localizando informações

Quando falamos a nível de dados (campos e registros), estamos tratando com o objeto Recordset. Vamos mostrar como encontrar dados específicos em um Recordset ADO. Lembrando que um objeto Recordset possui muitas funções úteis. Entre elas podemos citar as mais usadas: Bookmark, Find, Seek, Filter.

Usando Bookmarks (marcadores)

Um bookmark de um recordset é como um cursor que aponta para um registro específico dentro do Recordset identificando-o de forma única. Fazendo uma analogia: ao ler um livro, você costuma usar um marcador para indicar em qual página parou para, quando retornar a leitura, localizar com rapidez onde parou. Assim funciona um bookmark. Para usá-lo em um objeto recordset, as etapas são:

  • Defina uma variável para ser usada como marcador:  Dim marcador as variant
  • Quando desejar marcar uma posição em um recordset no registro atual usando a variável definida acima, faça:  marcador = rs.bookmark
  • Para retornar a posição marcada no item anterior, faça:  rs.bookmark = marcador

Mas tome cuidado pois nem todos os registros suportam bookmarks. Para verificar se um recordset suporta bookmarks, use a seguinte instrução:  blnmarcador = rs.Supports(adBookmark)

Assim, o método Supports usando o argumento adBookmark retorna TRUE se o recordset suporta bookmarks e FALSE, caso não suporte.

Localizando dados com ADO

Basicamente temos dois métodos para localizar dados em um recordset usando ADO: Find e Seek.

1) Usando o método Find

O método Find é usado para encontrar um registro que contém um determinado valor em um determinado campo do registro. Você define um critério de busca, e se o critério for satisfeito, o ponteiro do registro se posiciona no registro que atendeu ao critério. Se o critério não foi atendido, o ponteiro se posiciona no fim do recordset. A sintaxe é a seguinte:

Find (critério, SkipRows, searchDirection, start)

Parâmetros:

critério – uma string contendo o nome da coluna, o operador de comparação e o valor que desejamos localizar.

Exemplos de strings de busca:

  • “FornecedorID >= 7”
  • “DataPedido = #09/10/1997#”
  • “Codigo > 7”
  • “Nome = ‘” & variavel & “‘”

Lembrando que os valores strings devem vir entre aspas simples (‘Joao’) e as datas devem estar iniciadas e terminadas com o símbolo (#).

SkipRows – define o deslocamento da linha atual ou o bookmark padrão para iniciar a busca. O padrão é começar na linha atual e terminar na última linha.

searchDirection – indica a direção em que o recordset é procurado. Os valores podem ser:

  • adSearchForward ou adSearchBackward – a busca irá cessar no início ou no fim do recordset dependendo destes valores. Se a busca é iniciada para frente e nada for encontrado, o cursor do recordset é definido para além do último registro e a propriedade EOF (End Of File) retorna TRUE. Já se a busca é feita para trás e nada for achado, o cursor é definido para além do início do arquivo e a propriedade BOF (Beginning Of File) retorna TRUE.

start – define um bookmark de início para a busca.

Obs.: Se você não definir a posição do cursor na linha atual quando for iniciar a busca, irá ocorrer um erro. Por isso, antes de usar o método Find, você pode mover o cursor para o início do arquivo usando o método MoveFirst.

Exemplo prático:

Vamos mostrar em um exemplo prático como usar o método Find.

  • Inicie um novo projeto no VB e antes de qualquer coisa, faça uma referência a biblioteca ADO, na opção do menu Project | References, como na figura abaixo.

  • A seguir, insira o seguinte código no projeto:
Dim cnn As New ADODB.connection
Dim rst As New ADODB.Recordset

Private Sub Form_Load()
Dim criterio As String ‘Abre a conexão
cnn.Open “Provider=Microsoft.Jet.OLEDB.3.51;Data Source=C:\teste\Northwind.mdb;” ‘Abre o Recordset
rst.CursorLocation = adUseClient
rst.Open “Select * From Suppliers”, cnn, adOpenKeyset, adLockOptimistic, adCmdText

‘move-se para o primeiro registro
rst.MoveFirst

define o criterio para busca
criterio = “Country Like ‘A%'”
inicia busca no recordset
rst.Find criterio, 0, adSearchForward

‘ percorre o recordset ate o seu final
While Not rst.EOF
Debug.Print rs(“CompanyName”)
marcador = rst.Bookmark
rs.Find criterio, 1, adSearchForward, marcador
Wend

End Sub

Vamos explicar passo a passo:

1. Dim cnn As New ADODB.connection
Dim rst As New ADODB.Recordset

Define as variáveis objetos usadas para a conexão e para o objeto Recordset.

2. ‘Abre a conexão
cnn.Open “Provider=Microsoft.Jet.OLEDB.3.51;Data Source=C:\teste\Northwind.mdb;”

Abrimos uma conexão usando o provedor (Microsoft.Jet.OLEDB.3.51) e o Data Source (C:\teste\Northwind.mdb).

3. ‘Abre o Recordset
rst.CursorLocation = adUseClient
rst.Open “Select * From Suppliers”, cnn, adOpenKeyset, adLockOptimistic, adCmdText

Definimos o tipo de cursor usado, no caso usamos o cursor do lado do cliente (AdUseClient) e abrimos um recordset com os parâmetros AdOpenKeySet (permite a alteração) e adLockOptimistic (usa o bloqueio pessimista (mantém o bloqueio até usar o método para atualizar)).

4. define o criterio para busca
criterio = “Country Like ‘A%'”
inicia busca no recordset
rst.Find criterio, 0, adSearchForward

Definimos o critério para busca e iniciamos a busca usando o método Find, usando os parâmetros SkipRows = 0 e adSearchForward (busca do início para o fim).

5. While Not rst.EOF
Debug.Print rs(“CompanyName”)
marcador = rst.Bookmark
rs.Find criterio, 1, adSearchForward, marcador
Wend

Percorremos o recordset, imprimindo o campo CompanyName e se posicionando a partir do bookmark anterior, com avanço de um registro para frente, a partir do bookmark (marcador). Note que usamos o bookmark para armazenar a posição atual do registro e usamos esta posição inicial para a próxima busca.

2) Usando o método Seek

O método Seek permite a procura em uma coluna. Ele só encontra os valores iguais ao valor da procura e vai precisar de um provedor de dados que permita a utilização da propriedade Index e o método Seek (nem todos os provedores permitem). Além disso, o método Seek vai requerer um cursor do lado do servidor.

Atualmente, somente alguns provedores permitem usar a propriedade Index e o método Seek do objeto Recordset para procurar por valores em um índice de uma tabela. O provedor OLE DB (Provider for Microsoft Jet 4.0) que é usado para se conectar a um banco de dados Access, permite a utilização do método Seek.

Para verificar se o provedor suporta a propriedade Index e o método Seek, podemos usar o método Supports com os parâmetros adIndex e adSeek. Veja o exemplo abaixo:

If rs.Supports(adIndex) then
msgbox “Este Provedor suporta a propriedade Index”
endif

If rs.Supports(adSeek) then
msgbox “Este Provedor suporta a propriedade Seek”
endif

Você deve ter o cuidado de definir a propriedade Index assim que o Recordset for aberto para depois usar o método Seek. A propriedade Index indica o nome do índice que estará ativo. Assim, supondo que você possua uma tabela chamada clientes e que queira fazer uma busca pela coluna Nome da tabela, vai precisar definir um índice para estar coluna na tabela, dando a ele um nome. O nome do índice pode ser o mesmo nome da coluna. Para o nosso caso, poderíamos ter criado um índice chamado Nome (você poderia ter usado qualquer outro nome para definir o índice). Teríamos então:  rs.index – “nome”

Em muitos casos, quando você usa um campo autonumeração no Access e define este campo como uma chave primária, o índice PrimaryKey será criado para esta coluna da tabela. Então, se for usar esta coluna para fazer uma busca usando o Seek, deverá usar a sintaxe:  rs.Index = “PrimaryKey”

Depois que a propriedade Index foi definida para o nome do índice existente na tabela, podemos usar o método Seek para procurar na coluna desejada. Quando o método Seek encontrar o registro desejado, o ponteiro irá se posicionar neste registro. Se nada for encontrado, o ponteiro é definido para EOF. A sintaxe é a seguinte:

rs.Seek Array(valordacoluna)

Aqui você deve tomar cuidado. Como um índice pode ser constituído de uma ou mais colunas, o termo valordacoluna indica os valores da coluna. Vamos supor que você tem uma tabela de clientes com um campo CodigoID definido como chave primária, e você quer procurar pelo cliente cujo código seja igual a 120. Você deverá procurar pelo valor 120 na coluna CodigoID e deverá fazer:

rs.Index = “PrimaryKey”

rs.Seek Array(120)

Se o índice possuir mais de uma coluna, você deverá informar no vetor (array) os valores de todas as colunas contidas no índice. Por exemplo, se uma tabela pedidos possuir um índice chamado PrimaryKey e for constituído pelos campos codigopedido e codigoproduto da tabela, ao usar o método Seek para procurar pelo pedido cujo código seja igual a 23 e código de produto igual a 50, você deverá fazer:

rs.Index = “PrimaryKey”

rs.Seek Array(23,50)

Vejamos agora um exemplo completo usando a propriedade Index e o método Seek:

Neste exemplo, usaremos o banco de dados Northwind.mdb e a tabela Funcionários. A estrutura e os índices criados são dados abaixo:

Iremos usar o índice chave primária CodigoDoFuncionario para localizar o funcionário e exibir o seu nome.

O projeto usará um formulário, uma caixa de texto e um botão de comando.

Defina as variáveis objeto na seção General Declarations:

Dim cnn As New ADODB.connection
Dim rst As New ADODB.Recordset

O código do botão de comando segue abaixo:

Private Sub Command1_Click()

If Text1.Text = “” Then
MsgBox ” Informe um valor para busca ”
Exit Sub
End If

‘Abre a conexão
cnn.Open “Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\teste\Northwind.mdb;”

Abre o Recordset
rst.CursorLocation = adUseServer
rst.Open “Funcionários”, cnn, adOpenKeyset, adLockReadOnly, adCmdTableDirect

If rst.Supports(adIndex) And rst.Supports(adSeek) Then
rst.Index = “CódigoDoFuncionário”
rst.MoveFirst
rst.Seek Array(CLng(Text1.Text))
If rst.EOF Then
MsgBox “Funcionário não localizado”
Else
MsgBox rst(“CódigoDoFuncionário”) & ” – ” & rst(“nome”) & vbCrLf
End If
Else
MsgBox ” O provedor utilizado não suporta : Index e Seek ”
End If

´Fechamos a conexão e o recordset
rst.Close
cnn.Close
Set rs = Nothing
Set cnn = Nothing

End Sub

Observe que antes de iniciar a busca, verificamos se o provedor suporta a utilização de Index e de Seek. Se o método Supports é novo para você, veja abaixo as constantes que você pode usar com ele:

Constante Utilização
adAddNew Verifica se novos registros podem ser adicionados
adApproxPosition Verifica se as propriedades: AbsolutePage e AbsolutePosition estão disponíveis
adBookMark Verifica se podemos usar um marcador no Recordset
adDelete Verifica se os registros poderão ser excluídos
AdHoldRecords Verifica se podemos recuperar os registros sem submeter as alterações
adResync Verifica se o método Resynd esta disponível
adUpdate Verifica se o conjunto de registros permite a atualização
adUpdateBatch Verifica se o recordset permite a atualização em lote – via UpdateBatch

Começar a Programar

Antes de começar a programar, é necessário saber algumas noções de programação, e essas noções envolvem principalmente o raciocínio lógico. A programação destina-se a resolver problemas da forma mais simples possível, eliminando processos redundantes e melhorando a obtenção de resultados.

Estrutura da programação

  • Análise do problema (dados de entrada, dados de saída, relações de transformação)
  • Desenvolvimento do algoritmo
  • Codificação na linguagem de programação
  • Execução e testes.

Dados de entrada: dados que são necessários fornecer para que possam ser calculados os dados de saída.

Dados de saída: resultados a obter.

Relações de transformação: relações matemáticas ou de qualquer outra espécie que permitam transformar os dados de entrada nos dados de saída.

Algoritmo: escrita, numa linguagem normalizada, da sequência de operações que definem o problema.

Noções de Algoritmo

Para resolver os problemas em programação, recorreremos à utilização de algoritmos.

E o que é um algoritmo?

Um algoritmo é, nada mais nada menos, do que a sequência de passos a realizar para que possamos chegar à solução de um determinado tipo de problema.

A utilização de algoritmos apenas visa tornar mais fácil a programação, visto que, ao elaborarmos um algoritmo, subdividimos o problema sistematicamente em partes mais pequenas e menos complexas, chegando a um ponto em que compreendemos claramente cada uma das partes.

Assim,podemos indicar sem ambiguidade os passos (algoritmo) para a resolução de problemas:

  • Analisar o problema
  • Conhecer o problema: ouvir o problema, entendê-lo, perceber qual o objetivo
  • Descrever o problema: subdividir o problema (esquematizar), detalhar
  • Resolver o problema: escrever passo-a-passo o raciocínio da solução do problema; verificar se não existe ambiguidade
  • Implementar: esta fase acontece apenas após o problema estar resolvido e consiste em implementar o algoritmo numa linguagem de programação

Linguagens de Programação

Para que um computador produza resultados úteis é necessário indicar as ordens que ele deve obedecer. Essas ordens são uma série de instruções binárias – as únicas instruções que o computador entende, também designadas por código de máquina.

Apesar de ser possível escrever um programa diretamente em código de máquina, dar ordens em número binários é difícil, lento e sujeito a erros. Assim, se desenvolveram linguagens de programação de baixo e alto nível, que são próximas do código de máquina ou da linguagem humana, respectivamente.

É nessas linguagens que são escritos os programas com que os computadores funcionam e que se formam por programas fonte. Assim, uma linguagem de programação é constituída por um conjunto de palavras (ou símbolos) que, colocados segundo determinadas regras, significam operações que o computador deve realizar.

As linguagens de programação têm como função descrever todas as operações a serem efetuadas por um computador, necessárias para se resolver um determinado problema. Desta forma, uma linguagem de programação deve apresentar as seguintes facilidades:

  • Um vocabulário limitado
  • Regras gramaticais simples
  • Ser clara e concisa
  • De aprendizagem simples

Existe uma grande variedade de linguagens de programação:

Linguagens de baixo nível:

  • Linguagem de máquina e linguagens Assembly
  • Vocabulário elementar
  • Processamento de execução rápida
  • Formulação dos problemas extremamente complicada e sujeita a erros

Linguagens de alto nível:

  • BASIC, Fortran, Cobol, C, Pascal, Java, etc.
  • Vocabulário adequado à expressão de grande complexidade
  • Processamento de execução morosa
  • Facilitam a tarefa do programador