• Nenhum resultado encontrado

campos alfanuméricos (strings) ]

No documento Banco de Dados - Princípios e Prática (páginas 109-148)

Podemos utilizar os operadores de comparação para strings, da mesma maneira que para números. A ordem a ser seguida nesses casos é a alfabé- tica ou lexicográfica para cada posição da string. Assim, a palavra “casa”

será menor que “caso”, bem como menor que “casarão”. A ordem numé- rica também está associada à alfabética, de forma que a palavra “casa1” será menor que “casa2”.

Outra forma poderosa de comparação de strings é sobre o casamento de padrões entre elas. Numa comparação desse tipo, expressões que tenham a forma: “s LIKE p”, retornam strings que atendam um certo padrão, sendo s uma variável ou string e p o padrão de ocorrência. Os caracteres especiais “%” e “_” são utilizados para identificar os padrões procurados em um conjunto de strings. Por exemplo, caso queiramos obter todos os nomes da tabela “Clientes” que comecem com Carlos, é possível utilizarmos a expressão SQL:

SQL (17):

SELECT nome FROM clientes

WHERE nome LIKE “Carlos%”

O símbolo “%”, ao final, indica que serão considerados para a tabela de saída todos os nomes de clientes que comecem com Carlos. Caso quei- ramos todos os nomes que terminem com Silva, o símbolo “%” precisa estar no início do padrão de comparação:

SQL (18):

SELECT nome FROM clientes

WHERE nome LIKE “%Silva”

Ou, se quisermos encontrar uma palavra qualquer dentro de um campo, não importando a posição onde ela esteja, colocamos no início e no final do padrão:

SQL (19):

SELECT nome FROM clientes

109

No caso de compararmos com um padrão que case exatamente em ter- mos de caractere em vez de uma string, utilizamos o símbolo “_”. Assim, para uma consulta que deve retornar apenas os nomes que começam com a letra “L” e tenham apenas cinco letras, a obtemos com a consulta:

SQL (20):

SELECT nome FROM clientes

WHERE nome LIKE “L _ _ _ _“

Os caracteres para casamento de padrões podem variar entre certas implementações. Em Microsoft Access, por exemplo, em vez de “%” usa-se “∗” (asterisco), e em vez de “_” usa-se “?”.

Certos desenvolvedores web, quando utilizam sistemas de bus- cas em bancos de dados baseadas em SQL, na maior parte dos casos não se preocupam em interceptar a possibilidade do usu- ário colocar o caractere % no campo para busca. Uma busca que tenha a expressão campo LIKE ‘%’ retorna todos os registros que existem dentro da tabela para o atributo “campo”. Depen- dendo da quantidade de registros, o servidor de banco de dados pode ficar sobrecarregado com a pesquisa a ser efetuada.

A utilização de operadores de comparação para data e para hora tam- bém é válida, pois internamente os bancos de dados utilizam formatos numéricos para conversão de data e de hora.

[

trabalhando com data e com hora

]

Existe uma variedade de formatos de data e de hora que podem ser tra- balhados em bancos de dados. A maioria implementa o tratamento de

forma diferenciada, não seguindo o padrão. De acordo com o padrão SQL2, um valor constante de hora deve ser expresso com o prefixo DATE, antes da data e entre aspas, assim como:

DATE‘15/09/2004’

Para constantes referentes a hora, usamos o prefixo TIME:

TIME‘09:03:02’

