Índice

 

SQL Linguagem Estruturada de Consultas

SQL é uma linguagem de consultas a bancos de dados fácil de ser aprendida para consultas básicas, mas que também tem recursos sofisticados para consultas mais complexas. A versão 3.0 do CashPreview tem no menu "Operações" as opções "Nova consulta SQL" e "Abrir consulta SQL" que servem respectivamente para se criar uma consulta ao banco de dados, executá-la e salvá-la para uso posterior ou para abrir uma consulta previamente criada e comandar a sua execução.

A linguagem SQL permite a criação de comandos não apenas para consulta de informações ao banco de dados, mas também para alterar, excluir ou mesmo modificar a estrutura do esquema de armazenamento das informações. As consultas SQL permitidas no CashPreview são apenas as do tipo "SELECT", usadas para consulta de informações.

Antes de mais nada, porém, para usar as consultas SQL são necessárias algumas informações básicas.

I - Como estão organizadas as informações dentro de um banco de dados?

As informações estão organizadas na forma de tabelas. Cada tabela contém múltiplas linhas e múltiplas colunas. Em cada linha de uma tabela temos múltiplas informações sobre um tipo de objeto. Por exemplo, uma tabela de funcionários conterá uma linha para as informações de cada funcionário. Estas linhas são chamadas de registros. Cada registro é dividido em vários campos. Os campos são usados para conterem unidades de informações. Por exemplo, teremos o campo "Nome" para conter a informação do nome do funcionário, o campo "Codigo" para conter um código associado ao funcionário, que o identifica de modo único no banco de dados.

E já que estamos falando de tabelas, os campos também são chamados de colunas.  Portanto, no cruzamento da coluna "Nome" com as linhas (registros) da tabela Funcionarios, teremos os nomes de todos os funcionários. Veja graficamente abaixo:

Tabela Funcionarios

Codigo

Nome

1  Helena de Morais Camargo
2  Cássia Silva Mendes
3  Roberto Gouveia Mattos

Além de um nome para identificá-los, os campos de uma tabela possuem informação de tamanho e de tipo de dados, que servem para identificar como os dados estão armazenados nos campos. Os tipos de dados podem ser: númerico, data, texto, booleano, etc. Vale aqui dizer que os campos do tipo booleano são usados para receber apenas dois tipos de valores: verdadeiro ou falso. As palavras reservadas TRUE e FALSE representam respectivamente verdadeiro e false na linguagem SQL e, nos bancos de dados do Access, estes valores podem ser interpretados numericamente como -1 e 0.

Quando um campo é definido durante a criação de uma tabela, pode-se definir um valor padrão para este campo no caso de ele não ser informado na inclusão de um novo registro na tabela. Para exemplificar, se tivessemos o campo Inativo do tipo booleano  na tabela de Funcionarios, poderiamos definir o valor padrão para este campo em FALSE, pois, ao incluir um novo funcionário,  este valor seria assumido por padrão, mesmo que não fosse informado. Caso não se tenha nenhuma definição de valor padrão para o campo e ele não seja informado, o valor NULL será assumido. NULL é uma palavra reservada do SQL que veremos mais adiante como usá-la para testarmos se um campo contém ou não alguma informação armazenada.

Dentro de um banco de dados, podemos ter múltiplas tabelas e estas podem estar relacionadas entre si por um ou mais campos contendo informações em comum. Sabemos que uma tabela real de funcionários teria muito mais informações do que simplesmente o código e o nome de cada funcionário. Por exemplo, teríamos também informação sobre o cargo ocupado pelo funcionário. Neste caso, o cargo seria representado não pelo nome do cargo, mas por um código numérico que identificasse o cargo.

Porém, onde estaria o nome do cargo quando quisessemos conhecê-lo? Estaria numa tabela "Cargos". Na tabela "Cargos" poderiamos ter um código que identificaria o cargo, o nome do cargo, o salário atribuido ao cargo, etc. Veja um exemplo da tabela "Cargos" abaixo:

Tabela Cargos

CodigoCargo

Cargo

Salário

1 Assistente Administrativo  R$ 1.000,00
2 Operador de Telemarketing

 R$ 1.200,00

3 Recepcionista

 R$ 850,00

4 Programador Pleno

 R$ 2.500,00

5 Analista de Sistemas Sênior

 R$ 6.000,00

Supondo que tenhamos o campo CodigoCargo na tabela de funcionários, ela poderia ser assim:

Tabela Funcionarios

Codigo

Nome

CodigoCargo

1  Helena de Morais Camargo

2

2  Cássia Silva Mendes

3

3  Roberto Gouveia Mattos

5

Há várias vantagens em se usar o código do cargo e não o nome do cargo na tabela de funcionários. Uma delas é que o nome do cargo pode mudar na tabela Cargos sem que nada precise mudar na tabela Funcionarios, pois lá temos apenas o código do cargo, que permanece fixo. Outra vantagem é que a tabela Cargos pode conter muito mais informações relativas a cada cargo do que apenas o nome. A presença do código do cargo na tabela Funcionarios relaciona cada registro de funcionário a todas as informações do seu cargo que se encontram na tabela Cargos.

Se quisessemos listar a tabela de funcionários e mais o nome do cargo e salário de cada um, teríamos que fazer uma consulta que coletasse informações tanto da tabela Funcionarios como da tabela Cargos. Isto seria feito cruzando as duas tabelas pelo campo CodigoCargo e resultaria em algo assim:

Codigo

Nome

CodigoCargo

Cargo

Salário

1 Helena de Morais Camargo 2 Operador de Telemarketing  R$ 1.200,00
2 Cássia Silva Mendes 3 Recepcionista

R$ 850,00

3 Roberto Gouveia Mattos 5 Analista de Sistemas Sênior

 R$ 6.000,00

Apenas antecipando o que veremos mais adiante, o texto de uma consulta SQL para retornar as informações acima poderia ser escrito assim:

SELECT F.*, C.Cargo, C.Salario FROM Funcionarios As F, Cargos As C WHERE F.CodigoCargo = C.CodigoCargo;

A instrução acima instrui o banco de dados para retornar um conjunto de registros com todos os campos da tabela Funcionarios (aqui apelidada de F) que tenham o campo CodigoCargo igual ao campo CodigoCargo na tabela Cargos (aqui apelidada de C). Além disto, instrui para que sejam juntadas às informações de cada funcionário o nome de cargo e salário extraidos da tabela Cargos correspondentes ao código de cargo do funcionário.

Veremos, a seguir, toda a lógica da sintaxe desta consulta e das instruções SELECT em geral.

II - Sintaxe das instruções SELECT

O seguinte esquema mostra todos os elementos sintáticos de uma instrução SELECT.

