Neste capítulo, mostraremos os principais comandos SQL para manipulação dos dados armazenados nas tabelas do banco. Esse capítulo, abordará os comandos DML, disponíveis para inserção, alteração, deleção e seleção de dados.

Adicionado, Alterando e Removendo Dados

Para inserir, alterar ou apagar dados nas tabelas do banco, através de instruções SQL, devemos utilizar os comandos Insert, Update e Delete respectivamente. Através desses três comandos, manipulamos as informações em uma ou mais tabelas do banco de dados.

Utilizando a instrução Insert

Através da instrução Insert, podemos adicionar uma ou mais linhas para uma tabela do banco de dados:


INSERT INTO NOME_DA_TABELA (coluna1, coluna2, coluna3, ....colunaN)
VALUES (valor1, valor2, valor3, ..., valorN);

No parâmetro Nome_da_Tabela, podemos especificar tanto o nome de uma tabela do banco de dados, como também de uma View atualizável. Caso você não especifique o nome das colunas que receberão valores dentro da instrução Insert, o servidor de banco de dados utilizará todas as colunas da tabela informada. Veja alguns exemplos de uso da instrução Insert:

INSERT INTO CLIENTES (CODIGO, NOME, SEXO) VALUES (1, 'Natália da Silva', 'F');
INSERT INTO CIDADES (CODCIDADE, CODPAIS, NOMECIDADE, DDD) VALUES (4, 55, 'Curitiba', '31');
INSERT INTO ITENS VALUES (1, 13, 200.87);
Nota: Antes de inserir um registro em uma tabela, que possui chave estrangeira, verifique se o valor que será inserido na coluna relacionada, existe na coluna chave primária da outra tabela.

Dentro da seção da instrução Values, podemos utilizar os seguintes valores em conjunto, ou não, com as seguintes funções:

  • Valores gerais como números, strings ou data;
  • Função Cast: Para converter um valor de um tipo para outro durante a operação de inserção;
  • Função Upper: Para converter uma string que está sendo inserida para maiúscula;
  • Função Gen_Id: Normalmente utilizada com Generators para geração de um valor único;
  • Valor Null: Para inserção de nulo para a coluna durante a operação de inserção do registro;
  • User: Comando utilizado para inserir o nome do usuário conectado no banco de dados;
  • Variável: Podemos inserir variáveis ou parâmetros através de Stored Procedures ou Triggers;

Inserindo várias linhas

Através da instrução Insert, podemos inserir várias linhas a partir de um único comando:

INSERT INTO NOME_DA_TABELA_DESTINO (
  coluna1, coluna2, coluna3, ...., colunaN)
SELECT (coluna1, coluna2, coluna3, ..., colunaN)
FROM NOME_DA_TABELA_ORIGEM;

A instrução Select, precisa ter o mesmo número de colunas listadas da expressão Insert. Caso o nome das colunas não seja informado, o Select precisa retornar um resultado que possua o mesmo número de colunas que a tabela onde os dados serão inseridos. Veja mais alguns exemplos a seguir:

INSERT INTO CIDADE_BR
SELECT * FROM CIDADE;
 
INSERT INTO ITENS (CODIGO, NF, QUANT)
SELECT (CODIGO, NUM_NF, QUANT)
FROM ITENS_VALIDOS
WHERE NUM_NF = 15;
 
INSERT INTO CLIENTES (CODIGO, NOME, FONE, ENDERECO)
SELECT (COD_CLI, NOME, FONE_CLI, END_CLI)
FROM CLIENTES_INATIVOS;

IUtilizando a instrução Update

Para alterar os valores armazenados em registros existentes na tabela, devemos utilizar o comando Update:

UPDATE NOME_DA_TABELA
SET COLUNA1 = VALOR1, COLUNA2 = VALOR2, COLUNA3 = VALOR3, ...., COLUNAN = VALORN
WHERE CONDICOES;

Como no comando Insert, podemos utilizar diversos tipos de valores e funções dentro da instrução Update. Normalmente utilizamos a instrução Update em conjunto com a cláusula Where, para que apenas uma, ou um conjunto de registros sejam atualizados.

Atenção: Caso a instrução Update seja utilizada sem uma cláusula Where, a atualização ocorrerá em todos os registros armazenados dentro da tabela.

Você pode utilizar a instrução Where em conjunto com os operadores e palavras chaves para limitar o número de registros a serem atualizados constantes na Tabela 9.1.