Os bancos de dados implementam formas diferentes de tratar data e hora. O Microsoft Access exige que seja colocado cerquilha (#) em vez de aspas e que seja sem a palavra-chave DATE. Assim, deve ser utilizado #15/09/2004# e #09:03:02#. Bancos de dados como o Interbase e o MySQL não necessitam de prefixo para ambos, data e hora, desde que estejam nos formatos corretos.

[

ordenando os resultados

]

Uma consulta pode retornar os resultados ordenados de acordo com o tipo do atributo. Através do uso da cláusula ORDER BY, podemos colo- car um ou mais atributos pelos quais queremos que apareça a ordem da consulta efetuada. Por exemplo, para retornar a tabela de clientes orde- nada pelo nome do cliente:

SQL (21):

SELECT nome FROM clientes ORDER BY nome

Ou, ainda, pelo nome do cliente e telefone:

SQL (22):

SELECT nome FROM clientes

111

Se for atendido o critério de o nome do cliente começar com a letra “A”, temos:

SQL (23):

SELECT nome FROM clientes WHERE nome LIKE “A%” ORDER BY nome, telefone

Em vez de utilizarmos o nome do atributo, podemos também colocar o número de ordem, do mesmo, na tabela:

SQL (24):

SELECT nome FROM clientes WHERE nome LIKE “A%” ORDER BY 2,3

A ordenação pode ter sua seqüência invertida, ao colocarmos o quali- ficador DESC após o atributo. Assim a seguinte consulta apresenta os dados na ordem inversa de nomes:

SQL (25):

SELECT nome FROM clientes ORDER BY nome DESC

[

consultas aninhadas ou subconsultas

]

Veremos a partir daqui formas mais aprofundadas de utilização da cláu- sula WHERE. Quando falamos em comparações nas seções anteriores, utilizamos números, caracteres ou strings. No entanto é possível fazer a comparação também com resultados provenientes de outras consultas que estejam acontecendo dentro da principal. Denominamos a isso de

aninhamento de consultas ou subconsultas.

Recordando o exemplo, já visto para o produto cartesiano, onde buscá- vamos o nome do cliente para o pedido 1010:

SQL (26):

SELECT clientes.nome FROM pedido, clientes

WHERE pedido.codcli = clientes.codigo AND pedido.codigo = 1010

Observe que, nesse exemplo, a expressão pode ser modificada consi- derando-se o uso de uma subconsulta. Assim, deve ser verificado se o código do cliente é igual ao retornado pelo resultado da subconsulta à tabela “Pedido”: SQL (27): SELECT clientes.nome FROM clientes WHERE clientes.codigo = SELECT pedido.codcli FROM pedido WHERE pedido.codigo = 1010)

Observe que essa expressão retorna o mesmo resultado e que, na cláu- sula WHERE, a comparação é feita usando o campo clientes.codigo com o resultado que vem da subconsulta. Analisando, agora, a subcon- sulta, são projetados para o campo pedido.codcli os registros da tabela “Pedido” que atendam à condição de que o código do pedido seja igual a 1010. Nesse caso, para aquele registro que atender à condição de igualdade (=) da cláusula WHERE da consulta principal (campo codigo na tabela “Clientes” igual ao campo codcli na tabela “Pedido”), o nome do cliente é mostrado no resultado.

nome

Luís Alberto

Um fato a ser considerado é que a subconsulta pode retornar apenas um valor. É como se a consulta que gerasse esse resultado fosse:

SELECT cliente.nome FROM clientes

113

Será gerado um erro, caso exista mais de um registro no resultado da subconsulta. Assim, o operador de igualdade (=) deve ser substituído por outro tipo de operador, para que seja possível executar a consulta. Tais operadores serão vistos na próxima seção.

Outra observação pertinente a essa consulta aninhada deve ser feita. Note que o comando a seguir irá retornar apenas os campos presentes na tabela “Clientes”, devido ao uso do asterisco na cláusula SELECT e da referência à tabela “Clientes” na cláusula FROM da consulta principal:

SQL (28): SELECT * FROM clientes WHERE clientes.codigo = SELECT pedido.codcli FROM pedido WHERE pedido.codigo = 1010

E o comando a seguir retorna todos os campos presentes nas tabelas “Clientes” e “Pedido”, devido à presença das duas tabelas na cláusula

FROM. Portanto as duas formas de expressão não são perfeitamente

equivalentes:

SELECT *

FROM pedido, clientes

WHERE pedido.codcli = clientes.codigo AND pedido.codigo = 1010

[

condições em consultas aninhadas

]

Certos operadores – também chamados de predicados ou qualificado-