SELECT [predicado { * | tabela.* | [tabela.]campo1 [AS alias1] [, [tabela.]campo2 [AS alias2] [, ...]]} FROM expressãotabela [, ...] [IN bancodedadosexterno] [WHERE... ] [GROUP BY... ] [HAVING... ] [ORDER BY... ]

No esquema acima, as palavras em letras maiúsculas são palavras reservadas da linguagem SQL que têm funções específicas na instrução SELECT.

Uma consulta de seleção de registros começa sempre pela palavra SELECT.

A plavra FROM indica a origem dos dados a serem retornados. Pode ser uma sequência de nomes de tabelas separadas por vírgulas ou mesmo subconsultas também separadas por vírgulas. Exemplo:

SELECT F.*, C.Cargo, C.Salario FROM Funcionarios AS F, Cargos AS C WHERE F.CodigoCargo = C.CodigoCargo;

SELECT F.*, C.Cargo, C.Salario FROM Funcionarios AS F, (SELECT CodigoCargo, Cargo, Salario FROM Cargos) AS C WHERE F.CodigoCargo = C.CodigoCargo;

No primeiro exemplo acima, as tabelas Funcionarios e Cargos foram renomeadas (apelidadas) internamente usando a expressão AS para F e C respectivamente. Esta técnica se mostra útil quando se tem campos de mesmos nomes em ambas as tabelas ou subconsultas e se quer determinar exatamente qual deve ser retornado. A forma de identificar a qual campo de qual tabela estamos nos referindo é usar o apelido dado à tabela seguido de um ponto e do nome do campo, exemplo: F.CodigoCargo. Poderiamos usar o nome da tabela em lugar do seu apelido, mas apelidar a tabela por uma simples letra facilita a escrita dentro da consulta.

No segundo exemplo, tivemos os dados buscados na tabela Funcionarios e numa subconsulta à tabela Cargos. Este segundo exemplo não é prático, pois obteríamos o mesmo resultado usando a simplicidade do primeiro, mas serve para exemplificar a possibilidade de se embutir uma consulta SQL dentro de outra.

A palavra WHERE é usada para indicar qual será o critério a ser usado na consulta. Após esta palavra, incluimos as condições que irão filtrar os registros do universo total existente nas tabelas envolvidas na consulta. Os critérios podem ser construídos usando operadores de comparação entre os campos existentes nas tabelas ou mesmo com um valor determinado. Nos exemplos usados acima, o critério foi apenas o da comparação entre os campos CodigoCargo da tabela de funcionários com o campo CodigoCargo da tabela Cargos, mas poderia se estender além disto. Poderia ser, por exemplo: F.CodigoCargo = C.CodigoCargo AND F.Nome = 'Paulo Ferreira' AND F.Inativo = FALSE. Observe, neste exemplo, que informações definidas no banco de dados como sendo do tipo texto, tais como nomes, números de telefones, endereços, devem estar entre aspas simples nas consultas SQL para bancos de dados Access. Neste exemplo, o campo Inativo da tabela Funcionarios (F) é do tipo booleano e por isto é testado para um valor booleano (FALSE).

Neste caso, temos um critério que compara os campos CodigoCargo presentes nas duas tabelas, mas também busca apenas os funcionários que tenham o nome 'Paulo Ferreira' e que não estejam inativos. Observe que estes três critérios foram unidos pela palavra AND, que significa "e" em inglês. AND cumpre a função de um operador lógico, que fará com que o critério somente seja satisfeito para os registros que cumprirem a todas as condições de comparação. Mas também poderíamos usar a palavra OR, que significa "ou" em inglês. OR cumpre a função do operador lógico "ou inclusivo", ou seja, seriam retornados todos os registros que cumprissem ao menos uma de duas condições ou ambas. Além de AND e OR, também é possível usar o operador NOT para negar uma condição de comparação. Caso quisessemos cruzar a tabela Funcionarios com a tabela Cargos como fizemos acima, porém retornando apenas os registros em que o nome do funcionário fosse diferente de 'Paulo Ferreira', criaríamos um critério assim: F.CodigoCargo = C.CodigoCargo AND NOT F.Nome = 'Paulo Ferreira'.

Como operadores de comparação podemos usar também >, <, >=, <= e as palavras reservadas BETWEEN ... AND ... Esta última para especificar que desejamos apenas o que estiver dentro de um certo intervalo de valores. Exemplo: Data BETWEEN #12/31/2007# AND #01/31/2008#  . Observe neste exemplo que, com bancos de dados Access, os valores de datas no SQL devem sempre ser informados entre sinais de # e o mês deve preceder o dia na expressão da data.

Uma outra palavra reservada também é usada no Access para a criação de critérios que testam os valores dos campos para verificar se estão em NULL. Trata-se da palavra IS. No Access, para testar se um campo está com valor nulo usamos a expressão IS NULL e nunca = NULL. Exemplo: F.CodigoCargo = C.CodigoCargo AND NOT C.Salario IS NULL .

A cláusula GROUP BY... e as funções agregadas

A linguagem SQL nos fornece algumas funções que usamos para retornar contagens, somatórias, médias, máximos e mínimos, valores estatísticos calculados com base nos valores de campos das tabelas. Veja abaixo as mais comuns:

     COUNT    

Usada para fazer a contagem de registros que satisfaçam a um determinado critério ou todos se nenhum critério for informado na cláusula WHERE. Ex.: COUNT (CodigoCargo). Neste caso, só serão contados os registros que tenham algum valor para CodigoCargo. Aqueles que tiverem valores nulos somente seriam contados se a expressão fosse COUNT (*), que conta todos os registros.

SUM

Usada para somar os valores de campos numéricos dos registros que satisfaçam a um determinado critério ou de todos se nenhum critério for informado na cláusula WHERE. Ex.: SUM (Salario).

MIN, MAX

Usadas para obter o menor valor (MIN) e o maior valor (MAX) de campos numéricos dos registros que satisfaçam a um determinado critério ou de todos se nenhum critério for informado na cláusula WHERE. Ex.: MAX (Salario).

AVG

Usada para obter a média aritmética dos valores de campos numéricos dos registros que satisfaçam a um determinado critério ou de todos se nenhum critério for informado na cláusula WHERE. Ex.: AVG (Salario).

Exemplos de consultas completas usando as funções acima:

SELECT MAX (Salario) AS Maior_Salario FROM Cargos WHERE DataDeCriacao BETWEEN #01/31/2007# AND #12/31/2007#

SELECT COUNT(*) AS Total_de_Recepcionistas FROM Funcionarios WHERE CodigoCargo = 2

Note que nos exemplos acima a consulta retornará apenas um registro, pois a totalização se referirá ao conjunto de todos os registros que satisfaçam ao critério da cláusula WHERE . Suponhamos que quisessemos algo mais detalhado, como por exemplo, a contagem de quantos funcionários temos por cada cargo. Neste caso, usariamos a cláusula GROUP BY para agruparmos a contagem por cargo e teríamos uma consulta assim:

SELECT CodigoCargo, COUNT( *) AS Total_de_Funcionarios FROM Funcionarios GROUP BY CodigoCargo

Neste caso, teríamos como retorno um registro para cada código de cargo e o total de funcionários em cada cargo conforme abaixo:

CodigoCargo

Total_de_Funcionarios

1

5

2

3

3

8

O uso da cláusula GROUP BY faz com que os registros sejam retornados na ordem crescente do(s) campo(s) usado(s) para agrupar o resultado da função agregada. Mais um detalhe, todos os campos na cláusula SELECT devem aparecer após a cláusula GROUP BY separados por vírgula,  ou você terá um erro de sintaxe na consulta.

A cláusula HAVING ...

A cláusula HAVING vem a complementar a cláusula GROUP BY . Quando usamos GROUP BY , os registros retornados serão todos os que satisfizerem ao critério informado após a palavra WHERE . Porém, podemos querer fazer uma segunda filtragem após termos os resultados dos cálculos das funções agregadas. Neste caso, usamos a cláusula HAVING para fazer esta filtragem posterior. Exemplo:

SELECT CodigoCargo, COUNT(*) AS Total_de_Funcionarios FROM Funcionarios  GROUP BY  CodigoCargo HAVING  COUNT(*) >= 4

No exemplo acima, queremos que sejam retornados apenas os registros de códigos de cargos que tenham a contagem de funcionários superior ou igual a 4 funcionários.

Usando ORDER BY... para ordenar os registros retornados

A cláusula opcional ORDER BY é usada para definir o critério de ordenação dos registros resultantes da consulta. Tem precedência sobre a ordenação automática produzida quando se usa a cláusula GROUP BY. A ordenação é especificada pela lista dos campos segundo os quais será feita a ordenação e na ordem decrescente de precedência de uns sobre os demais. Por padrão a ordenação é ascendente, mas pode ser modificada usando-se as palavras  ASC e DESC após os campos conforme a ordenação que será feita através dos seus valores. Exemplo:

SELECT Sobrenome,  Nome FROM Funcionarios ORDER BY Sobrenome, Nome DESC

Acima, ordenamos uma consulta à tabela Funcionarios de modo a ter os registros em ordem crescente por sobrenome e em ordem decrescente por nome.

As demais partes do esquema de sintaxe da consulta SELECT já apresentado antes estão descritas abaixo: 

Parte: Descrição:
predicado Um dos seguintes predicados: ALL, DISTINCT, DISTINCTROW ou TOP . Você usa o predicado para restringir o número de registros que retornam. Se nenhum for especificado, o padrão será ALL, que produz o retorno de todos os registros que atendam ao critério da consulta.
* Especifica que todos os campos da tabela ou tabelas especificadas são selecionados. Se houver mais de uma tabela na consulta e houver campos com nomes iguais em duas ou mais tabelas, você deve usar aliases. Veja mais abaixo a explicação sobre alias1, alias2.
tabela O nome da tabela que contém os campos dos quais os registros são selecionados.
campo1, campo2 Os nomes dos campos dos quais os dados serão recuperados. Se você incluir mais de um campo, eles serão recuperados na ordem listada.
alias1, alias2 Os nomes que serão usados como títulos de colunas no conjunto retornado em vez dos nomes originais das colunas na tabela. Exemplo: SELECT Codigo As Identificacao, Nome As Funcionario FROM Funcionarios
expressãotabela

O nome da tabela ou tabelas contendo os dados que você quer recuperar. Também pode ser uma subconsulta entre parenteses. Exemplos:

SELECT * FROM Funcionarios

SELECT F.Codigo, F.Nome FROM (SELECT Codigo, Nome FROM Funcionarios) As F

bancodedadosexterno

O nome do banco de dados que contém as tabelas em expressãotabela se não estiver no banco de dados atual. Exemplo:

SELECT * FROM [MS Access;Database=C:\Arquivos de Programas\CashPreview\Exemplo.mdb].Funcionarios

No exemplo acima, a tabela Funcionarios estaria dentro do banco de dados Exemplo.mdb.

 

 

Consultas de União

Uma outra forma de se combinar consultas além de se embutir uma dentro de outra, como vimos acima, é criar uma união de consultas. Usando a palavra UNION podemos unir várias consultas SQL e obter os registros retornados por cada uma*. A condição para que possamos fazer isto é que todas as consultas retornem o mesmo número de campos, com os mesmos nomes ou apelidos e na mesma ordem dentro da consulta. Exemplo:

(SELECT CodConta, Data, Valor From Lancamentos)

UNION

(SELECT CodConta, Data, Valor From HistoricosDeLancamentos)

ORDER BY Data;

Um detalhe importante a saber sobre as consultas de união é que elas sempre retornam um conjunto de registros exclusivos, ou seja, se em uma ou mais consultas houver mais de um registro com todos os campos iguais, apenas um deles será retornado. Para que mesmo os registros repetidos possam ser retornados, devemos usar o predicado ALL após cada palavra UNION ligando as consultas. Para que todos os registros fossem retornados, o exemplo acima ficaria assim:

(SELECT CodConta, Data, Valor From Lancamentos)

UNION ALL

(SELECT CodConta, Data, Valor From HistoricosDeLancamentos)

ORDER BY Data;

Consultas parametrizadas

Além do que já foi exposto acima, as consultas SQL também podem ser parametrizadas, isto é, podem conter variáveis que são definidas antes de cada execução para determinar os critérios da execução da consulta. Veja mais sobre isto em " A cláusula PARAMETERS ".