Expressão Descrição
= Valor Igual a um determinado valor
< Valor Menor que um determinado valor
<= Valor Menor ou igual a um determinado valor
>= Valor Maior ou igual a um determinado valor
< > Valor Diferente de um determinado valor
BETWEEN valor1 AND valor2 Entre uma faixa de valores informada
LIKE Valor Que contenha um determinado valor (%)
IN (valor1, valor2, valor3, ..., valor4) Que contenha um dos elementos da lista
IS NULL Verifica se o valor da coluna é nulo
IS NOT NULL Verifica se o valor da coluna não é nulo
STARTING WITH Valor Que contenha uma string case sensitive
CONTAINING Valor Que contenha uma string case insensitive

Tabela 9.1. Operadores e palavras chaves para limitar o número de registros atualizados pelo comando Update

Veja a seguir, alguns exemplos de uso da instrução Update:

UPDATE CLIENTES
SET CIDADE = 'Curitiba', UF = 'PR'
WHERE COD_REF = 20;
 
UPDATE ITENS SET VALOR = 0.00
WHERE VALOR IS NULL;
 
UPDATE VENDAS
SET ATIVO = 'N'
WHERE DATA_VENDA BETWEEN '01.01.1992' AND '12.10.1995';
 
UPDATE PRODUTOS
SET TIPO = 'H', ATIVO = 'S', COD_FORNECEDOR = 100
WHERE COD_REF IN (1, 5, 10, 11);
 
UPDATE PRECOS
SET VALOR_TOTAL = VALOR_TOTAL * 1.1
WHERE (QUANTIDADE * VALOR_UNITARIO) > 1000;

Atualizando várias linhas através de outra tabela

Utilizando a instrução Update, podemos também alterar registros de uma tabela a partir de valores armazenados em outra tabela do banco de dados. Veja o exemplo seguir:

UPDATE PRODUTO
SET VALOR = VALOR + 100
WHERE COD_FORNECEDOR IN (
  SELECT COD_FORNECEDOR
  FROM FORNECEDOR
  WHERE UF = 'SP');

Na instrução SQL anterior, aumentamos em 100 reais o valor de todos os produtos onde o código do fornecedor for igual aos códigos dos fornecedores cadastrados na tabela Fornecedor que sejam do estado de São Paulo.

Utilizando a instrução Delete

Para remover um ou mais registros de uma tabela devemos utilizar o comando Delete. Veja a seguir, sua sintaxe básica:

DELETE FROM NOME_DA_TABELA WHERE CONDICOES;

No parâmetro Condicoes devemos especificar o conjunto de registros que serão apagados da tabela informada no parâmetro Nome_Da_Tabela.

Atenção: Caso nenhuma condição seja passada durante o uso do comando Delete, todos os registros da tabela serão apagados.

Como mostrado no comando Update, a cláusula Where pode ser utilizada com diversos operadores e palavras chaves para limitar o número de registros que serão apagados da tabela. Veja a seguir, alguns exemplos de uso da instrução Delete:

DELETE FROM CLIENTES
WHERE SEXO = 'M';
 
DELETE FROM PRODUTOS
WHERE TIPO = 1;
 
DELETE FROM TEMPORARIA;
 
DELETE FROM VENDAS
WHERE DATA_VENDA BETWEEN '01.01.2000' AND '31.12.2003';
 
DELETE FROM PRODUTOS
WHERE COD_FORNECEDOR IN (
  SELECT COD_FORNECEDOR
  FROM FORNECEDOR
  WHERE COD_CIDADE = 5);

Caso você precise apagar registros de uma tabela relacionada com outra, ou outras tabelas do banco de dados, você precisará primeiro apagar todos os registros da tabela filha, que possui o valor de referencia da chave estrangeira, para só depois excluir o registro da tabela pai, a qual possui o valor da chave primária.

O servidor de banco de dados não permite que registros fiquem órfãos dentro da tabela, através da exclusão de registros primários dos quais eles dependem e estão relacionados através de uma Foreign Key.

Nota: Você pode utilizar a cláusula Delete Cascade durante a definição da Foreign Key para permitir que, ao excluir um registro pai, todos os registros vinculados a ele sejam apagados automaticamente.

Buscando Dados

Através do comando Select, podemos realizar pesquisas e extrair informações das tabelas do banco de dados. Sem dúvida alguma a instrução Select é uma das mais importantes instruções SQL. Utilizando o comando Select, podemos buscar dados de uma ou mais tabelas do banco de dados, onde para isso contamos com inúmeros operadores que permitem que façamos essas buscas.

Usando os operadores disponíveis em conjunto dentro de uma instrução SQL, podemos fazer qualquer tipo de busca dentro das tabelas do banco de dados. Segue a seguir, a sintaxe básica da instrução Select:

SELECT LISTA_DE_COLUNAS
FROM LISTA_DE_TABELAS
WHERE CONDICOES
GROUP BY LISTA_DE_COLUNAS
ORDER BY LISTA_DE_COLUNAS;