res – em SQL podem ser aplicados a uma tabela ou relação e produzirem um valor lógico. Uma subconsulta pode retornar tal valor para uma con- sulta principal. Os operadores disponíveis são: IN, EXISTS, ALL e ANY.

O operador IN

Vejamos a seguir um exemplo onde o resultado possa ser mais de um registro. Supondo que é preciso retornar os nomes de clientes com valor de pedido acima de R$1.000.00, fazemos:

SQL (29): SELECT clientes.nome FROM clientes WHERE clientes.codigo IN (SELECT pedido.codcli FROM pedido WHERE pedido.valor > 1.000,00) Resultando: nome Ernesto Luís Alberto

Note que foi substituído o operador de igualdade (=) pelo operador IN. Este operador atua na consulta indicando se o código do cliente está

contido no resultado da subconsulta. Dessa maneira, o operador IN opera de forma mais genérica que o operador de igualdade (=).

O operador EXISTS

O operador EXISTS P indica uma condição que é verdadeira se e somente

se P não for vazio. Entende-se aqui “P” como sendo o resultado (ou rela- ção) de uma subconsulta aninhada. Se “P” não possui nenhum registro, então EXISTS P retorna falso, caso contrário retorna verdadeiro.

O operador IN não deve ser interpretado como semelhante ao operador

EXISTS. Enquanto IN faz a pergunta: “está contido?”, o operador EXISTS,

115

A consulta a seguir modifica o exemplo dado para IN, utilizando agora

EXISTS: SQL (30): SELECT clientes.nome FROM clientes WHERE EXISTS (SELECT pedido.codcli FROM pedido WHERE pedido.valor > 1.000,00)

A interpretação agora é diferente: se existir algum pedido maior que

R$1.000.00, os nomes de clientes serão mostrados. Como existem dois registros, o conjunto da subconsulta não é vazio. Assim temos o resultado mostrando todos os nomes de clientes que estão na tabela “Clientes”.

nome Ernesto Amélia Luís Alberto José Antonio Carlos Silva

O operador lógico NOT pode ser aplicado aos operadores IN e EXISTS, de forma a apresentar o complemento da operação. Assim, caso a con- sulta utilizando IN seja:

SQL (31):

SELECT clientes.nome FROM clientes

WHERE clientes.codigo NOT IN (SELECT pedido.codcli FROM pedido

WHERE pedido.valor > 1.000,00)

O resultado responde à seguinte pergunta: “Quais os nomes de clientes cujos pedidos não são maiores que 1.000.00?”. Nesse caso, a resposta é:

nome

Amélia

José Antonio

Carlos Silva

No entando, se aplicarmos o operador NOT à consulta utilizada para o operador EXISTS,

SQL (32):

SELECT clientes.nome FROM clientes WHERE NOT EXISTS (SELECT pedido.codcli FROM pedido

WHERE pedido.valor > 1.000,00)

o resultado será vazio, pois a pergunta da consulta agora é: “Não exis- tem registros com valor de pedido maior que R$1.000,00?”. Como tais registros existem, a resposta para a pergunta retorna falso:

nome

O operador ALL

O operador ALL deve ser disposto na cláusula WHERE tal como campo > ALL subconsulta

retornando uma condição verdadeira se e somente se campo for maior que todo e qualquer valor localizado em subconsulta. O operador de comparação (>) pode ser trocado ainda por outros operadores (>=, <, <=, = ou <>). Por sua vez, o operador lógico NOT pode ser aplicado à frente, negando a condição. Assim, para selecionar os registros, na con- sulta principal, que venham a satisfazer a comparação com todos os registros retornados pela subconsulta, utilizamos o predicado ALL.

117

Como exemplo, montamos uma consulta com a cláusula ALL para retor- nar a informação do código e valor do pedido com maior subtotal exis- tente dentro da tabela “Itens”, mencionada anteriormente:

SQL (33):

SELECT pedido.codigo, pedido.valor FROM pedido

WHERE pedido.valor >= ALL (SELECT itens.subtotal FROM itens)

Com a seguinte relação como resultado:

codigo valor

