|
||||||||||||||||||||||||||||||||||||||||||||||||
Microsoft Jet SQL intermediário para Access 2000 |
||||||||||||||||||||||||||||||||||||||||||||||||
Segundo em uma série de três artigos, o SQL Intermediário amplia os conceitos cobertos no artigo SQL Fundamental e apresenta uma imagem muito mais detalhada do que pode ser feito com o Microsoft Jet SQL no Access. Para usuários e desenvolvedores que procuram expandir seu conhecimento da Linguagem Estruturada de dados como usada pelo Motor de Bases de Dados Microsoft Jet, este artigo é o passo seguinte. |
||||||||||||||||||||||||||||||||||||||||||||||||
Acey James Bunch
O artigo Microsoft Jet SQL Fundamental Para Access 2000 mostrou como construir os objetos básicos que fazem uma base de dados relacional. As seções a seguir, neste artigo, discutem os comandos intermediários da Linguagem de Definição de Dados (Data Definition Language – DDL) que ajudam a melhorar e/ou modificar aquelas estruturas básicas. Alterando Tabelas Após criarmos e popularmos uma tabela, podemos necessitar alterar a estrutura da tabela. Para fazer isso, usamos o comando ALTER TABLE. Uma coisa deve ser lembrada: a alteração da estrutura de uma tabela pode fazer com que alguns dados sejam perdidos. Por exemplo, alterar o tipo de dados de um campo pode resultar em perda de dados ou em erros de arredondamento, dependendo do tipo de dados que está sendo usado. Também pode afetar outras partes do aplicativo que referenciem o campo alterado. Devemos ter bastante cuidado ao alterar a estrutura de uma tabela já existente e em uso. Com o comando ALTER TABLE, podemos adicionar remover ou alterar uma coluna (ou campo) e podemos adicionar ou remover uma restrição (constraint). Também podemos declarar um valor padrão para um campo. E só podemos alterar um campo de cada vez. Suponhamos que temos um banco de dados de pedidos e desejamos adicionar um campo à tabela Clientes. Para adicionar um campo usando o comando ALTER TABLE, usamos a cláusula ADD COLUMN com o nome do campo, o tipo de dados e o tamanho do tipo de dados, se requerido.
Deve-se notar que, para utilizar este método, eliminaremos todos os dados do campo. Se desejarmos preservar os dados existentes, devemos alterar o nome do campo usando o modo de criação de tabela da interface de usuário do Access ou escrever código para preservar os dados atuais em uma tabela temporária e devolve-los ao novo campo.
Note-se que o valor padrão não está entre aspas simples. Se estivesse, as aspas também seriam inseridas no registro. A palavra-chave DEFAULT também pode ser usada em um comando CREATE TABLE.
A seção a seguir discute a utilização de constraints com o comando ALTER TABLE. Para maiores informações sobre a utilização do comando ALTER TABLE, utilize o Help do Access. Restrições (Constraints) O artigo Microsoft Jet SQL Fundamental para o Access 2000 apresenta os constraints como o modo de estabelecer relacionamentos entre tabelas. Os constraints também podem ser usados para estabelecer as chaves primárias, a integridade referencial e restringir os valores que podem ser inseridos em um campo. De modo geral, os constraints podem ser utilizados para preservar a integridade e consistência dos dados em uma base de dados. Temos dois tipos de constraints: um em nível de campo, chamado constraint de campo único e outro, multi-campos ou constraint de tabela. Ambos podem ser utilizados nos comandos CREATE TABLE ou ALTER TABLE. Um constraint de campo único, também conhecido como constraint em nível de coluna, é declarado com o próprio campo, após a declaração do campo e tipo de dados. Vamos utilizar a tabela Clientes e criar uma chave primária de campo único para o campo CustomerID. Para adicionar o constraint, usamos a palavra-chave CONSTRAINT com o nome do campo: ALTER TABLE tblCustomers
ALTER COLUMN CustomerID INTEGER CONSTRAINT PK_tblCustomers PRIMARY KEY Deve-se notar que é fornecido o nome do constraint. Podemos utilizar um atalho declarando uma chave primária e deixando a cláusula CONSTRAINT totalmente de fora: ALTER TABLE tblCustomers
ALTER COLUMN CustomerID INTEGER PRIMARY KEY Entretanto, a utilização do método do atalho fará com que o Access gere aleatoriamente um nome para o constraint, o que torna difícil referenciá-lo em código. É uma boa idéia sempre nomear os constraints. Para excluir um constraint, usamos a cláusula DROP CONSTRAINT em um comando ALTER TABLE, fornecendo o nome do constraint. ALTER TABLE tblCustomers
DROP CONSTRAINT PK_tblCustomers Os constraints também podem ser utilizados para restringir os valores permitidos em um campo. Podemos restringir os valores a NOT NULL ou UNIQUE, ou podemos definir uma restrição de verificação (check constraint), que é um tipo de regra de negócio que pode ser aplicada a um campo. Digamos que desejemos restringir os valores dos campos nome e sobrenome como únicos, significando que a combinação de nome e sobrenome não pode ser a mesma em dois registros diferentes da tabela. Como esta é uma restrição multi-campos, ela deve ser declarada no nível de tabela e não no nível de campo. Usamos a cláusula ADD CONSTRAINT e definimos a lista de campos: ALTER TABLE tblCustomers
ADD CONSTRAINT CustomerNames UNIQUE ([Last Name], [First Name]) Nota: Dificilmente faríamos uma restrição que limitasse nomes próprios a valores únicos em um aplicativo real. Isto é feito aqui apenas para demonstrar a utilização de constraints. Uma restrição de verificação é uma nova característica do SQL que permite adicionarmos uma validação de dados a uma tabela criando uma expressão que pode se referir a um único campo ou a diversos campos em uma ou mais tabelas. Digamos que queremos nos assegurar que os valores inseridos em um registro de pedido sejam sempre maiores que R$0,00. Para isso, usamos uma restrição de verificação declarando a palavra-chave CHECK e a expressão de validação na cláusula ADD CONSTRAINT de um comando ALTER TABLE. ALTER TABLE tblInvoices
ADD CONSTRAINT CheckAmount CHECK (Amount > 0) Nota: A declaração CHECK CONSTRAINT só pode ser executada através do provedor Jet OLE DB e ADO, retornando um erro se usada no modo SQL da interface do usuário. Para excluir um CHECK CONSTRAINT, o comando DROP CONSTRAINT também deve ser executado através do provedor Jet OLE DB e ADO. Além disso, se definirmos uma restrição de verificação: (1) ela não aparecerá como regra de validação na interface de usuário do Access, (2) não pode definir a propriedade Texto de Validação, o que fará com que uma mensagem genérica seja apresentada na interface de usuário do Access e (3) não será possível excluir a tabela usando a interface de usuário do Access ou via código até que os constraints sejam excluídos usando um comando DROP CONSTRAINT no ADO. A expressão usada para definir uma verificação de restrição também pode se referir a mais de um campo na mesma tabela ou a campos em outras tabelas, e pode usar qualquer operação válida no Microsoft Jet SQL, como SELECT, comandos, operações matemáticas e funções agregadas. A expressão que define a restrição de verificação não pode ter comprimento maior que 64 caracteres. Digamos que queremos verificar o limite de crédito de cada cliente antes que seja incluído na tabela Customers. Usando o comando ALTER TABLE com as cláusulas ADD COLUMN e CONSTRAINT, vamos criar uma restrição que busca pelo valor na tabela CreditLimit para verificar o limite de crédito do cliente. Usamos os comandos SQL a seguir para criar a tabela tblCreditLimit, adicionar o campo CustomerLimit à tabela tblCustomers, adicionar a restrição de verificação à tabela tblCustomers e testar a verificação de restrição. CREATE TABLE tblCreditLimit (
Limit DOUBLE) INSERT INTO tblCreditLimit VALUES (100) ALTER TABLE tblCustomers ADD COLUMN CustomerLimit DOUBLE ALTER TABLE tblCustomers ADD CONSTRAINT LimitRule CHECK (CustomerLimit <= (SELECT Limit FROM tblCreditLimit)) UPDATE TABLE tblCustomers SET CustomerLimit = 200 WHERE CustomerID = 1 Note-se que, quando executamos o comando UPDATE TABLE, recebemos uma mensagem indicando que a atualização não foi bem sucedida porque violou a verificação de restrição. Se atualizarmos o campo CustomerLimit para um valor igual ou menor que 100, a atualização será bem sucedida. Atualizações e exclusões em cascata Os constraints também podem ser usados para estabelecer a integridade referencial entre tabelas do banco de dados. Ter integridade referencial significa que os dados são consistentes e não corrompidos. Por exemplo, se excluíssemos o registro de um cliente e os seus registros de pedidos continuassem no banco de dados, estes estariam inconsistentes porque teríamos registros órfãos na tabela de pedidos. A integridade referencial é estabelecida quando criamos um relacionamento entre duas tabelas. Além de estabelecer a integridade referencial, podemos assegurar que os registros nas tabelas referenciadas se mantenham sincronizados utilizando atualizações e exclusões em cascata. Por exemplo, quando as atualizações e exclusões em cascata são declaradas, ao excluirmos o registro do cliente, seus registros de pedidos são excluídos automaticamente. Para permitir atualizações e exclusões em cascata, usamos as palavras-chave ON UPDATE CASCADE e/ou ON DELETE CASCADE na cláusula CONSTRAINT de um comando ALTER TABLE. Note-se que devem ser aplicadas à chave estrangeira. ALTER TABLE tblShipping
ADD CONSTRAINT FK_tblShipping FOREIGN KEY (CustomerID) REFERENCES tblCustomers (CustomerID) ON UPDATE CASCADE ON DELETE CASCADE Chaves Estrangeiras Ao tratarmos de chaves estrangeiras, o conceito de uma chave estrangeira rápida pode ser útil. Uma chave estrangeira rápida é uma chave estrangeira sem índice. Ainda que isto possa parecer contra intuitivo, há uma explicação válida: por padrão, quando uma chave estrangeira é definida, um índice baseado na(s) coluna(s) da chave estrangeira é criado automaticamente. Em muitos casos isto melhora o desempenho ao executar operações que mantém a integridade referencial. Entretanto, se existirem muitos valores duplicados no campo da chave estrangeira, o índice de chave estrangeira vai afetar o desempenho na inclusão e exclusão de registros da tabela. Para evitar a criação automática de índices de chaves estrangeiras, usamos as palavras-chave NO INDEX na declaração da chave estrangeira. ALTER TABLE tblInvoices
ADD CONSTRAINT FK_tblInvoices FOREIGN KEY NO INDEX (CustomerID) REFERENCES tblCustomers (CustomerID) ON UPDATE CASCADE ON DELETE CASCADE Nota O comando de chave estrangeira rápida só pode ser executado com o uso do Jet OLE DB e ADO. Se usado no modo SQL da interface do usuário do Access, vai gerar uma mensagem de erro. Note-se, também, que para excluir uma chave estrangeira rápida, devemos usar o comando DROP CONSTRAINT através do provedor Jet OLE DB e ADO. Outro exemplo de situação onde uma chave estrangeira rápida seria um aplicativo de banco de dados de entrada de pedidos. Digamos que temos uma tabela chamada CustomerTypes (TiposDeClientes) que identifica o tipo de cliente que está sendo atendido, uma tabela Customers (Clientes) e uma tabela Orders (Pedidos). Digamos que temos 10 linhas na tabela CustomerTypes, 100.000 linhas na tabela Customers e 350.000 linhas na tabela Orders. Uma boa escolha para a tabela Customers seria uma chave estrangeira rápida que referenciasse a chave primária na tabela CustomerTypes. Isto porque existe um máximo de 10 valores em 100.000 linhas. Um índice, neste caso, teria pouco valor na pesquisa dos dados e seria um complicador na concorrência de registros e nas inclusões, exclusões e alterações na coluna CustomerType. Por outro lado, uma chave estrangeira rápida provavelmente não seria interessante se aplicada à coluna CustomerID na tabela Orders, pois estes valores provavelmente serão únicos, já que cada um representa um cliente diferente. Neste caso, ter a chave estrangeira indexada de modo normal traz muitas vantagens, já que é usada em junções (joins) e outros critérios de pesquisa. Nota Ainda que a maioria dos exemplos nesta seção tenha usado o comando ALTER TABLE, todos poderiam ser escritos em um comando CREATE TABLE. Para maiores informações sobre a cláusula CONSTRAINT, procure por constraints no Help do Access. Tipos de Dados Em um esforço para facilitar a atualização e transição de aplicativos Access baseados no motor de banco de dados Jet para outros, baseados no SQL Server ou MSDE, o motor de banco de dados Jet teve alterados algumas das implementações de tipos de dados, além de acrescentar alguns sinônimos de tipos de dados. As seções a seguir apresentam os tipos de dados primários do Jet e como são implementados. Tipos de Dados TEXT Um tipo de dados TEXT é o tipo de dados que estabelece um campo que pode armazenar texto, ou uma combinação de texto e números (alfanumérico), mas cujos números não são usados para cálculos. Como exemplo, temos números de telefone ou Códigos de Endereçamento Postal. Quando criamos nossas tabelas usando a interface de usuário do Access, temos dois tipos básicos de texto: TEXTO e MEMO. Quando usamos comandos SQL como CREATE TABLE e ALTER TABLE para criarmos nossas tabelas, temos diversos outros sinônimos para os tipos TEXTO e MEMO para escolher. De modo geral, campos texto podem armazenar até 255 caracteres, enquanto que os campos memo podem conter até 65.535 caracteres, mas se o campo memo não contiver dados binários, o limite é a capacidade do banco de dados (aproximadamente 2.14GB ou 1.070.000.000 caracteres Unicode). Além disso, os caracteres não utilizados de um campo texto não ocupam espaço, já que não é reservado espaço em memória para eles. A seguir temos uma tabela que lista os tipos de dados texto básicos do Jet, vários sinônimos e o número de bytes alocado para cada um deles.
O comando CREATE TABLE a seguir mostra a variedade de sinônimos do tipo de dados Texto que podem ser usados para criar uma tabela usando a interface de usuário do Modo SQL do Access. CREATE TABLE tblUITextDataTypes (
Field1_TEXT TEXT, Field2_TEXT25 TEXT(25), Field3_MEMO MEMO, Field4_CHAR CHAR, Field5_CHAR25 CHAR(25), Field6_LONGTEXT LONGTEXT, Field7_LONGCHAR LONGCHAR, Field8_ALPHA ALPHANUMERIC, Field9_ALPHA25 ALPHANUMERIC(25), Field10_STRING STRING, Field11_STRING25 STRING(25), Field12_VARCHAR VARCHAR, Field13_VARCHAR25 VARCHAR(25), Field14_NOTE NOTE) Se verificarmos a tabela tblUITextDataTypes usando a interface de usuário do Access, veremos que os sinônimos MEMO, LONGTEXT, LONGCHAR e NOTE resultam em tipo de dados MEMO. Todos os outros sinônimos resultam em tipo de dados TEXT. Para os campos com tipo de dados TEXT sem o comprimento declarado, é assumido um comprimento de 255 caracteres. O comando SQL acima também pode ser executado usando-se o provedor Jet OLE DB e ADO mas existem outras variações que só podem ser executadas através do provedor Jet OLE DB e ADO. CREATE TABLE tblCodeTextDataTypes
Field1_NTEXT NTEXT, Field2_NTEXT25 NTEXT(25), Field3_NCHAR NCHAR, Field4_NCHAR NCHAR(25), Field5_VARYING CHAR VARYING, Field6_VARYING CHAR VARYING(25), Field7_VARYING CHARACTER VARYING, Field8_VARYING CHARACTER VARYING(25), Field9_NATIONAL NATIONAL CHAR, Field10_NATIONAL NATIONAL CHAR(25), Field11_NATIONAL NATIONAL CHARACTER, Field12_NATIONAL NATIONAL CHARACTER(25), Field13_NATIONAL NATIONAL CHAR VARYING, Field14_NATIONAL NATIONAL CHAR VARYING(25), Field15_NATIONAL NATIONAL CHARACTER VARYING, Field16_NATIONAL NATIONAL CHARACTER VARYING(25)) Se verificarmos os tipos de dados de tblUITextDataTypes, através da interface de usuário do Access, veremos que apenas o tipo de dados NCHAR resultou em um campo do tipo MEMO. Todos os outros tipos de dados resultaram em campos do tipo TEXTO. Para os campos sem tamanho declarado é assumido o tamanho padrão de 255 caracteres. Nota Os tipos de dados listados no comando SQL acima só podem ser executados através do provedor Jet OLE DB e ADO. Teremos mensagens de erro se usarmos o modo SQL da interface de usuário do Access. Devemos notar, também que, se criarmos um campo com o tipo de dados TEXT através do provedor Jet OLE DB e ADO, teremos um campo MEMO, se visto através da interface do usuário do Access. Compressão Unicode Com o motor de banco de dados Microsoft Jet 4.0, todos os dados para os tipos de dados TEXT são armazenados no formato de representação de caracteres Unicode de 2 bytes. Ele substitui o conjunto de caracteres multi-byte (MBCS), usado em versões anteriores. Ainda que a representação Unicode exija mais espaço para armazenar cada caracter, as colunas com tipo de dados TEXT podem ser definidas para comprimir automaticamente os dados, se possível fazê-lo. Quando criamos tipos de dados TEXT usando o SQL, a propriedade de compressão Unicode assume Não como padrão. Para ativarmos a propriedade compressão Unicode, usamos as palavras-chave WITH COMPRESSION (ou WITH COMP) no nível de declaração do campo. O comando CREATE TABLE, a seguir, cria uma nova tabela Customers, desta vez definindo a propriedade compressão Unicode como Sim. CREATE TABLE tblCompressedCustomers (
CustomerID INTEGER CONSTRAINT PK_tblCompCustomers PRIMARY KEY, [Last Name] TEXT(50) WITH COMP NOT NULL, [First Name] TEXT(50) WITH COMPRESSION NOT NULL, Phone TEXT(10), Email TEXT(50), Address TEXT(40) DEFAULT Unknown) Note-se que as palavras-chave WITH COMPRESSION ou WITH COMP são declaradas antes das palavras-chave NOT NULL. Também podemos alterar a propriedade de compressão Unicode de um campo já existente através de um comando ALTER TABLE, como este: ALTER TABLE tblCustomers
ALTER COLUMN [Last Name] TEXT(50) WITH COMPRESSION Nota As palavras-chave WITH COMPRESSION e WITH COMP listadas no comando SQL acima só podem ser executados através do provedor Jet OLE DB e ADO. Elas resultarão em uma mensagem de erro se usadas através do modo SQL da interface de usuário do Access. Qual tipo de dados deve ser escolhido quando criamos nossas tabelas depende dos objetivos a serem alcançados pelo aplicativo. Se soubermos que nosso aplicativo vai permanecer baseado, sempre, em um banco de dados Jet, usamos os tipos de dados com os quais nos sentimos mais confortáveis. Mas, se existir a possibilidade de uma atualização para um banco de dados ODBC, como o SQL Server ou o MSDE, usamos os tipos de dados que façam com que a migração seja mais simples. Tipos de Dados NUMERIC Um tipo de dados NUMERIC estabelece um campo que pode armazenar números que podem ser utilizados em cálculos. Tipicamente o que separa os tipos de dados numéricos é o número de bytes usados para armazenar os números, o que afeta, também, a precisão do número armazenado naquele campo. Muitos dos tipos de dados do Jet SQL têm sinônimos que podem ser usados na declaração do tipo de dados. Qual deve ser usado depende do que vai acontecer com a base de dados: se ela vai permanecer no ambiente Jet ou se vai ser migrada para o ambiente de um servidor de bancos de dados, como o SQL Server. Se existe a possibilidade da migração, usamos declarações de tipos de dados que facilitem a transição. Abaixo temos uma tabela que lista os tipos NUMERIC básicos do Jet, diversos sinônimos e o número de bytes alocado para cada um.
O comando CREATE TABLE a seguir mostra a variedade de tipos numéricos que podem ser usados para criar uma tabela usando-se o modo SQL da interface do usuário do Access. CREATE TABLE tblUINumericDataTypes (
Field1_INT INT, Field2_INTEGER INTEGER, Field3_LONG LONG, Field4_INTEGER1 INTEGER1, Field5_BYTE BYTE, Field6_NUMERIC NUMERIC, Field7_REAL REAL, Field8_SINGLE SINGLE, Field9_FLOAT FLOAT, Field10_FLOAT4 FLOAT4, Field11_FLOAT8 FLOAT8, Field12_DOUBLE DOUBLE, Field13_IEEESINGLE IEEESINGLE, Field14_IEEEDOUBLE IEEEDOUBLE, Field15_NUMBER NUMBER, Field16_SMALLINT SMALLINT, Field17_SHORT SHORT, Field18_INTEGER2 INTEGER2, Field19_INTEGER4 INTEGER4) Ainda que o comando acima também possa ser executado através do provedor Jet OLE DB e ADO, existem outras variações que só podem ser executadas através dele. CREATE TABLE tblCodeNumericDataTypes (
Field1_TINYINT TINYINT, Field2_DECIMAL DECIMAL, Field3_DEC DECIMAL, Field4_DPRECISION DOUBLE PRECISION) Nota Os tipos de dados listados no comando SQL acima só podem ser executados através do provedor Jet OLE DB e ADO. Eles resultarão em erro se declarados através do modo SQL da interface de usuário do Access. Note-se, também, que, se criarmos um campo com tipo de dados NUMERIC através do modo SQL da interface de usuário do Access, ele resultará em um tipo de dados DOUBLE quando visto através da interface de usuário do Access. Mas, se criarmos o campo de tipo de dados NUMERIC através do provedor Jet OLE DB e ADO, ele resultará em um campo do tipo DECIMAL quando visto através da interface de usuário do Access. Com o novo tipo de dados DECIMAL, podemos indicar a precisão e a escala do número. A precisão é o número total de dígitos que o campo pode conter, enquanto que a escala determina quantos destes dígitos estarão à direita do ponto decimal. Para a precisão, o padrão é 18, sendo 28 o valor máximo permitido. Para a escala, o padrão é zero e 28 é o número máximo permitido. CREATE TABLE tblDecimalDataTypes (
DefaultType DECIMAL, SpecificType DECIMAL(10,5)) Tipo de Dados CURRENCY O tipo de dados CURRENCY (MOEDA) é usado para armazenar dados numéricos que contenham até 15 dígitos à esquerda do ponto decimal e até 4 dígitos à direita. Ele usa 8 bytes de memória para armazenamento e seu único sinônimo é MONEY. O comando CREATE TABLE a seguir mostra como o tipo de dados CURRENCY pode ser usado para criar uma tabela através do modo SQL da interface do usuário ou através do provedor Jet OLE DB e ADO. CREATE TABLE tblCurrencyDataTypes (
Field1_CURRENCY CURRENCY, Field2_MONEY MONEY) Tipo de Dados BOOLEAN Os tipos de dados BOOLEAN (SIM/NÃO) são tipos lógicos, que resultam em valores Verdadeiro ou Falso. Eles utilizam um byte de memória para armazenamento e seus sinônimos são BIT, LOGICAL, LOGICAL 1 e YSENO. Um valor Verdadeiro é igual a -1 e um valor Falso é igual a 0 (zero). O comando CREATE TABLE abaixo mostra os diferentes sinônimos que podem ser usados para criar um campo do tipo de dados BOOLEAN através do provedor Jet OLE DB e ADO. CREATE TABLE tblUIBooleanDataTypes (
Field1_BIT BIT, Field2_LOGICAL LOGICAL, Field3_LOGICAL1 LOGICAL1, Field4_YESNO YESNO) Tipo de Dados BINARY O tipo de dados BINARY é utilizado para armazenar uma pequena quantidade de dados no seu formato binário nativo. Ele utiliza 1 byte de memória para cada caracter armazenado e podemos, opcionalmente, especificar o número de bytes a serem alocados. Se o número de bytes não for especificado, o padrão é 510 bytes, que é o número máximo permitido. Seus sinônimos são BINARY, VARBINARY e BINARY VARYING. O tipo de dados BYNARY não está disponível através da interface de usuário do Access. O comando CREATE TABLE, a seguir, mostra a variedade de tipos de dados BINARY que podem ser usados para criar uma tabela através do modo SQL da interface de usuário. CREATE TABLE tblUIBinaryDataTypes (
Field1_BINARY BINARY, Field2_BINARY250 BINARY(250), Field3_VARBINARY VARBINARY, Field4_VARBINARY250 VARBINARY(250)) Ainda que o comando SQL acima possa ser utilizado através do provedor Jet OLE DB e ADO, temos outros sinônimos do tipo da dados binário que só podem ser executados através do provedor Jet OLE DB e ADO, como isto: CREATE TABLE tblCodeBinaryDataTypes (
Field1_BVARYING BINARY VARYING, Field2_BVARYING250 BINARY VARYING(250)) Tipos de Dados OLEOBJECT Os tipos de dados OLEOBJECT são usados para armazenar objetos binários grandes, como documentos do Word ou planilhas do Excel. O número de bytes não é especificado e o tamanho máximo é 2.14 Gb. Seus sinônimos são IMAGE, LONGBINARY, GENERAL, e OLEOBJECT. O comando CREATE TABLE a seguir mostra o tipo de dados OLEOBJECT que pode ser usado para criar uma tabela usando o modo SQL da interface de usuário do Access ou através do provedor Jet OLE DB e ADO. CREATE TABLE tblImageDataTypes (
Field1_IMAGE IMAGE, Field2_LONGBINARY LONGBINARY, Field3_GENERAL GENERAL, Field4_OLEOBJECT OLEOBJECT) Tipo de Dados DATETIME O tipo de dados DATETIME (Data/Hora) é usado para armazenar datas, horas e combinação de valores de data e hora para os anos 100 a 9999. ele usa 8 bytes de memória para armazenamento e seus sinônimos são DATE, TIME, DATETIME, e TIMESTAMP. O comando CREATE TABLE abaixo mostra os sinônimos do tipo de dados DATETIME que podem ser usados para criar uma tabela usando o modo SQL da interface de usuário do Access ou através do provedor Jet OLE DB e ADO. CREATE TABLE tblDateTimeDataTypes (
Field1_DATE DATE, Field2_TIME TIME, Field3_DATETIME DATETIME, Field4_TIMESTAMP TIMESTAMP) Tipo de Dados COUNTER O tipo de dados COUNTER (AUTONUMERAÇÂO) é usado para armazenar valores inteiros longos que são incrementados automaticamente sempre que um novo registro é inserido em uma tabela. Com o tipo de dados COUNTER podemos, opcionalmente, criar um valor inicial e um valor de incremento. O valor inicial é o valor de partida a ser introduzido no campo na inserção do primeiro registro na tabela. O valor de incremento é o número a ser adicionado ao último valor do contador para estabelecer seu próximo valor. Se o valor inicial e o valor de incremento não forem especificados, ambos assumem o valor 1. podemos ter apenas um campo do tipo COUNTER em uma tabela, e os sinônimos são COUNTER, AUTOINCREMENT e IDENTITY. O comando CREATE TABLE a seguir mostra os sinônimos do tipo de dados COUNTER que podem ser usados para criar uma tabela através do modo SQL da interface de usuário do Access. CREATE TABLE tblUICounterDataTypes (
Field1 COUNTER, Field2 TEXT(10)) Note-se que, como os valores inicial e de incremento não foram determinados, assumem o valor 1. outra forma de declarar o tipo de dados COUNTER é utilizar a palavra-chave AUTOINCREMENT: CREATE TABLE tblUICounterDataTypes (
Field1 AUTOINCREMENT(10,5), Field2 TEXT(10)) Desta vez os valores inicial e de incremento foram especificados. O valor inicial será 10 e será incrementado em 5. Ainda que o comando SQL acima também possa ser executado através do provedor Jet OLE DB e ADO, há uma variação do tipo de dados COUNTER que só pode ser executado através dele. A palavra-chave IDENTITY também pode ser usada para declarar um tipo de dados COUNTER, sendo compatível com o tipo de dados IDENTITY do SQL Server. CREATE TABLE tblCodeCounterDataTypes
Field1_IDENTITY IDENTITY(10,5), Field2 TEXT(10)) Os valores inicial e de incremento podem ser alterados através de um comando ALTER TABLE, e todas a s novas linhas inseridas após a alteração serão baseadas nestes novos valores. Como, normalmente, os tipos de dados COUNTER são usados como chaves primárias, que deve ser única para cada linha, se o valor inicial e de incremento forem alterados poderemos gerar valores duplicados para a chave primária, causando erros. ALTER TABLE tblUICounterDataTypes
ALTER COLUMN Field1 COUNTER(10,10) Nota Não podemos usar o comando ALTER TABLE para alterar o tipo de dados de uma coluna para COUNTER se a coluna existente já contiver dados. Nas versões anteriores do banco de dados Jet, o valor inicial podia ser reinicializado ao valor máximo do contador após a compactação do banco de dados. Isto ainda acontece no Jet 4.0, desde que os valores inicial e de incremento sejam o padrão 1. se forem especificados valores diferentes para o valor inicial e de incremento, a compactação do banco de dados não vai reinicializar o valor inicial. Variável @@IDENTITY A variável @@IDENTITY é uma variável global do SQL que pode ser usada para recuperar o último valor inserido em uma coluna do tipo de dados COUNTER. Não podemos especificar o nome de uma tabela quando recuperamos o valor de @@IDENTITY. O valor retornado é sempre o valor da última tabela com um campo do tipo COUNTER que tenha tido um registro inserido por meio de código. Usamos o comando SELECT para recuperar o valor de @@IDENTITY. SELECT @@IDENTITY Para adicionar um valor àquele contido na variável @@IDENTITY, devemos colocar a variável entre colchetes: SELECT [@@IDENTITY] + 1 Nota A variável @@IDENTITY apresentada nos comandos SQL acima só pode ser executada através do provedor Jet OLE DB e ADO. Ela resultará em um valor 0 se usada através do modo SQL da interface de usuário do Access. Além disso, a variável só recebe um valor quando os registros são inseridos através de código de programação. Se um registro for inserido através da interface do usuário, seja por meio de folha de dados, formulários ou comandos SQL na janela modo SQL da interface do usuário, a variável @@IDENTITY vai devolver um valor 0. Por esta razão, o valor de @@IDENTITY só está correto imediatamente após a inclusão de um registro por meio de código. Para maiores informações sobre os tipos de dados, procure por tipos de dados Jet SQL no Help do Access. Linguagem de Manipulação de Dados Intermediária O artigo Microsoft Jet SQL Fundamental para Access 2000 mostrou como usar o SQL para recuperar e gerenciar a informação armazenada em um banco de dados. Nas próximas seções deste artigo vamos discutir os comandos da Linguagem de Manipulação de Dados (Data Manipulation Language – DML) intermediários, que permitem um controle ainda maior de como as informações podem ser recuperadas e manipuladas. Predicados Um predicado é uma cláusula SQL que qualifica um comando SELECT, similar à cláusula WHERE, exceto que os predicados são declarados antes da lista de colunas. Os predicados podem restringir ainda mais o conjunto de registros a serem recuperados e, em alguns casos, filtrar quaisquer dados duplicados que possam ocorrer. ALL A palavra chave ALL é o padrão usado quando nenhum predicado é declarado em um comando SQL. Ela significa, simplesmente, que serão recuperados todos os registros que estejam de acordo com os critérios de qualificação estabelecidos no comando SQL. Voltando à nossa base de dados de pedidos, vamos selecionar todos os registros da tabela Clientes. SELECT *
FROM tblCustomers Vemos que, mesmo não declarando a palavra chave ALL, ele é um predicado padrão. Poderíamos escrever o comando de outra forma: SELECT ALL *
FROM tblCustomers DISTINCT A palavra chave DISTINCT é usada para controlar como são trabalhados os valores duplicados em um conjunto resultante de registros. Baseando-se na(s) coluna(s) especificadas na lista de campos, as linhas que têm valores duplicados nos campos não vão aparecer. Se mais de uma coluna for especificada, é usada a combinação de todas as colunas como filtro. Por exemplo, se pesquisarmos a tabela Customers procurando por sobrenomes diferentes, apenas os nomes diferentes serão devolvidos; qualquer duplicação resultará em apenas um registro sendo mostrado no conjunto resultante. SELECT DISTINCT [Last Name]
FROM tblCustomers É importante notar que o conjunto resultante de uma consulta que utilize a palavra chave DISTINCT não pode ser atualizada; ela é apenas leitura. DISTINCTROW A palavra chave DISTINCTROW é similar à palavra chave DISTINCT, exceto que se baseia em linhas inteiras e não em campos individuais. É útil apenas quando baseamos a consulta em diversas tabelas e, apenas, quando selecionamos alguns campos de algumas, mas não todas, as tabelas. Se basearmos nossa consulta em uma tabela ou selecionarmos campos de todas as tabelas, a palavra chave DISTINCTROW age, essencialmente, como a palavra chave ALL. Por exemplo, no nosso banco de dados de Pedidos, cada cliente pode ter a) nenhum pedido, b) um pedido e c) diversos pedidos. Queremos descobrir quantos clientes tem um ou mais pedidos. Usamos a palavra chave DISTINCTROW para determinar nossa lista de clientes. SELECT DISTINCTROW [Last Name], [First Name]
FROM tblCustomers INNER JOIN tblInvoices ON tblCustomers.CustomerID = tblInvoices.CustomerID Se não usássemos a palavra chave DISTINCTROW, teríamos uma linha para cada pedido de cada cliente. (A declaração INNER JOIN será discutida mais adiante). TOP A palavra chave TOP é usada para retornar certo número de linhas que estejam no topo ou no piso de uma faixa especificada pela cláusula ORDER BY. A clausula ORDER BY é usada para classificar as linhas em ordem ascendente ou descendente. Se existirem valores iguais, a palavra chave TOP vai apresentar todos os registros que tenham valores iguais. Digamos que queremos determinar os três pedidos de valor mais alto no nosso banco de dados de pedidos. O comando ficaria assim: SELECT TOP 3 InvoiceDate, Amount
FROM tblInvoices ORDER BY Amount DESC Podemos, também, utilizar a palavra chave PERCENT, opcional, em conjunto com TOP para apresentar uma porcentagem de linhas que estejam no topo ou no piso da faixa especificada por uma cláusula ORDER BY. O código ficaria assim: SELECT TOP 25 PERCENT InvoiceDate, Amount
FROM tblInvoices ORDER BY Amount DESC Nota Se não for especificada uma cláusula ORDER BY, a palavra chave TOP não será significativa, devolvendo uma amostra aleatória das linhas. Para maiores informações sobre predicados, consulte all, distinct predicates, no Help do Access. Expressões SQL Uma expressão SQL é uma string usada como parte de um comando SQL que se resolve em um valor único. Podemos usar qualquer combinação de operadores, constantes, valores literais, funções, nomes de campos, controle ou propriedades para criar as expressões SQL. O artigo Microsoft Jet SQL Fundamental para Access 2000 descreve como usar expressões na cláusula WHERE para qualificar os comandos SQL e, nas próximas seções deste artigo, examinaremos os diferentes operadores SQL que podem ser usados em expressões. Operador IN O operador IN é usado para determinar se o valor de uma expressão é igual a algum dos valores especificados em uma lista. Se a expressão concordar com um dos valores da lista, o operador IN devolve Verdadeiro. Se não encontrado, o operador IN devolve Falso. Suponhamos que queremos encontrar todos os endereços de remessa localizados nos estados de Washington e Geórgia. Poderíamos escrever um comando SQL com uma longa cláusula WHERE usando o operador lógico AND. Usar o operador IN fará com que o comando fique mais simples: SELECT *
FROM tblShipping WHERE State IN ('WA','GA') Usando o operador lógico NOT, podemos verificar o oposto do operador IN. Este comando devolve todos os endereços de remessa que não sejam do estado de Washington: SELECT *
FROM tblShipping WHERE State NOT IN ('WA') Operador BETWEEN O operador BETWEEN é utilizado para determinar se o valor de uma expressão está contido numa faixa especificada de valores. Se o valor da expressão estiver na faixa especificada, incluindo os valores inicial e final, o operador BETWEEN retorna Verdadeiro. Se o valor não estiver na faixa especificada, o operador retorna Falso. Suponhamos que queremos encontrar todos os pedidos que tenham um valor entre $50 e $100. Usamos o operador BETWEEN na cláusula WHERE com a palavra chave AND para especificar a faixa. SELECT *
FROM tblInvoices WHERE Amount BETWEEN 50 AND 100 Se usarmos o operador lógico NOT, verificaremos o oposto do operador BETWEEN para localizar os pedidos que estejam fora da faixa especificada. SELECT *
FROM tblInvoices WHERE Amount NOT BETWEEN 50 AND 100 Note-se que a faixa pode estar em ordem inversa e chegaremos aos mesmos resultados (BETWEEN 100 AND 50), mas muitas bases de dados concordantes com ODBC exigem que a faixa siga o método valor inicial – valor final. Se pretendermos atualizar nosso banco de dados para uma tecnologia concordante com ODBC, devemos usar sempre o método valor inicial – valor final. Operador LIKE O operador LIKE é utilizado para determinar se o valor de uma expressão pode ser comparado com um exemplo. Um exemplo pode ser uma string inteira ou 24-Nov-2005 19:54nga. Usando o operador LIKE, podemos pesquisar um campo em um conjunto resultante e encontrar todos os valores que estejam de acordo com o exemplo especificado. SELECT *
FROM tblCustomers WHERE [Last Name] LIKE 'Johnson' Para retornar todos os clientes cujos sobrenomes comecem pela letra J, usamos o caracter coringa asterisco (*). SELECT *
FROM tblCustomers WHERE [Last Name] LIKE 'J*' Usando o operador lógico NOT, podemos verificar o oposto do operador LIKE e excluir todos os Johnsons da lista. SELECT *
FROM tblCustomers WHERE [Last Name] NOT LIKE 'Johnson' Temos uma variedade de caracteres coringa que podemos usar com o operador LIKE, como mostrado na tabela abaixo.
Nota Os caracteres coringa "%" e "_" na tabela acima só podem ser utilizados através do provedor Jet OLE DB e ADO. Fornecerão um conjunto resultante vazio se usado através da interface de usuário do Access. Para maiores informações sobre os caracteres coringa, procure por caracteres coringa ou wildcard characters no Help do Access. Operador IS NULL Um valor nulo é aquele que indica que os dados estão ausentes ou são desconhecidos. O operador IS NULL é usado para determinar se o valor de uma expressão é igual ao valor nulo. SELECT *
FROM tblInvoices WHERE Amount IS NULL Adicionando-se o operador lógico NOT, podemos verificar o oposto do operador IS NULL. Neste caso o comando não mostrará os pedidos com valores desconhecidos ou nulos. SELECT *
FROM tblInvoices WHERE Amount IS NOT NULL Comando SELECT INTO O comando SELECT INTO, também conhecido como consulta criar tabela, pode ser usado para criar uma nova tabela a partir de uma ou mais tabelas pré-existentes. A tabela produzida pode ser baseada em qualquer comando SELECT válido. O comando SELECT INTO pode ser usado para arquivar registros, criar tabelas de backup ou criar novas tabelas em uma base de dados externa. Quando usamos o comando SELECT INTO para criar uma nova tabela, todos os campos da nova tabela herdam os tipos de dados das tabelas originais. Entretanto, nenhuma outra propriedade da tabela, como chaves primárias ou índices, são criados na nova tabela. Estas propriedades, é claro, podem ser adicionadas com o uso do comando ALTER TABLE logo após a criação da tabela. Para criar uma nova tabela, usamos o comando SELECT INTO com uma lista de campos para as colunas que desejamos incluir na tabela, um nome para a nova tabela e fornecemos a fonte dos dados na cláusula FROM. SELECT *
INTO tblNewCustomers FROM tblCustomers Para especificar alguns campos para a nova tabela, substituímos o asterisco pelos nomes de campos originais na lista de campos, e usamos a palavra chave AS para dar nomes às colunas da nova tabela. SELECT [First Name] & ' ' & [Last Name] AS FullName
INTO tblNewCustomerNames FROM tblCustomers Para criarmos uma nova tabela em uma base de dados externa, usamos a palavra chave IN. Se a base de dados externa não existir, será retornada uma mensagem de erro. SELECT *
INTO tblNewCustomers IN 'C:\Customers.mdb' FROM tblCustomers Subconsultas Uma subconsulta é um comando SELECT usado dentro de outro comando SELECT, SELECT INTO, INSERT INTO, DELETE ou UPDATE. Ela pode ajudar a qualificar ainda mais o conjunto resultante baseado nos resultados de outro conjunto resultante. Isto é chamado aninhamento e, como uma subconsulta é um comando SELECT, podemos aninhar uma subconsulta dentro de outra subconsulta. Quando usamos uma subconsulta em um comando SQL, ela pode ser parte da lista de campos, da cláusula WHERE ou da cláusula HAVING. Temos três formatos básicos de subconsultas, e cada um deles usa um tipo diferente de predicado. Subconsultas IN A subconsulta IN é usada para verificar o valor de uma coluna específica contra uma lista de valores de uma coluna em outra tabela ou consulta. A limitação é que só pode devolver uma única coluna da outra tabela. Se retornar mais de uma coluna, um erro será gerado. Usando o banco de dados de pedidos como exemplo, vamos escrever um comando SQL que devolve uma lista de todos os clientes que têm pedidos. SELECT *
FROM tblCustomers WHERE CustomerID IN (SELECT CustomerID FROM tblInvoices) Usando o operador lógico NOT, podemos verificar o oposto na subconsulta IN e gerar uma lista com os clientes que não têm pedidos. SELECT *
FROM tblCustomers WHERE CustomerID NOT IN (SELECT CustomerID FROM tblInvoices) Subconsultas ANY/SOME/ALL Os predicados de subconsultas ANY (qualquer), SOME (algum) e ALL (todos) são usados para comparar registros da consulta principal com múltiplas linhas da subconsulta. Os predicados ANY e SOME são sinônimos e podem ser usados alternativamente. Usamos os predicados ANY e SOME quando desejamos recuperar, na consulta principal, o conjunto de registros que satisfaçam à comparação com qualquer dos registros da subconsulta. O predicado é usado imediatamente antes do parêntese que abre a subconsulta. SELECT *
FROM tblCustomers WHERE CustomerID = ANY (SELECT CustomerID FROM tblInvoices) Note-se que o conjunto resultante devolvido pelo comando SQL acima é o mesmo que o devolvido pelo exemplo da subconsulta IN. o que faz com que os predicados ANY e SOME sejam diferentes é eles também poderem ser usados em conjunto com operadores relacionais diferentes de Igual (=), tais como Maior Que (>) ou Menor Que (<). SELECT *
FROM tblCustomers WHERE CustomerID > ANY (SELECT CustomerID FROM tblInvoices) Quando desejamos recuperar os registros, pela consulta principal, que atendam à comparação com todos os registros da subconsulta, usamos o predicado ALL. SELECT *
FROM tblCustomers WHERE CustomerID > ALL (SELECT CustomerID FROM tblInvoices) Subconsulta EXISTS O predicado EXISTS é usado em subconsultas para verificar a existência de valores em um conjunto resultante. Em outras palavras, se a subconsulta não devolver nenhuma linha, a comparação é Falsa. Se ela retornar uma ou mais linhas, a comparação é Verdadeira. SELECT *
FROM tblCustomers AS A WHERE EXISTS (SELECT * FROM tblInvoices WHERE A.CustomerID = tblInvoices.CustomerID) Note-se que, no comando SQL acima, é usado um alias na tabela tblCustomers. Isso é feito para que possamos referenciá-lo depois pela subconsulta. Quando uma subconsulta é vinculada à principal desta forma, ela e chamada de consulta correlacionada. Usando o operador lógico NOT, podemos verificar o oposto da subconsulta EXISTS para obter um conjunto resultante dos clientes que não têm nenhum pedido. SELECT *
FROM tblCustomers AS A WHERE NOT EXISTS (SELECT * FROM tblInvoices WHERE A.CustomerID = tblInvoices.CustomerID) Para maiores informações sobre subconsultas, procure, no Help do Access, por subconsultas SQL ou SQL subqueries. Uniões (Joins) Em um sistema de banco de dados relacional como o Access, muitas vezes necessitamos extrair informações de mais de uma tabela de cada vez. Isto pode ser conseguido utilizando um comando JOIN SQL. Um comando JOIN nos permite recuperar registros de tabelas que tenham relacionamentos definidos, sejam eles um-para-um, um-para-muitos ou muitos-para-muitos. INNER JOINs O INNER JOIN, também conhecido como equi-join, é o tipo de união mais usado. Esta união é usada para recuperar linhas de duas ou mais tabelas vinculando o valor de um campo comum entre as tabelas. Os campos a serem vinculados devem ter tipos de dados similares e não podem ser do tipo MEMO ou OLEOBJECT. Para criar um comando INNER JOIN, use as palavras chave INNER JOIN na cláusula FROM de um comando SELECT. Vamos usar o INNER JOIN para criar um conjunto resultante de todos os clientes que tenham pedidos e as datas e valores de tais pedidos. SELECT [Last Name], InvoiceDate, Amount
FROM tblCustomers INNER JOIN tblInvoices ON tblCustomers.CustomerID=tblInvoices.CustomerID ORDER BY InvoiceDate Note-se que os nomes das tabelas estão separados pelas palavras-chave INNER JOIN e que a comparação relacional está após a palavra chave ON. Para as comparações relacionais, podemos usar, também, os operadores <, >, <=, >= ou <>. Podemos usar, ainda, a palavra chave BETWEEN. Devemos notar, além disso, que os campos ID de ambas as tabelas são usados apenas na comparação relacional, não fazendo parte do conjunto resultante. Para qualificar ainda mais o comando SELECT, podemos usar uma cláusula WHERE após a comparação de vinculação na cláusula ON. No exemplo a seguir, reduzimos o conjunto resultante para incluir apenas os pedidos feitos após 01 de Janeiro de 1998. SELECT [Last Name], InvoiceDate, Amount
FROM tblCustomers INNER JOIN tblInvoices ON tblCustomers.CustomerID=tblInvoices.CustomerID WHERE tblInvoices.InvoiceDate > #01/01/1998# ORDER BY InvoiceDate Em casos onde seja necessário vincular mais de uma tabela, podemos aninhar as cláusulas INNER JOIN. Neste exemplo, vamos utilizar um comando SELECT criado anteriormente para gerar nosso conjunto resultante, mas vamos incluir a cidade e o estado para cada cliente adicionando um INNER JOIN para a tabela tblShipping. SELECT [Last Name], InvoiceDate, Amount, City, State
FROM (tblCustomers INNER JOIN tblInvoices ON tblCustomers.CustomerID=tblInvoices.CustomerID) INNER JOIN tblShipping ON tblCustomers.CustomerID=tblShipping.CustomerID ORDER BY InvoiceDate Note that the first JOIN clause is enclosed in parentheses to keep it logically separated from the second JOIN clause. It is also possible to join a table to itself by using an alias for the second table name in the FROM clause. Let's suppose that we want to find all customer records that have duplicate last names. We do this by creating the alias "A" for the second table and checking for first names that are different. SELECT tblCustomers.[Last Name],
tblCustomers.[First Name] FROM tblCustomers INNER JOIN tblCustomers AS A ON tblCustomers.[Last Name]=A.[Last Name] WHERE tblCustomers.[First Name]<>A.[First Name] ORDER BY tblCustomers.[Last Name] OUTER JOINs SELECT [Last Name] & ', ' & [First Name] AS Name,
IIF(Sum(Amount) IS NULL,'NONE',Sum(Amount)) AS Total FROM tblCustomers LEFT OUTER JOIN tblInvoices ON tblCustomers.CustomerID=tblInvoices.CustomerID GROUP BY [Last Name] & ', ' & [First Name] Temos algumas coisas diferentes no comando SQL acima. A primeira é a utilização do caracter de concatenação de strings “&”. Este operador nos permite unir dois ou mais campos como uma string. A segunda é o se imediato (IIF), que verifica se o total é nulo. Se for, o comando devolve a palavra “NONE”. Se o total não é nulo, é devolvido o valor. A última coisa é a cláusula OUTER JOIN. O uso de LEFT OUTER JOIN preserva as linhas da tabela da esquerda, de modo que vemos todos os clientes, mesmo aqueles que não têm nenhum pedido. Os OUTER JOINS podem ser aninhados em INNER JOINS em relacionamentos multi tabelas, mas os INNER JOINs não podem ser aninhados dentro de OUTER JOINs. Produto Cartesiano Um termo que surge muitas vezes durante a discussão sobre JOINs é produto Cartesiano. Um produto Cartesiano é definido como “todas as possíveis combinações de todas as linhas em todas as tabelas”. Por exemplo, se vinculássemos duas tabelas sem especificarmos nenhum tipo de qualificação ou tipo de vinculação, teríamos um produto Cartesiano. SELECT *
FROM tblCustomers, tblInvoices Isto não é algo interessante, principalmente com tabelas que contenham centenas ou milhares de registros. Podemos evitar a criação de produtos Cartesianos qualificando SEMPRE as vinculações. Operador UNION Ainda que o operador UNION, também conhecido como consulta união, não seja, tecnicamente, um JOIN, está incluído aqui porque envolve a combinação de dados de diversas fontes de dados em um conjunto resultante, o que é similar a alguns tipos de JOINs. O operador UNION é usado para juntar dados de tabelas, comandos SELECT ou consultas, deixando de fora quaisquer linhas duplicadas. Ambas as fontes de dados devem ter o mesmo número de campos, mas os campos, não necessariamente devem ter o mesmo tipo de dados. Suponhamos que temos uma tabela de funcionários (Employees) com a mesma estrutura de uma tabela de clientes (Customers) e desejamos construir uma lista de nomes e endereços de e-mail combinando ambas as tabelas. SELECT [Last Name], [First Name], Email
FROM tblCustomers UNION SELECT [Last Name], [First Name], Email FROM tblEmployees Se quiséssemos recuperar todos os campos de ambas as tabelas, poderíamos usar a palavra chave TABLE. TABLE tblCustomers
UNION TABLE tblEmployees O operador UNION não vai mostrar nenhum registro que seja duplicata idêntica em ambas as tabelas, mas isso pode ser superado usando o predicado ALL após a palavra chave UNION. SELECT [Last Name], [First Name], Email
FROM tblCustomers UNION ALL SELECT [Last Name], [First Name], Email FROM tblEmployees Comando TRANSFORM Mesmo o comando TRANSFORM, também conhecido como consulta de referência cruzada, também não sendo considerado uma vinculação (join), está incluído aqui pois envolve a combinação de dados de diversas fontes em um conjunto resultante, o que é similar a diversos tipos de vinculação. Um comando TRANSFORM é usado para calcular a soma, a média, a contagem ou outro tipo de total de agregação em registros. A informação é, então, mostrada no formato de grade ou planilha com os dados agrupados tanto vertical (linhas) quanto horizontalmente (colunas). O formato geral de um comando TRANSFORM é: TRANSFORM aggregating function
SELECT statement PIVOT column heading field Suponhamos que queremos construir uma folha de dados que mostra o total de pedidos para cada cliente em uma base anual. Os títulos verticais serão os nomes dos clientes e os horizontais, os anos. Vamos modificar o comando SQL acima para atender as necessidades. TRANSFORM
IIF(Sum([Amount]) IS NULL,'NONE',Sum([Amount])) AS Total SELECT [Last Name] & ', ' & [First Name] AS Name FROM tblCustomers LEFT JOIN tblInvoices ON tblCustomers.CustomerID=tblInvoices.CustomerID GROUP BY [Last Name] & ', ' & [First Name] PIVOT Format(InvoiceDate, 'yyyy') IN ('1996','1997','1998','1999','2000')
Código Inline Private Sub cmdBinary_Click()
Dim conDatabase As ADODB.Connection Dim SQL As String On Error GoTo Error_Handler Set conDatabase = Application.CurrentProject.Connection 'NOTE: Fields 1 through 4 can be created through both 'SQL View and the Jet OLEDB Provider. 'Fields 5 and 6 can only be created through the 'Jet OLE DB provider. SQL = "CREATE TABLE tblCodeBinaryDataTypes (" & _ "Field1_BINARY BINARY, " & _ "Field2_BINARY250 BINARY(250), " & _ "Field3_VARBINARY VARBINARY, " & _ "Field4_VARBINARY250 VARBINARY(250), " & _ "Field5_BVARYING BINARY VARYING, " & _ "Field6_BVARYING250 BINARY VARYING(250))" conDatabase.Execute SQL MsgBox "The BINARY data types table has been created!" conDatabase.Close Set conDatabase = Nothing Exit Sub Error_Handler: MsgBox Err.Description, vbInformation End Sub Após a execução de um comando DDL, devemos abrir o objeto de banco de dados afetado por ele e verificar as alterações que foram feitas. Se o comando DDL afeta o relacionamento entre tabelas, é só abrir a janela Relacionamentos para ver as alterações. Vamos ver, por exemplo, o botão de comando Alter Table w/ Fast Foreign Key, no formulário Intermediate DDL Statements. 1. Abra o banco de dados acIntSQL. 2. Verifique se as tabelas tblCustomers e tblInvoices foram criadas. Selecione Formulário na barra Objetos da janela Banco de Dados. Selecione o formulário Intermediate DDL Statements e clique no botão Design na barra de ferramentas da janela Banco de dados. No formulário Intermediate DDL Statements, clique com o botão direito do mouse no botão de comando Alter Table w/ Fast Foreign Key e selecione Construir evento… no menu popup. Isto vai abrir o ambiente de desenvolvimento VBA e a janela de código deve conter o sub procedimento cmdFastKey_Click. 3. Examine o comando SQL passado para a variável SQL. SQL = "ALTER TABLE tblInvoices " & _
"ADD CONSTRAINT FK_tblInvoices " & _ "FOREIGN KEY NO INDEX (CustomerID) REFERENCES " & _ "tblCustomers (CustomerID) " & _ "ON UPDATE CASCADE " & _ "ON DELETE CASCADE" Note que a declaração DDL está alterando a tabela tblInvoices e adicionando um constraint de chave estrangeira rápida. Ela também estabelece a consistência de dados entre tblInvoices e tblCustomers com as cláusulas CASCADE. 4. Feche o ambiente de desenvolvimento VBA. 5. Feche o formulário Intermediate DDL Statements. No menu Ferramentas, selecione Relacionamentos… para abrir a janela de Relacionamentos; Dê um duplo clique na ligação entre tblCustomers e tblInvoices para abrir a caixa de diálogo Editar relacionamentos. 6. Note que as opções Propagar atualização e propagar exclusão não estão selecionados. 7. Feche a caixa de diálogo. 8. Com a ligação ainda selecionada, tecle Del ou Delete para excluir a ligação. 9. Feche a janela de relacionamentos. Abra o formulário Intermediate DDL Statements. Clique no botão Alter Table w/ Fast Foreign Key para recriar o relacionamento de chave estrangeira. 10. Feche o formulário Intermediate DDL Statements. Seguindo os passos apresentados acima, abra a caixa de diálogo Editar relacionamento para a ligação recém criada. 11. Note que as opções propagar atualização e propagar exclusão agora estão marcadas. Comandos DML Intermediários O banco de dados acIntSQL contém muitos exemplos de comandos da Linguagem de Manipulação de Dados (DML) que podem ser usados para recuperar dados, e a maioria deles estão implementados como consultas. Os únicos comandos implementados como SQL inline estão no formulário Intermediate DML Statements. Os três exemplos de DML no formulário tratam da utilização dos caracteres coringa “_” e “%” em cláusulas LIKE e com a criação de uma tabela em um banco de dados externo com a utilização do comando SELECT INTO. Duas das consultas salvas no banco de dados acIntSQL são comandos DML que executam ações semelhantes à DDL. São declarações SELECT INTO que recuperam dados de tabelas existentes e criam novas tabelas usando estes dados. Nestes exemplos aparecerá uma mensagem solicitando que as tabelas resultantes sejam excluídas, se já existirem. O botão de comando Create Customers Database no formulário Intermediate DML Statements apresenta uma utilização interessante do comando SELECT INTO. A seguir está o código do sub procedimento para o botão de comando. Private Sub cmdCreateDB_Click()
Dim conCatalog As ADOX.Catalog Dim conDatabase As ADODB.Connection Dim SQL As String Dim sDBName As String On Error GoTo Error_Handler 'Inicializa os objetos e variáveis. Set conDatabase = Application.CurrentProject.Connection Set conCatalog = New ADOX.Catalog sDBName = "C:\Customers.mdb" 'Cria o banco de dados Customers. conCatalog.Create "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=" & sDBName 'Executa o comando DML para construir a tabela Customers. SQL = "SELECT * INTO tblCustomers IN '" & sDBName & _ "'" & "FROM tblCustomers" conDatabase.Execute SQL MsgBox "The new CUSTOMERS database has been created " & _ "as " & sDBName & ".", vbInformation conDatabase.Close Set conDatabase = Nothing Set conCatalog = Nothing Exit Sub Error_Handler: MsgBox Err.Description, vbInformation End Sub Se o banco de dados Customers já existir, o código vai apresentar uma mensagem de erro dizendo que o banco de dados não pode ser criado. Vamos acompanhar o código para ver o que ele faz. 1. Verifique se já não existe, no seu drive C:, o banco de dados Customers.mdb. Se existir, delete-o. 2. Abra o banco de dados acIntSQL.mdb. 3. Verifique se a tabela tblCustomers foi criada e se contém dados. Selecione Formulários na barra Objetos da janela de Banco de dados. Selecione o formulário Intermediate DML Statements e clique no botão Abrir na barra de ferramentas da janela de Banco de dados. Clique no botão Create Customers Database para criar o novo banco de dados. 4. Abra o Windows Explorer e veja o conteúdo do seu drive C:. o Banco de dados Customers.mdb deve ter sido criado. 5. Dê um duplo clique no banco de dados Customers.mdb para iniciar uma nova instância do Access. 6. Abra a tabela tblCustomers. Note que ela contém os mesmos dados da tabela tblCustomers do banco de dados acIntSQL. O código de exemplo de criação de um novo banco de dados usa a biblioteca de objetos ADOX para criar um banco de dados Access através do provedor Jet OLE DB. A utilização da biblioteca de objeto ADOX está além do âmbito deste artigo. Para maiores informações, procure por “Microsoft ActiveX Data Objects (ADO)” na aba Conteúdo do Help do Access 2000 e expanda o conteúdo até encontrar “Microsoft ADO Extensions for DDL and Security (ADOX) Programmer’s Reference”. Um Último Comentário Além de mostrarmos como executar diversas novas tarefas, também mostramos diversas formas alternativas para executá-las. Qual método ou técnica SQL a ser usada deve ser determinado pelas necessidades do aplicativo e seu nível de conforto e conhecimento da sintaxe SQL. Recursos Adicionais
|
||||||||||||||||||||||||||||||||||||||||||||||||