Dentro de uma instrução Select, podemos buscar informações de colunas presentes e um ou mais tabelas relacionadas dentro do banco. No parâmetro Lista_de_Colunas, logo após a palavra reservada Select, podemos listar todas as colunas que queremos buscar da tabela.

Caso seja colocado o caractere asterisco (*), o servidor de banco de dados trará todas as colunas disponíveis dentro da tabela especificada na cláusula From. No parâmetro Lista_de_Tabelas devemos especificar o nome das tabelas que faremos a busca das informações. Veja alguns exemplos básicos de uso da instrução Select:

SELECT CODIGO, NOME
FROM CLIENTES;
 
SELECT * FROM CIDADES;
 
SELECT CODIGO, NOME, ENDERECO, FONE, BAIRRO, CIDADE, UF
FROM FORNECEDORES;
 
SELECT PROD_ID, PROD_DESCRICAO, FOR_NOME
FROM PRODUTOS, FORNECEDORES
WHERE PRODUTOS.FOR_ID = FORNECEDORES.FOR_ID;

Quanto você utiliza uma instrução Select para extrair informações contidas em duas ou mais tabelas, normalmente essas tabelas possuem pelo menos uma coluna fazendo o relacionamento entre elas.

Nota: Você pode fazer o relacionamento entre duas tabelas durante uma instrução Select, independente de essas tabelas possuírem uma constraint de Foreign Key, ou não.

Listando as Colunas

Para listar as colunas que deseja trazer no resultado da instrução Select, informe-as logo após a palavra chave Select separando-as por vírgulas. Veja o exemplo a seguir:

SELECT CODIGO, NOME
FROM FUNCIONARIOS;

Caso você queira trazer todas as colunas de uma determinada tabela, você pode como comentado anteriormente, utilizar o caractere asterisco (*). Através dele, o servidor retornará todas as colunas da tabela em questão mostrando-as na ordem em que estão posicionadas dentro da tabela.

Caso você não utilize a cláusula Where para fazer algum filtro na instrução Select, o servidor de banco de dados retornará todas colunas e todos os registros da tabela. Veja o exemplo a seguir:

SELECT * FROM EMPRESAS;
 
SELECT * FROM EMPRESAS
WHERE UF = 'SP';

Quando você lista as colunas dentro da instrução Select, elas não precisam seguir a ordem em que estão armazenadas dentro da tabela, isso é, em um banco relacional a ordem das colunas não é importante, a não ser que você esteja utilizando essa instrução Select para fazer inserção de dados através de um Insert, por exemplo. O IB/FB possui a palavra reservada Distinct para que possamos aplicar nas colunas da instrução Select para remover valores duplicados.

Quando fazemos um Select sem a palavra Distinct, o servidor de banco de dados retorna os valores na ordem em que eles estão armazenados dentro da tabela em questão. Quando utilizamos à instrução Distinct o servidor agrupa os valores retornados pelo Select.

Para que possamos agrupar os valores duplicados dentro da instrução Select, para que o comando Distinct possa removê-los, devemos utilizar a cláusula Order By no final da instrução Select. Através da cláusula Order By podem ordenar o resultado do Select seguindo os valores de uma ou mais colunas disponíveis dentro do mesmo. Veja alguns exemplos a seguir:

SELECT DISTINCT NOME
FROM CLIENTES
ORDER BY NOME;
 
SELECT CODIGO, NOME, CIDADE
FROM FORNECEDORES
ORDER BY CIDADE, NOME;

Quando utilizamos a cláusula Order By, podemos utilizar os comandos Ascending (ASC) ou Descending (DESC) para especificar a ordem a qual a coluna será mostrada. Por padrão, se nenhum dos dois comandos for utilizado, o servidor retorna sempre seguindo a ordem ascendente dos valores das colunas. Veja a seguir, alguns exemplos de uso da cláusula Order By em conjunto com os comandos ASC e DESC:

SELECT NOME, UF
FROM CIDADE
ORDER BY NOME DESC;
 
SELECT CODIGO, DATA_VENDA, VALOR
FROM VENDAS
ORDER BY DATA_VENDA DESC, CODIGO ASC;
 
SELECT *
FROM EMPRESAS
ORDER BY UF ASC, CIDADE ASC, NOME DESC;

Utilizando a cláusula Where

Através da cláusula Where, podemos limitar o número de registros (linhas) retornados pela instrução Select. Como visto durante a explicação das cláusulas Update e Delete, podemos utilizar diversos operadores diferentes para fazer o filtro das informações a serem retornadas. Veja alguns exemplos:

SELECT * FROM CLIENTES
WHERE UF = 'PR';

Na instrução anterior, trazemos apenas os clientes que são do estado do Paraná.

SELECT CODIGO_VENDA, DATA_VENDA, VALOR_VENDA
FROM VENDAS
WHERE DATA_VENDA BETWEEN '01.01.2004' AND '31.12.2004';

Na instrução anterior, trazemos todas as vendas realizadas dentro do ano de 2004.

SELECT * FROM PRODUTOS
WHERE PROD_TIPO = 'A' OR PROD_TIPO = 'B';

Na instrução anterior, trazemos todos os produtos que são do tipo A ou B. A cláusula Where suporta ainda o uso de expressões aritméticas:

SELECT * FROM PEDIDOS
WHERE DATA_PEDIDO = 'TODAY' – 15;

Na instrução anterior, trazemos todos os pedidos que foram emitidos quinze dias atrás. Caso a coluna que faz parte da cláusula Where possuir um índice, o servidor irá utilizá-lo, se necessário para aumentar à performance na busca as informações. Entretanto, o IB/FB é capaz de utilizar índices apenas para certos tipos de condições Where. Veja algumas situações a seguir:

SELECT * FROM CIDADES
WHERE NOME = 'Curitiba';

Na instrução anterior, o índice na coluna span Nome pode ser utilizado pelo servidor, pois estamos buscando por um valor exato para fazer o filtro.

SELECT * FROM CIDADES
WHERE NOME LIKE '%José%';

Já na instrução anterior, o servidor não é capaz de utilizar um índice para acelerar a busca, pois o valor que estamos procurando aparece no meio da coluna. Dessa maneira, o servidor espera por valores aleatórios nos dois lados da coluna, não tendo assim, como utilizar um índice.

SELECT * FROM CIDADES
WHERE NOME STARTING WITH 'São';

Na instrução anterior, o servidor utiliza um índice, pois o mesmo possui uma combinação exata de valores no início da coluna para realizar a busca de forma indexada.

Utilizando Alias para Tabelas

Em instruções Select, que fazem buscas em duas ou mais tabelas do banco de dados, retornando um grande número de colunas em seu resultado, podem ficar extensas e tediosas para serem montadas.

Para ajudar e facilitar, o IB/FB permite que você especifique um alias (apelido) para cada tabela utilizada dentro da instrução SQL. Normalmente os alias são uma ou duas letras, como por exemplo “C” para Clientes, ou “F” para Fornecedores. Para utilizar um alias dentro de uma instrução Select coloque-o logo após o nome da tabela dentro da cláusula From:

SELECT C.CODIGO, C.NOME, C.UF
FROM CIDADES C
ORDER BY C.NOME;

Nota: O uso de alias não é obrigatório, porém, ele pode facilitar a digitação de instruções SQL mais complexas e melhora o entendimento das mesmas.

Utilizando Joins

Normalmente, você terá que realizar consultas em mais de uma tabela ao mesmo tempo para conseguir extrair as informações que precisa. Em bancos de dados relacionais normalizados, as informações normalmente ficam distribuídas em várias tabelas do banco de dados. Para fazer a busca em várias tabelas através de um único comando Select, precisamos ligá-las através de colunas relacionadas, normalmente especificadas e identificadas através do uso de Foreign Key.

Vamos analisar o seguinte exemplo: Suponhamos que no nosso banco de dados, temos uma tabela de Clientes, a qual possui a coluna Cli_Id que é definida como chave primária da tabela, a qual garante a identificação de cada registro de forma única. Nesse mesmo banco, temos as tabelas de Vendas, Pedidos e Contatos. Cada uma dessas tabelas também possui um campo Cli_Id, o qual foi definido (ou não) utilizando uma Foreign Key ligando a coluna Cli_Id da tabela Clientes.

Para que possamos buscar as informações de um determinado cliente junto com todos os pedidos emitidos para o mesmo, teremos que fazer um join (ligação) entre a tabela de clientes e a de pedidos, para conseguirmos montar o resultado com as colunas que precisamos.

Nota: O IB/FB não impede que façamos ligações sem sentido. Podemos, por exemplo, ligar a coluna Cliente.Uf com a coluna Cidade.Pais. O servidor realizará a pesquisa, porém nenhum resultado será retornado, visto que não existem valores combinantes nessas duas colunas.

Sintaxe utilizada para realização de Join

Tanto o InterBase quanto o Firebird suportam duas diferentes sintaxes para o uso da instrução Join:

SELECT LISTA_DE_COLUNAS
FROM TABELA1, TABELA2
WHERE TABELA.COLUNA1 = TABELA2.COLUNA1;