1005 1.200,00

O operador ANY

O operador ANY deve ser disposto tal como campo > ANY subconsulta

retornando uma condição verdadeira se e somente se campo for maior que pelo menos um valor em subconsulta. O operador de comparação (>) pode ser trocado ainda por outros operadores (>=, <, <=, = ou <>). Sendo que o operador lógico NOT pode ser aplicado à frente, negando a condição. Assim, para selecionar os registros, na consulta principal, que venham a satisfazer a comparação com algum dos registros retornados pela subconsulta, utilizamos o predicado ANY (ou também SOME). Como exemplo, desejamos saber, dentro da tabela “Pedido”, quais são os que possuem itens cujo subtotal são 50% ou mais do valor do pedido. Então:

SQL (34):

SELECT pedido.codigo, pedido.valor FROM pedido

WHERE pedido.valor >= ANY (SELECT itens.subtotal FROM itens

WHERE itens.subtotal > pedido.valor * 0.5 AND itens.codped = pedido.codigo)

E a seguinte relação como resultado:

codigo valor

1005 1.200,00

1008 960,00

1015 755,00

Ou seja, retornaram aqueles pedidos e seus valores nos quais existe itens cujo subtotal seja maior ou igual a 50% do valor total do pedido. Note que é permitido usar expressões na comparação utilizando operações algébricas.

Algumas equivalências podem ser encontradas entre os operadores. Por exemplo

campo = ANY subconsulta campo

é igual a pelo menos um registro em subconsulta. E o mesmo que campo IN subconsulta campo

está contido em subconsulta. Assim como para o operador ALL campo <> ALL subconsulta campo

não é igual a todo e qualquer registro em subconsulta. É o mesmo que campo NOT IN subconsulta campo

119

[

eliminando registros duplicados

]

Em alguns resultados de consultas, pode ser que apareçam registros com valores duplicados. O uso da palavra-chave DISTINCT, presente na cláu- sula SELECT, faz com que seja apresentado apenas um dentre os regis- tros repetidos que possam aparecer.

Por exemplo, se quisermos obter os códigos de pedidos a partir da tabela “Itens”, lançamos a seguinte consulta:

SELECT codped FROM itens

Obtendo o seguinte resultado:

codped 1005 1008 1008 1010 1010 1010 1015 1015 1023 1023 1023

Para eliminar os registros que aparecem em duplicata, modificamos o comando SQL para:

SQL (35):

SELECT DISTINCT codped FROM itens

Obtendo somente um código para cada pedido. Assim: codped 1005 1008 1010 1015 1023

[

união

]

A operação de união em SQL é equivalente à existente para AR. A repre- sentação de união de duas tabelas “A” e “B” faz-se: A U B. Uma ressalva a ser feita é que o esquema das duas tabelas tem que ser igual, ou seja, conter os mesmos atributos.

Assim, se temos duas tabelas, “Computador” e “Notebook”, com os seguintes atributos:

COMPUTADOR(codigo, CPU, RAM, HD, CD, preco) NOTEBOOK(codigo, CPU, RAM, HD, Tela, preco)

A seguinte união em AR pode ser efetuada:

πcodigo,preco(Computador) U πcodigo,preco(Notebook)

Em SQL, utilizamos a cláusula UNION para efetuar a união. O comando SQL equivalente à consulta acima é:

SQL (36):

SELECT codigo, preco FROM computador UNION

SELECT codigo, preco FROM notebook

121

Veja que é preciso fazer dois comandos SQL e ligá-los pela cláusula

UNION. Caso existam registros repetidos, a operação de união irá auto-

maticamente eliminá-los. Porém, se for desejado o contrário, o qualifica- dor ALL pode ser usado para a operação apresentar todos os registros, inclusive os repetidos:

SQL (37):

SELECT codigo, preco FROM computador UNION ALL

SELECT codigo, preco FROM notebook

[

diferença

]

A operação de diferença, apesar de não ser implementada em alguns bancos de dados, também é equivalente à existente na AR. A representa- ção de diferença de duas tabelas “A” e “B” faz-se A − B*.