Essa sintaxe faz a união das colunas relacionadas dentro da cláusula Where da instrução Select:

SELECT C.CODIGO, C.NOME, E.SIGLA
FROM CIDADES C, ESTADOS E
WHERE C.COD_ESTADO = E.COD_ESTADO;
 
SELECT C.CODIGO, C.NOME, CID.NOME, E.NOME
FROM CLIENTES C, CIDADES CID, ESTADOS E
WHERE C.COD_CIDADE = CID.COD_CIDADE
AND CID.COD_ESTADO = E.COD_ESTADO;

A segunda sintaxe que pode ser utilizada é a sintaxe que segue o padrão SQL-92. Nessa sintaxe, a união às colunas relacionadas é realizada dentro da cláusula From da instrução Select, deixando assim a cláusula Where apenas para filtros das informações a serem buscadas:

SELECT LISTA_DE_COLUNAS
FROM TABELA1
JOIN TABELA2 ON TABELA1.COLUNA1 = TABELA2.COLUNA1
WHERE CONDICOES;

Veja alguns exemplos de uso dessa sintaxe padrão SQL-92:

SELECT C.CODIGO, C.NOME, E.SIGLA
FROM CIDADES
JOIN ESTADOS ON CIDADES.COD_ESTADO = ESTADOS.COD_ESTADO;
 
SELECT C.NOME, V.DATA_VENDA, I.QUANTIDADE
FROM CLIENTES C
JOIN VENDAS V ON (V.COD_CLIENTE = C.COD_CLIENTE)
JOIN ITENS I ON (I.COD_VENDA = V.COD_VENDA);

Como vimos nos últimos exemplos, podemos incluir colunas de quaisquer das tabelas utilizadas dentro da instrução Select. Nesse tipo de instrução Select, o uso de alias podem facilitar bastante, visto que, em algumas situações poderemos ter colunas de tabelas diferentes com o mesmo nome. Veja o exemplo a seguir:

SELECT E.NOME, P.NOME
FROM ESTADOS E
JOIN PAIS P ON E.COD_PAIS = P.COD_PAIS;

Na instrução anterior, tanto a tabela Estados, como a tabela Pais possuem um campo denominado Nome. Nessas situações o uso de alias pode ser bastante útil para que possamos identificar cada coluna dentro da instrução Select.

Nota: O IB/FB não possui nenhum limite para utilização de Join’s dentro de instruções Select. Você pode unir quantas tabelas forem necessárias para trazer o resultado que precisa.

Utilizando Alias para Colunas

Como em tabelas, podemos também definir um alias para as colunas que são retornadas dentro da instrução Select. Veja a seguir, a sintaxe básica para o uso de alias em colunas:

SELECT COLUNA1 AS ALIAS1, COLUNA2 AS ALIAS2
FROM LISTA_DE_TABELAS;

O uso de alias em colunas também não são obrigatórias, porém, em determinadas situações podem ser bastante úteis para facilitar a identificação de cada coluna dentro da instrução Select. Veja alguns exemplos a seguir:

SELECT E.NOME AS ESTADO, P.NOME AS PAIS
FROM ESTADOS E, PAIS P
WHERE E.COD_PAIS = P.COD_PAIS;

O uso do operador As, para definição do alias da coluna não é obrigatório, isso é, você pode definir o alias diretamente após especificar o nome da coluna. Veja o exemplo a seguir:

SELECT C.NOME CLIENTE, E.UF ESTADO
FROM CLIENTES C
JOIN ESTADOS E ON C.COD_ESTADO = E.COD_ESTADO
WHERE C.CODIGO = 12;

Criando novas Colunas

Durante a construção de uma instrução Select, podemos derivar novas colunas através das existentes. Veja alguns exemplos de derivação de novas colunas:

SELECT NOME || ' , ' || ENDERECO || ' , ' || BAIRRO || ' , ' || CIDADE
FROM CLIENTES
WHERE UF = 'RS';

Na instrução anterior, é retornado apenas uma coluna contendo a concatenação das colunas Nome, Endereco, Bairro e Cidade com seus valores separados por vírgula. Através do par de barras verticais (| |) o servidor de banco de dados identifica a concatenação entre colunas ou valores dentro da instrução SQL.

Nota: Apenas colunas do tipo Char e VarChar suportam concatenação. Para realizar a concatenação de colunas de outros tipos utilize a função Cast para convertê-las em string antes.

Você também pode realizar operações matemáticas entre colunas existentes na instrução para gerar uma nova coluna com o resultado da operação. Veja o exemplo a seguir:

SELECT COD_VENDA, DATA_VENDA - DATA_PRIMEIRO_CONTATO AS TEMPO_PRA_VENDA
FROM VENDAS;