A seguinte diferença em AR, portanto, é possível de ser efetuada: πcodigo (clientes) − πcodcli (pedido)

Em SQL, utilizamos a cláusula EXCEPT (do padrão SQL) ou MINUS para efetuar a diferença. O comando SQL equivalente à consulta acima é:

SQL (38): SELECT codigo FROM clientes EXCEPT SELECT codcli FROM pedido ou

* A mesma ressalva feita à operação de união vale aqui, ou seja, que o esquema das duas tabelas seja igual, contenha os mesmos atributos.

SELECT codigo FROM clientes MINUS SELECT codcli FROM pedido Produzindo: codigo 295

Os bancos de dados PostgreSQL e DB2 utilizam o EXCEPT. Em Oracle é utilizado o MINUS. O Microsoft SQL Server, o Sybase, o Microsoft Access, o Interbase e o MySQL não implementam a operação de diferença, devendo a mesma ser simulada. O Post- greSQL e o DB2 também suportam o EXCEPT ALL.

Para simular um comando equivalente em SQL para diferença, utiliza- mos o operador EXISTS, visto anteriormente. Assim, para saber qual cliente não efetuou pedido, é verificado se existe na tabela “Pedido” algum código de pedido que esteja presente nas duas tabelas:

SQL (39):

SELECT clientes.codigo FROM clientes

WHERE NOT EXISTS (SELECT pedido.codcli FROM pedido

WHERE pedido.codcli = clientes.codigo)

A subconsulta fornece a existência de algum registro que atende à condi- ção na sua cláusula WHERE, ou seja, se o código do cliente está presente na tabela “Pedido”. Note que na igualdade o atributo “codcli” da sub- consulta é comparado com o atributo “codigo” da consulta principal. Esta é, então, equivalente à consulta com a cláusula EXCEPT.

123

[

interseção

]

Da mesma forma que a operação de diferença, a representação da ope- ração de interseção é equivalente à AR. Duas tabelas “A” e “B” são ope- radas com interseção fazendo A ∩ B*.

A seguinte interseção em AR pode ser efetuada: πcodigo (clientes) ∩ πcodcli (pedido)

Em SQL, utilizamos a cláusula INTERSECT do padrão SQL para efetuar a interseção. O comando SQL equivalente à consulta supracitada é:

SQL (40): SELECT codigo FROM clientes INTERSECT SELECT codcli FROM pedido Produzindo: codigo 202 221 233 282

Os bancos de dados PostgreSQL, DB2 e Oracle utilizam o INTERSECT. O Microsoft SQL Server, o Sybase, o Microsoft Access, o Interbase e o MySQL não implementam a operação de interse- ção, devendo a mesma ser simulada. O PostgreSQL, o DB2 e o Oracle também suportam o INTERSECT ALL.

* A mesma ressalva feita à operação de união e diferença vale aqui, ou seja, que os esquemas das duas tabelas sejam iguais, contenham os mesmos atributos.

O comando equivalente, para simular o comportamento de interseção, utiliza também a cláusula EXISTS de maneira complementar à diferença:

SQL (41): SELECT clientes.codigo FROM clientes WHERE exists (SELECT pedido.codcli FROM pedido

WHERE pedido.codcli = clientes.codigo)

O comando seria idêntico ao utilizado para a diferença se não fosse a ausência do operador lógico NOT.

[

renomeando tabelas

]

Vimos anteriormente que na AR temos um operador para modificar o nome de uma tabela, o operador de renomeação (ρ). Se quisermos mudar o nome da tabela “Clientes” para “C”, fazemos:

ρC (clientes)

Em SQL, utilizamos a palavra-chave AS para renomear uma tabela. Isso é justificável quando tem o objetivo de simplificar a escrita dos comandos, e, também, quando fazemos referência à mesma tabela mais de uma vez. Desse modo, o seguinte comando, para buscar o nome do cliente para o pedido 1010, pode ser simplificado de:

SELECT cliente.nome FROM pedido, clientes