Na instrução anterior, criamos uma nova coluna de nome Tempo_pra_Venda, a qual é resultante da subtração das colunas Data_Venda e Data_Primeiro_Contato. O tipo do valor retornado pela coluna Tempo_pra_Venda será numérico trazendo o resultado da subtração das duas datas.

Utilizando Funções em instruções SQL

O InterBase e o Firebird suportam várias funções internas que podem ser utilizadas dentro de instruções SQL em geral.

Nota: Você pode adicionar ou criar suas próprias funções para utilização dentro do IB/FB através de UDF (Funções Definidas pelo Usuário).

A Função Cast

Podemos converter dados de um tipo para outro dentro de uma instrução SQL. Um exemplo de uso dessa função, por exemplo, seria a conversão de uma coluna do tipo numérico para VarChar para que a mesma possa ser concatenada com outra coluna ou valor durante o resultado de uma instrução Select.

Outra situação onde a função Cast pode ser útil, é em instruções de Insert que são geradas a partir de uma instrução Select para inclusão dos dados. Veja abaixo a sintaxe básica da função Cast:

CAST (COLUNA_ORIGEM AS NOVO_TIPO)

Você pode utilizar a instrução Cast para converter uma string, que possui um formato de data em uma data real, ou ainda, converter strings que possuem apenas valores numéricos em números inteiros ou flutuantes. Veja alguns exemplos de uso da instrução Cast:

SELECT CODIGO, CAST(DATA_VENDA AS CHAR(10)), 'VENDA: ' || CAST(NUM_VENDA AS VARCHAR(5))
FROM VENDAS
WHERE DATA_VENDA BETWEEN 'YESTERDAY' AND 'TODAY';

A Função Upper

Podemos converter todos os caracteres de uma string para maiúsculo. Essa função pode somente ser utilizada em colunas do tipo Char ou VarChar:

SELECT NOME, UPPER(NOME)
FROM CLIENTES;

Na instrução anterior, fazemos a comparação do campo cidade com o valor Curitiba, onde, para essa comparação, convertemos todos os valores da coluna Cidade para maiúsculo, garantindo assim que todos os fornecedores cadastrados para a cidade de Curitiba serão retornados no Select.

Nota: Para o uso da função Lower, verifique a biblioteca (DLL) que acompanha o InterBase, a qual contem diversas UDF’s para uso.

Tanto o InterBase quanto o Firebird, possuem ainda funções para que possamos agregar valores através de mais de uma linha de uma tabela. Através dessas funções de agregação, podemos coletar valores de várias linhas em uma única linha. Você pode, por exemplo, calcular a média de uma coluna que contem diversos valores, sua soma, maior valor ou menor valor etc.

A Função Sum

Podemos somar todos os valores de uma coluna especifica dentro de uma instrução SQL:

SELECT SUM(VALOR)
FROM VENDAS
WHERE COD_CLI = 10;

A Função Avg

Podemos calcular a média dos valores armazenados em uma determinada coluna utilizada dentro de uma instrução SQL:

SELECT AVG(IDADE)
FROM CLIENTES
WHERE NUM_DEPENDENTES = 2;

A Função Count

Podemos retornar o número total de linhas de uma determinada coluna:

SELECT COUNT(NOME)
FROM CLIENTES
WHERE DATA_CADASTRO > 'TODAY' – 265;

A Função Min

Podemos trazer o menor valor armazenado dentro de uma coluna especifica em uma instrução SQL:

SELECT MIN(VALOR)
FROM VENDAS;

A Função Max

Podemos trazer o maior valor encontrado dentro de uma coluna listada na instrução SQL:

SELECT MAX(QUANTIDADE)
FROM PEDIDOS
WHERE COD_REPRESENTANTE = 1203;

Nota: Quando você utiliza uma das funções de agregação, o servidor de banco de dados nomeia a coluna com o nome da função. Para renomear a coluna, especifique um alias para a mesma, através do operador As.

Quando utilizamos a função Count, normalmente é para trazer o número total de registros encontrados dentro da instrução SQL passada. Porém, podem surgir casos que você precise trazer a quantidade total dos registros retirando os valores duplicados. Para isso, utilize a função Count em conjunto com o comando Distinct:

SELECT COUNT(CIDADE), COUNT(DISTINCT(CIDADE))
FROM CLIENTES;

Na instrução anterior, trazemos na primeira coluna o número total de cidades encontradas na tabela Clientes, enquanto que na segunda coluna trazemos apenas o número total de cidades únicas (removendo as duplicadas) encontradas dentro da tabela Clientes.

Utilizando a cláusula Group By

Através da instrução Group By, podemos agrupar linhas dentro de instruções SQL para aumentar a funcionalidade das funções de agregação disponíveis. Através da linguagem SQL, você pode especificar quais colunas serão utilizadas para o agrupamento dos registros e quais serão utilizadas nos cálculos utilizando as funções de agregação.

A cláusula Group By deve sempre ser inserida após a cláusula Where e sempre antes da cláusula Order By. Como regra obrigatória, as colunas que forem listadas dentro da cláusula Group By devem sempre estar presentes na lista de colunas na cláusula Select da instrução SQL:

SELECT COLUNA1, COLUNA2, SUM(COLUNA3)
FROM LISTA_DE_TABELAS
WHERE CONDICOES
GROUP BY COLUNA1, COLUNA2
ORDER BY COLUNA1;

Veja alguns exemplos de uso da cláusula Group By:

SELECT C.NOME, SUM(V.VALOR)
FROM CLIENTES C, VENDAS V
WHERE V.COD_CLI = C.COD_CLI
GROUP BY C.NOME
ORDER BY C.NOME;

Na instrução anterior, trazemos a soma de todas as vendas cadastradas agrupadas e ordenadas por cliente.

SELECT E.SIGLA, C.CIDADE, AVG(P.VALOR) AS VALOR_MEDIO
FROM ESTADOS E, CIDADES C, PEDIDOS P
WHERE P.COD_CIDADE = C.COD_CIDADE
AND C.COD_ESTADO = E.COD_ESTADO
GROUP BY E.SIGLA, C.CIDADE
ORDER BY E.SIGLA, C.CIDADE

Na instrução anterior, trazemos o valor médio dos pedidos cadastrados agrupados por estado e por cidade.

SELECT R.NOME, COUNT(F.NOME)
FROM REGIOES R, FORNECEDORES F
WHERE F.REG_CODIGO = R.REG_CODIGO
GROUP BY R.NOME
ORDER BY R.NOME;

Na instrução anterior, trazemos a quantidade total de fornecedores agrupados e ordenados por região.

Utilizando a cláusula Having

Através da cláusula Having, podemos trazer uma soma ou contagem, mas apenas com os resultados onde o valor retornado pela função de agregação atinja uma determinada condição:

SELECT C.NOME, COUNT(V.COD_VENDAS)
FROM VENDAS V, CLIENTES C
WHERE V.COD_CLI = C.COD_CLI
GROUP BY C.NOME;

Na instrução anterior, trazemos a quantidade total de vendas agrupadas por cliente. Caso quiséssemos trazer apenas os clientes que tiveram mais de 15 vendas cadastradas, devemos montar a seguinte instrução SQL:

SELECT C.NOME, COUNT(V.COD_VENDAS)
FROM VENDAS V, CLIENTES C
WHERE V.COD_CLI = C.COD_CLI
GROUP BY C.NOME
HAVING COUNT(V.COD_VENDAS) > 15;

Tipos de Joins

Quando utilizamos um Join para fazer a união de duas ou mais tabelas, afim de trazer o resultado contendo as informações solicitadas, os resultados são incluídos apenas onde os valores unidos aparecem em ambas as tabelas.

Vamos analisar o seguinte exemplo: Suponhamos que em nosso banco de dados, tenhamos duas tabelas, uma com o cadastro de médicos e outra com o cadastro das consultas dos mesmos. Veja a seguinte instrução SQL:

SELECT M.NOME, COUNT(C.CODIGO)
FROM MEDICOS M
JOIN CONSULTAS C ON (C.COD_MEDICO = M.COD_MEDICO)
GROUP BY M.NOME;

Na instrução SQL anterior, trazemos a quantidade total de consultas para cada médico cadastrado. Este tipo de Join é conhecido como Inner Join, apesar da palavra Inner não ser obrigatória dentro da instrução SQL. E se nós precisássemos trazer os médicos que não possuem nenhuma consulta cadastrada, porém estão cadastrados dentro da tabela Medicos.

A instrução anterior, não trás esses médicos, e sim, apenas os que possuem pelo menos uma consulta cadastrada na tabela Consultas. Para resolver esse problema, devemos realizar um Join do tipo Outer Join. Existem três tipos de Outer Join’s:

  • Left Outer Join: Inclui todas as linhas da tabela do lado esquerdo da expressão Join;
  • Right Outer Join: Inclui todas as linhas da tabela do lado direito da expressão Join;
  • Full Outer Join: Inclui todas as linhas de ambas as tabelas utilizadas na expressão.

Veja a seguir, a instrução SQL para trazer todos os médicos cadastrados, mesmo que não tenham consultas referenciadas a eles:

SELECT M.NOME, COUNT(C.CODIGO)
FROM MEDICOS M
LEFT JOIN CONSULTAS C ON (C.COD_MEDICO = M.COD_MEDICO)
GROUP BY M.NOME;

Utilizando o Join do tipo Left Join, trazemos todos os registros da tabela Medicos (lado esquerdo da expressão Join), mesmo que alguns deles não possuam registros relacionados na tabela Consultas.

Utilizando SubQueries

Quando utilizamos uma instrução Select, podemos utilizar dentro de sua cláusula Where, outra instrução Select, desde que a mesma retorne apenas um valor simples, ou uma coluna contendo um conjunto de valores que podem ser utilizados para o filtro da instrução Select mais externa.

Quando utilizamos instruções de Select dentro de outra instrução Select, estamos utilizando uma SubQuery. Nos próximos exemplos, vamos utilizar uma instrução Select que retorna um único valor ou uma única coluna para ser utilizada pelo Select principal. No exemplo a seguir, fazemos um Select para trazer todos os produtos de todos os fabricantes que residem em um estado específico:

SELECT CODIGO_PRODUTO, DESCRICAO_PRODUTO, VALOR_PRODUTO
FROM PRODUTOS
WHERE CODIGO_FORNECEDOR IN (
  SELECT CODIGO_FORNECEDOR
  FROM FORNECEDORES
  WHERE UF = 'RJ');

Na instrução (query) a seguir, fazemos a busca por todos os pedidos que possuem o tipo definido como “Y”, fazendo a busca através da coluna Num_Pedido da tabela:

SELECT CODIGO, NUM_PEDIDO, DATA_PEDIDO, TIPO
FROM PEDIDOS
WHERE NUM_PEDIDO = (
  SELECT NUM_PEDIDO
  FROM PEDIDOS
  WHERE TIPO = 'Y');

Utilizando os operadores All e Any

Vamos imaginar a seguinte situação: suponhamos que você precise trazer todos os pedidos que são maiores que os pedidos de um cliente específico. Para conseguir fazer essa instrução SQL, você pode utilizar o operador All. Veja o exemplo:

SELECT CODIGO, CODIGO_CLIENTE, DATA, VALOR
FROM PEDIDOS
WHERE VALOR > ALL (
  SELECT VALOR
  FROM PEDIDOS
  WHERE CODIGO_CLIENTE = 200);

Quando utilizamos a expressão All, o servidor de banco de dados compara todas as linhas retornadas na subquery para verificar o seu valor. Nesse caso, podemos substituir a instrução anterior pela seguinte:

SELECT CODIGO, CODIGO_CLIENTE, DATA, VALOR
FROM PEDIDOS
WHERE VALOR > (
  SELECT MAX(VALOR)
  FROM PEDIDOS
  WHERE CODIGO_CLIENTE = 200);

Dessa maneira, a subquery gera um único registro trazendo o pedido de maior valor do cliente de código 200. Nesse caso, a comparação será feita em apenas um registro, aumentando consideravelmente a performance da instrução SQL.

Nota: Caso você esteja utilizando a expressão All, você pode utilizar a função Min para aumentar a performance da consulta.

Você pode também utilizar dentro de instruções SQL, o operador Any, o qual tem como sinônimo o operador Some:

SELECT CODIGO, CODIGO_CLIENTE, DATA, VALOR
FROM PEDIDOS
WHERE VALOR > ANY (
  SELECT VALOR
  FROM PEDIDOS
  WHERE CODIGO_CLIENTE = 200);

Nesse caso, retornamos todos os pedidos que são maiores que qualquer pedido feito pelo cliente de código 200. Como no caso da query que utiliza o operador All, esse método não é muito eficiente para realizar a busca, devido as inúmeras comparações que terão que ser realizadas dentro da subquery. Sempre que você utilizar a expressão Any, utilize no lugar a função Min. Caso a expressão seja Any, utilize então a função Max.

Nota: SubQuery’s que retornam um único valor são muito eficientes, e, caso tenham um índice vinculado na coluna sendo testada, sua performance será maior ainda. Nos exemplos mostrados, a coluna que precisaria de um índice seria a coluna Valor.

Relacionados a Programação

Saiba mais sobre SQL ;)

  • Curso de SQL:
    A linguagem SQL é amplamente utilizada em diversos tipos de aplicações que utilizem bancos de dados relacionais.
  • Guias Banco de Dados:
    Aqui você encontra o Guia de estudo ideal para aprimorar seus conhecimentos nos principais Banco de Dados do mercado. Escolha o seu e bons estudos!
  • Banco de Dados para Programadores:
    Neste guia você encontrará os principais conteúdos que você precisa estudar, como desenvolvedor, para trabalhar com bancos de dados.