WHERE pedido.codcli = clientes.codigo AND pedido.codigo = 1010

para:

SQL (42):

SELECT cliente.nome

FROM pedido AS p, clientes AS c WHERE p.codcli = c.codigo AND p.codigo = 1010

125

A consulta equivalente em AR é:

πc.nomep.codigo=1010 e p.codcli=c.codigop (pedido) × ρc (clientes)))

No próximo exemplo, se quisermos conhecer o código dos clientes que

efetuaram mais de um pedido, podemos fazer:

SQL (43):

SELECT p.codcli FROM pedido AS p WHERE p.valor < ANY (SELECT pedido.valor FROM pedido

WHERE pedido.codcli = p.codcli)

Outro comando SQL, utilizando renomeação de tabelas, pode ser feito para uma consulta na qual queiramos obter o valor maior ou menor dentro de certo atributo. Por exemplo, se quisermos obter o pedido de

maior valor, fazemos:

SQL (44):

SELECT pedido.valor FROM pedido

WHERE pedido.valor NOT IN (SELECT p1.valor

FROM pedido AS p1, pedido AS p2 WHERE pedido.codigo = p1.codigo) AND p1.valor < p2.valor)

Em AR, vimos um exemplo, utilizando diferença, que pode ser afirmado como equivalente ao comando SQL anterior:

πpedido.valor (pedido) − πp1.valorp1.valor<p2.valorp1(pedido) × ρp2(pedido)))

[

renomeando atributos

]

Assim como é possível renomear tabelas, também, o é em relação aos atri- butos de uma consulta em SQL. Tal operação tem como objetivo melhorar o formato do resultado de maneira a mostrar outra denominação em vez

do nome dos atributos. Sendo, inclusive, permitido fazer operações mate- máticas com eles. A palavra-chave AS também é utilizada para essa tarefa. Por exemplo, se quisermos modificar o nome dos campos de uma con- sulta para, assim, retornar o código do pedido e o valor para o pedido 1010, fazemos:

SQL (45):

SELECT codcli AS codigo_do_cliente, valor AS total_do_pedido FROM pedido

WHERE código = 1010

O resultado mostrado é:

codigo_do_cliente total_do_pedido

233 1.020,00

Outra variação permitida é “embutir” um atributo constante junto à saída:

SQL (46):

SELECT ‘codigo’ AS titulo, codcli AS codigo_do_cliente, valor AS

total_do_pedido

FROM pedido

WHERE codigo = 1010

Onde “codigo” é uma string constante que aparece à esquerda do código do cliente, e “titulo” é o nome do campo fictício:

titulo codigo_do_cliente total_do_pedido

codigo 233 1.020,00

Algo que aumenta ainda mais o poder de formatação de uma saída em SQL é o uso de operações matemáticas sobre os atributos. Caso quei- ramos mostrar a saída em outro formato de moeda (dólar), podemos multiplicar o atributo pelo valor de conversão (no exemplo, R$2,90 por dólar) na própria cláusula SELECT:

127

SQL (47):

SELECT ’codigo’ AS titulo, codcli AS codigo_do_cliente,

valor*2.90 AS total_do_pedido FROM pedido

WHERE codigo = 1010

E assim:

titulo codigo_do_cliente total_do_pedido

codigo 233 2.958,00

[

agregação

]

Através da agregação, efetuamos uma operação que resulta num valor único para uma lista de valores que aparecem em um atributo. Alguns exemplos são soma de valores e a contagem absoluta de registros. A operação é feita mediante o uso de uma função para o atributo dese- jado, inserido na cláusula SELECT. Podemos renomear a função de agre- gação para apresentação dos dados na tabela de resultado.

Veja as funções de agregação previstas para o padrão SQL no quadro a seguir:

Quadro 4.5 – Funções de agregação para o padrão SQL

Comando de agregação Finalidade

SUM Executa a soma dos valores existentes sobre o atributo especificado. É válido apenas para atributos de tipo numérico.

No documento Banco de Dados - Princípios e Prática (páginas 109-148)

Documentos relacionados