T301B SQL Structure Query Language Luis Fernando Calábria Erick Franklin Leonardo Bandeira SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA Sumário 1. 2. INTRODUÇÃO 3 1.1. 1.2. 1.3. 1.4. 1.5. 3 3 4 4 5 A LINGUAGEM SQL 6 2.1. 2.2. 2.3. 6 7 7 7 7 8 8 2.4. 3. 5. 6. 7. CRIANDO UMA TABELA IDENTIFICADORES E ATRIBUTOS TIPOS DE DADOS 2.3.1. DADOS CARACTERES “STRINGS” 2.3.2. DADOS NUMÉRICOS 2.3.3. DADOS DATA E HORA INCLUINDO DADOS QUERIES: OBTENDO OS DADOS DESEJADOS 3.1. 3.2. 4. SOBRE SQL VISÃO GERAL DE UM BANCO DE DADOS RELACIONAL COLUNAS E LINHAS ENTIDADES E CHAVE PRIMÁRIA CHAVE PRIMÁRIA COMPOSTA CLÁUSULAS SELECT E FROM CLÁUSULA WHERE 3.2.1. PREDICADOS RELACIONAIS 3.2.2. OUTROS PREDICADOS RELACIONAIS 3.2.3. VINCULANDO VÁRIOS PREDICADOS: AND E OR 9 9 10 11 11 13 QUERIES: MANIPULANDO DADOS 14 4.1. 4.2. 14 15 15 15 16 16 OPERADORES ARITMÉTICOS FUNÇÕES 4.2.1. FUNÇÕES AGREGADAS 4.2.2. FUNÇÕES NÃO AGREGADAS 4.2.3. FUNÇÕES DE SEQÜÊNCIAS DE CARACTERES 4.2.4. FUNÇÕES DE DATA E HORA ORGANIZANDO O RESULTADO 17 5.1. 5.2. 5.3. 17 17 18 CLÁUSULA GROUP BY CLÁUSULA HAVING CLÁUSULA ORDER BY JUNÇÕES: QUERIES QUE ENVOLVEM MAIS DE UMA TABELA 19 6.1. 6.2. 6.3. 6.4. EQUIJUNÇÕES JUNÇÕES EXTERNAS AUTO-JUNÇÕES OUTROS TIPOS DE JUNÇÕES 20 21 21 23 QUERIES EM OUTRAS DECLARAÇÕES 23 7.1. 7.2. 23 23 DECLARAÇÃO UNION UTILIZANDO QUERIES PARA INCLUIR DADOS Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 1 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA 8. ALTERANDO TABELAS E DADOS 24 8.1. 24 24 25 25 25 26 26 27 27 27 8.2. 9. 10. ALTERANDO OS DADOS 8.1.1. ATUALIZANDO DADOS EM UMA LINHA 8.1.2. ELIMINANDO LINHAS 8.1.3. GRAVANDO E DESFAZENDO ALTERAÇÕES ALTERANDO UMA TABELA 8.2.1. ELIMINANDO UMA COLUNA 8.2.2. INCLUINDO UMA COLUNA 8.2.3. MODIFICANDO UMA COLUNA 8.2.4. TROCANDO O NOME DE UMA TABELA OU COLUNA 8.2.5. ELIMINANDO UMA TABELA UTILIZANDO ÍNDICE PARA MELHORAR A PERFORMANCE 28 9.1. 9.2. 9.3. 9.4. 28 28 29 29 UTILIZANDO UM ÍNDICE UTILIZANDO UM ÍNDICE ÚNICO UTILIZANDO UM ÍNDICE CONCATENADO APAGANDO UM ÍNDICE PROGRAMANDO EM SQL 30 10.1. 10.2. 30 30 PORQUE SQL EMBUTIDA UTILIZANDO A FERRAMENTA ACCESS Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 2 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA 1.Introdução 1.1. Sobre SQL Um banco de dados é como um arquivo eletrônico, ou seja, tem a mesma função que qualquer outro arquivo — armazenar registros. A única diferença é que no banco de dados os registros são armazenados eletronicamente. Para termos acesso aos registros armazenados ou mesmo cadastrar novos registros, precisamos de um sistema que gerencie o banco de dados. Este sistema gerenciador de banco de dados é que torna possíveis as operações com o conteúdo do arquivo, como — “Traga-me este arquivo”, “Atualize este registro”. Existem vários tipos de sistemas de gerenciamento de banco de dados (SGBD ou DBMS), representando diversas abordagens relativas às tarefas de acesso às informações contidas no banco de dados, preservação da integridade dos dados, acompanhamento dos usuários e manutenção da segurança. Para o nosso estudo, porém, podemos classificar todos os sistemas em dois tipos: relacionais e não relacionais, embora seja visível o predomínio da abordagem relacional nos novos sistemas do mercado. Em um sistema relacional, os dados são armazenados e representados exclusivamente em tabelas. Em nenhum momento faz-se necessário recorrer a outras estruturas, como árvores hierárquicas, para ter acesso aos dados. A linguagem SQL — o nome é a sigla de Structured Query Language (Linguagem de Query Estruturada) — é uma linguagem para gerenciar um sistema de banco de dados relacional. Não só é uma linguagem, como também tem sido tão utilizada que pode ser considerada um padrão. Consiste de uma série de declarações, adotadas de comum acordo, que nos permitem realizar diversas operações. Temos que usar a expressão comum acordo porque, embora uma SQL padrão tenha sido criada pelo Instituto de Padrões Nacionais Americanos (ANSI), todas as implementações particulares da SQL personalizam a linguagem de várias formas. Tais implementações complementam a linguagem padrão com novos tipos de declarações ou expressões e muitas vezes adaptam as declarações padronizadas às necessidades específicas. 1.2. Visão Geral de um Banco de Dados Relacional Sistemas relacionais caracterizam um grande avanço no armazenamento e no gerenciamento de grandes quantidades de dados. A principal razão para isso é que, em um sistema relacional, pode-se reduzir bastante o armazenamento de dados redundantes. Na verdade, idealmente falando, em um sistema projetado segundo os princípios teóricos da abordagem relacional, a redundância não deve existir. Nenhum relacionamento entre dois itens de dados (uma pessoa possui um endereço, por exemplo) deve aparecer mais de uma vez em cada um banco de dados. Na prática, os sistemas apenas se aproximam deste ideal, por várias razões, e podemos dizer que normalmente contêm alguns dados repetidos em vários lugares. Mas mesmo em um sistema relacional que apenas se aproxime da situação ideal, minimizar a redundância dos dados acarreta dois benefícios básicos: em primeiro lugar, os dados podem ser reorganizados e combinados de forma mais facilmente em novos relacionamentos; não ficam presos aos relacionamentos em que foram armazenados. Em segundo lugar, a atualização torna-se muito mais fácil, pois poucos itens de dados têm que ser atualizados, o que reduz a incidência de erros. Todos os dados de um sistema relacional são armazenados e exibidos em tabelas. Programas de planilhas e sistemas de banco de dados não relacionais também usam tabelas, portanto não é uma característica exclusiva dos sistemas relacionais. Mas há algo que distingue a forma como os sistemas relacionais usam tabelas. Esta distinção deriva-se da definição e da utilização do banco de dados segundo certos princípios teóricos da abordagem relacional. Mais adiante iremos abordar tais princípios. Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 3 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA 1.3. Colunas e Linhas Qualquer informação refere-se a qualquer coisa, e talvez o primeiro princípio da abordagem relacional seja o de todas as informações contidas em uma tabela devem estar sempre relacionadas a exemplos de “um tipo de coisa”. Este princípio destingue o uso relacional de tabelas. Por exemplo, a tabela HOSPEDES abaixo contém informações sobre os sócios de um clube de tratamento da forma física, selecionado, conceituado e imaginário chamado Visual Spa (fig. 1.1). Fig. 1.1 - HOSPEDES NOME JOSÉ AUGUSTO MAURÍCIO DE SOUZA BIANCA OLIVEIRA JANE FYUNDAI STELLA SHIELDS ROGÉRIO NUNES SEXO M M F F F M BIOTIPO M M G G M M ALTURA 1,67 1,72 1,65 1,80 1,65 1,78 A tabela possui quatro colunas — NOME, SEXO, BIOTIPO e ALTURA e 6 linhas. Contém informações sobre os hóspedes do Spa; cada coluna vertical possui dados referentes a uma característica ou atributo dos hóspedes. Os atributos em que estamos interessados são nome, sexo, biotipo e altura de cada hóspede; por isso destinamos uma coluna a cada um deles. Esta é a função das colunas verticais de uma tabela: conter informações sobre os atributos das entidades a que se refere a tabela. Cada linha horizontal da tabela HOSPEDE contém as informações sobre todos os atributos referentes a um determinado hóspede. Portanto, enquanto a coluna NOME exibe os nomes de todos os hóspedes da tabela e a coluna SEXO o sexo de todos os hóspedes e assim por diante em relação às outras colunas, a linha em que aparece o nome José Augusto contém informações apenas referentes aos atributos do hóspede chamado José Augusto. Mais adiante introduziremos um novo conceito relacional: o de chave primária. 1.4. Entidades e Chave Primária No mundo real, você teria inúmeras razões para querer tratar cada hóspede do Visual Spa individualmente: se você não considerá-los separadamente, não poderá designar os quartos adequadamente, elaborar os programas de emagrecimento segundo as necessidades de cada um, preparar as faturas corretamente, e assim por diante. Pelas mesmas razões, você terá que ter os hóspedes também individualizados no banco de dados. Em termos práticos, isto significa que as linhas da tabela devem ser diferenciadas. Se você não puder diferenciar a linha de José Augusto da de Maurício de Souza, o banco de dados não lhe dará condições para designar os quartos adequadamente, elaborar os programas de emagrecimento segundo as necessidades de cada um, preparar as faturas corretamente, e assim por diante. Para que uma linha possa se distinguir das outras, tem que ser de alguma forma diferente, ou seja, tem que ter uma característica que a identifique. Em um sistema relacional, esta característica identificadora não pode ser identificador externo, como a posição que a linha ocupa em relação às outras; tem que ser um dos próprios componentes da linha. Como a linha só consiste de itens de dados, temos que tentar localizar dentre os dados da linha aquele que poderá identificá-la univocamente. Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 4 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA Em outras palavras, temos que procurar por uma coluna (ou grupo de colunas) que apresente um conteúdo diferente em cada linha — dados que são duplicados em duas linhas. Esta característica então servirá para identificar a linha da mesma forma que usamos um nome para identificar uma pessoa. Volte à tabela HÓSPEDE (fig. 1.1). Observe que nem todos os atributos, ou colunas, são igualmente suficientes para identificar as linhas. Por exemplo, não basta saber apenas o sexo de um hóspede que você queira identificar se este atributo é compartilhado por metade dos seus hóspedes. Da mesma forma, se soubermos o biotipo de um hóspede teremos um grupo mais reduzido mas não conseguiremos localizar um hóspede em particular. O problema é que as colunas SEXO e BIOTIPO contêm valores duplicados. Quando duas linhas contêm o mesmo atributo, este atributo não pode ser usado para distinguir as linhas entre si. Concluindo, a única coluna que pode servir de atributo identificador é a coluna NOME. Como não contém valores duplicados, as informações nela contidas são por si só suficientes para distinguir a linha de um hóspede na tabela. Descrevemos, na realidade, uma diferença entre os dois tipos de colunas. O primeiro tipo está baseado em um atributo que identifique univocamente ou defina uma linha. O segundo tipo baseia-se em atributos descritivos que fornecem informações, mas não são suficientes para identificar uma linha ou entidade. A coluna (ou grupo de colunas) baseada em um atributo identificador de uma linha é chamada de Chave ou Chave Primária. A chave de uma tabela lhe permite identificar as linhas individualmente, definindo também as entidades às quais a tabela se refere. Um banco de dados relacional todas as tabelas tem que ter uma chave primária que identifique cada linha. 1.5. Chave Primária Composta A chave primária pode consistir de mais de uma coluna, as vezes não podemos distinguir as linhas uma das outras usando apenas uma coluna, mais sim mais de uma. O exemplo a seguir lista o nome de todos os hóspedes que chegaram ou saíram no período entre 01 e 27/08/97; a data de chegada de cada hóspede, a data de saída — se houver —, o quarto e o técnico de cada hóspede e por último o desconto — se houver. Fig. 1.2 – LISTA DE HÓSPEDES NOME JANE FYUNDAI MARCELO FREITAS ALEXANDRE GOMES JOSÉ AUGUSTO MAURÍCIO DE SOUZA BIANCA OLIVEIRA JANE FYUNDAI STELLA SHIELDS ALEXANDRE GOMES QUARTO 4 2 1 3 5 6 7 8 9 TÉCNICO JÚLIO BRUNA RICARDO JÚLIO RICARDO BRUNA SERENA SERENA BRUNA CHEGADA 15-08-1997 26-08-1997 14-08-1997 15-08-1997 25-08-1997 15-08-1997 24-08-1997 25-08-1997 17-08-1997 SAÍDA 17-08-1997 DESCTO 0.20 0.10 16-08-1997 19-08-1997 20-08-1997 0.15 0.05 23-08-1997 0.15 0.20 Nenhuma das colunas por si só poderá funcionar como chave primária, pois todas elas possuem valores duplicados, inclusive NOME: Alexandre Gomes e Jane Fyundai estiveram hospedados duas vezes e por isso aparecem duas vezes na lista. Para estabelecermos uma chave para esta tabela, teremos que usar duas ou mais colunas conjuntamente. Este tipo de chave, envolvendo duas ou mais colunas, denomina-se chave composta ou chave primária composta. No exemplo (Fig. 1.2) as colunas que melhor se candidatam a formar chave composta são NOME e CHEGADA. O NOME e a CHEGADA combinados lhe permite distinguir uma linha da outra, ou seja, não há linhas com os valores de NOME e CHEGADA iguais. Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 5 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA 2.A Linguagem SQL SQL é uma linguagem própria para a realização de operações relacionais. Em linhas gerais, é uma linguagem para gerenciar um sistema relacional. Através das declarações SQL, dados são recuperados, atualizados ou eliminados, colunas são alteradas, tabelas são criadas e eliminadas, e qualquer outras modificações são efetuadas na estrutura de um banco de dados. As declarações em SQL podem ser subdivididas em quatro categorias: queries, definição de dados, manipulação de dados e controle de dados. 2.1. Criando uma Tabela Usamos a declaração CREATE TABLE para criar uma tabela. As declarações abaixo criam as duas tabelas que já vimos anteriormente — HÓSPEDES e LISTA DE HÓSPEDES. A tabela HÓSPEDES contém os dados de todos os hóspedes do Visual Spa, passados e atuais. A tabela LISTA DE HÓSPEDES registra as datas de entrada e saída, quartos ocupados, etc., de todas as pessoas que se hospedaram no spa no período de 01 e 27/08/1997. Observe que as declarações a seguir apenas criam as tabelas. Preenchê-las com dados constitui uma outra operação, que veremos posteriormente. CREATE TABLE HOSPEDES (NOME VARCHAR(25) NOT NULL, SEXO VARCHAR(1), BIOTIPO VARCHAR(1), ALTURA DECIMAL(3,2)); CREATE TABLE LISTA_DE_HOSPEDES (NOME VARCHAR(25) NOT NULL, QUARTO VARCHAR(3), TECNICO VARCHAR(8), CHEGADA DATE NOT NULL, SAIDA DATE, DESCONTO DECIMAL(2,2); As tabelas HOSPEDES e LISTA_DE_HOSPEDES já existem, embora vazias. A tabela HOSPEDES consiste das quatro colunas NOME, SEXO, BIOTIPO e ALTURA; a LISTA_DE_HOSPEDES consiste das seis colunas NOME, QUARTO, TECNICO, CHEGADA, SAIDA e DESCONTO. Observe que ambas das declarações CREATE TABLE terminam com um ponto e vírgula (;). Este é o sinal de que a declaração terminou. Embora esta não seja propriamente uma característica da SQL, todas as implementações interativas da SQL exigem um sinal indicativo de final de declaração. Algumas interfaces interativas, oferecem duas formas de marcar o término de uma declaração. A primeira e colocar um ponto e vírgula seguido de um retorno <ENTER> no final da última linha da declaração; a segunda e colocar na linha seguinte à última linha da declaração uma barra (/) e um retorno <ENTER> como mostramos nos exemplos abaixo: SELECT NOME, ALTURA FROM HOSPEDES; ou SELECT NOME, ALTURA FROM HOSPEDES / Ambos os métodos são muito usados, nesta apostila terminamos as declarações normalmente com o ponto e vírgula. Não existe regra quanto ao número de linhas de uma declaração SQL. Poderíamos ter escrito a declaração toda em uma linha só, o que ocuparia menos espaço. O ponto e vírgula ou a barra é obrigatório somente no final da última linha da declaração. Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 6 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA 2.2. Identificadores e Atributos Observe os dois traços sublinhados ( ___ ) ligando as três palavras que compões o nome da tabela LISTA_DE_HOSPEDES. O traço sublinhado é um meio convencional para representar o espaço nos nomes de tabelas ou colunas que contêm mais de uma palavra. Ele têm por finalidade ligar uma palavra à outra, fazendo com que formem apenas um conjunto de caracteres, podendo se reconhecidas portanto como partes integrantes de um único nome. 2.3. Tipos de Dados A SQL padrão da ANSI reconhece dois tipos genéricos de dados — seqüências (“strings”) de caracteres de dados numéricos —, e oferece vários tipos particulares com diferentes características para atender às necessidades de cada coluna. Estes incluem CHAR (ou CHARACTER), para seqüências de caracteres, e os tipos NUMERIC, DECIMAL, INTEGER, SMALLINT, FLOAT, REAL, DOUBLE PRECISION, para dados numéricos. Existem diversos tipos de dados implementados para duas outras categorias de dados. Uma delas abrange os dados tipo data e hora, representados em SQL Base pelos tipos DATE, TIME, TIMESTAMP; a outra é o tipo de dado LONG VARCHAR ou LONG, tipo genérico que pode armazenar qualquer categoria de dados, inclusive dados binários. Em SQL Base, os dados do tipo LONG podem ter um tamanho virtual qualquer (bilhões de bytes); em outras implementações, o limite normalmente é de 64 Kbytes. 2.3.1. Dados Caracteres “Strings” O tipo CHAR armazena seqüências de caracteres de tamanho fixo que consistem de letras, caracteres especiais ou dígitos, e cujo tamanho não pode ultrapassar 254 bytes. O tamanho máximo (até 255 caracteres) a ser aceito em uma coluna deve ser definido quando, ao criá-la, especificamos o atributo de tamanho. Todos os dados desta coluna são armazenados com o tamanho indicado quando da sua definição. Em SQL padrão, quando um dado possui um tamanho menor ao especificado para a coluna, espaços em branco são acrescentados à direita. Em SQL Base, estes dados podem definidos como CHAR ou VARCHAR. 2.3.2. Dados Numéricos O tipo NUMBER armazena números de 1.0E-100 a 1.0E+100, com, no máximo, 22 dígitos decimais de precisão. As colunas deste tipo não possuem indicações de precisão e escala em suas definições. O tipo DECIMAL armazena números de 1.0E-100 a 1.0E+100, com no máximo 22 dígitos decimais de precisão, mas, ao contrário do tipo NUMBER, as colunas DECIMAL têm que ter indicações de precisão e escala em suas definições. O tipo INTEGER armazena um número com até dez dígitos de precisão. Não são aceitos dígitos fracionários; os algarismos à direita do ponto decimal são truncados. O tipo SMALLINT armazena um número com até cinco dígitos de precisão. Da mesma forma que o tipo INTEGER, não são aceitos dígitos fracionários, os quais são truncados. O tipo FLOAT armazena um número decimal de ponto flutuante de dupla precisão ou precisão simples, dependendo da especificação de tamanho. Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 7 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA 2.3.3. Dados Data e Hora O tipo DATE armazena datas, que podem ser codificadas e exibidas em diversos formatos. O tipo TIME armazena horas, registrando até os microssegundos, sendo que podem também ser codificados e exibidas em diversos formatos. O tipo TIMESTAMP é usado em colunas criadas para armazenar data e hora ao mesmo tempo. Este tipo é uma combinação dos formatos DATE e TIME, sendo que os dados contêm ambos os componentes data e hora. Veja na tabela seguinte os formatos de datas convencionais mais importantes: Tabela – Formatos de Datas Nome Formato Exemplo Organizações de Padrões Intern. aaaa-mm-dd 1998-10-30 Padrão IBM — EUA (USA) mm/dd/aaaa 10/30/1998 Padrão IBM — Europa (EUR) dd.mm.aaaa 30.10.1998 Padrão Industrial Japonês (JIS) aaaa-mm-dd 1998-10-30 Veja na tabela seguinte os formatos de datas convencionais mais importantes: Tabela – Formatos de Horas 2.4. Nome Formato Exemplo Organizações de Padrões Intern. hh.mm.ss 14.30.02 Padrão IBM — EUA (USA) hh:mm AM ou PM 2:30 PM Padrão IBM — Europa (EUR) hh.mm.ss 14.30.02 Padrão Industrial Japonês (JIS) hh:mm:ss 14:30:02 Incluindo Dados A declaração CREATE TABLE mostrada no início apenas criou as tabelas HOSPEDES e LISTA_DE_HOSPEDES, sem preenchê-las com dados. Para incluir dados nas tabelas, usamos uma outra declaração ou comando. Na linguagem SQL a única forma de incluir dados é através da declaração INSERT, que normalmente inclui uma única linha de cada vez. Só pode ser utilizada para incluir várias linhas se nela for inserida uma query que recupere de outra tabela os dados a serem incluídos. A declaração SQL abaixo ilustra a inclusão de uma única linha de dados na tabela LISTA_DE_HOSPEDES. A linha consiste de seis itens de dados, separados por vírgulas – um item para cada uma das seis colunas da tabela LISTA_DE_HOSPEDES. O primeiro item de dados é incluído na primeira coluna da tabela, o segundo item na segunda coluna, e assim por diante, como se segue: INSERT INTO LISTA_DE_HOSPEDES (NOME, QUARTO, TECNICO, CHEGADA, SAIDA, DESCONTO) VALUES (‘CLOVIS ALMEIDA’, ‘3’, ‘JULIO’, 13-08-1997, 17-08-1997, .2; Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 8 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA Como estamos incluindo dados em todas as colunas da tabela LISTA_DE_HOSPEDES, poderíamos omitir a lista dos nomes das colunas após o nome da tabela. Esta lista só é indispensável caso estejamos incluindo dados em apenas algumas colunas e não em todas; temos então que indicar os nomes das colunas que receberão dados. Nomeamos todas as colunas neste exemplo simplesmente para facilitar análise da declaração. Observe que os dados referentes às colunas NOME, QUARTO e TECNICO estão entre apóstrofes (‘). Isto se deve ao fato de que os dados das três colunas são do tipo VARCHAR. Dados CHAR ou VARCHAR usados em declarações SQL devem aparecer entre apóstrofes. 3.Queries: Obtendo os Dados Desejados A query é o meio através do qual podemos pesquisar e obter dados das tabelas de um banco de dados. A seguir abordamos os seus elementos básicos, inclusive as duas cláusulas essenciais obrigatórias em todas as queries e uma terceira que contém a especificação das linhas em que estão os dados desejados. 3.1. Cláusulas SELECT e FROM Por mais básica que seja, uma query tem que ter pelo menos dois componentes — uma cláusula SELECT e uma cláusula FROM. Em uma query simples, a cláusula SELECT enumera os nomes das colunas que contêm os dados desejados, e a FROM especifica as tabelas em que estão localizadas as colunas. A query mais simples possível seleciona todos os dados de todas as colunas da tabela. Entretanto, podemos restringir a cláusula SELECT de modo que se obtenha dados de apenas algumas colunas, ou, de outras formas, acrescentando qualificações. Podemos citar na cláusula SELECT colunas de mais de uma tabela, além de especificar várias operações a serem executadas sobre os dados e exibir os resultados das mesmas. O resultado da query é exibido em forma de tabela e é, às vezes, chamado de tabela resultado. As linhas do resultado representam os dados que atendem às condições estabelecidas ou são o produto das operações especificadas na query. Se não houver dados em nenhuma destas situações, não serão selecionadas linhas. Analisemos um exemplo de uma query e seu resultado. SELECT NOME, QUARTO, TECNICO, CHEGADA, SAIDA, DESCONTO FROM LISTA_DE_HOSPEDES; NOME JANE FYUNDAI MARCELO FREITAS JANE FYUNDAI ALEXANDRE GOMES JOSÉ AUGUSTO MAURÍCIO DE SOUZA BIANCA OLIVEIRA STELLA SHIELDS ALEXANDRE GOMES QUARTO 3 2 4 1 7 5 6 8 9 TÉCNICO JÚLIO BRUNA SERENA RICARDO JÚLIO RICARDO BRUNA SERENA BRUNA CHEGADA 15-08-1997 26-08-1997 24-08-1997 14-08-1997 15-08-1997 25-08-1997 15-08-1997 25-08-1997 17-08-1997 SAÍDA 17-08-1997 DESCTO 0.20 0.10 16-08-1997 19-08-1997 20-08-1997 23-08-1997 0.15 0.05 0.15 0.20 A query acima solicita todas as linhas de dados para todas as colunas da tabela LISTA_DE_HOSPEDES. Não acrescentamos qualificações, e, portanto, o resultado contém todos os dados destas colunas. Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 9 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA Incidentemente, podemos usar um asterisco (*) em vez de nomes de colunas na cláusula SELECT. O asterisco representa “os valores de todas as colunas”. Usar o asterisco é o mesmo que nomear todas as colunas de uma tabela ou mais tabelas, na sua ordem original. Portanto, ao invés de digitar todos os nomes de colunas como fizemos no exemplo anterior, poderíamos ter obtido o mesmo resultado codificando a query assim: SELECT * FROM LISTA_DE_HOSPEDES; Podemos selecionar de apenas algumas colunas e omitir outras. A query a seguir obtém os dados somente da coluna NOME: SELECT NOME FROM LISTA_DE_HOSPEDES; Podemos evitar que dados sejam exibidos duplicados, usando a palavra-chave DISTINCT imediatamente após a palavra “SELECT” na cláusula SELECT para suprimir as linhas duplicadas do resultado. No exemplo abaixo a palavra-chave DISTINCT foi acrescentada na query anterior: SELECT DISTINCT NOME FROM LISTA_DE_HOSPEDES; A palavra-chave DISTINCT suprime apenas as linhas duplicadas do resultado, e não valores duplicados. 3.2. Cláusula WHERE A cláusula WHERE reduz o escopo da query focalizando apenas determinadas linhas. Ao invés de retornar os valores das expressões da cláusula SELECT de todas as linhas, uma query com uma cláusula WHERE retorna apenas os valores das linhas que atendam às condições especificadas na cláusula WHERE. Em outras palavras, uma query contendo a cláusula WHERE tem essencialmente o seguinte formato: SELECT o valor das expressões FROM estas tabelas somente nas linhas WHERE estas condições foram atendidas. As condições da cláusula WHERE são chamadas de condições de pesquisa. O exemplo abaixo seleciona dados das colunas NOME e TECNICO da tabela LISTA_DE_HOSPEDES somente nas linhas em que o técnico for a Bruna. Em outras palavras, a query lista os nomes (e técnicos) de todas as pessoas cujo o técnico seja a Bruna: SELECT NOME, TECNICO FROM LISTA_DE_HOSPEDES WHERE TECNICO = ‘BRUNA’; NOME MARCELO FREITAS BIANCA OLIVEIRA ALEXANDRE GOMES TÉCNICO BRUNA BRUNA BRUNA Não é obrigatório citar na cláusula WHERE somente colunas que apareçam na cláusula SELECT. A query anterior funcionaria da mesma forma se eliminássemos a coluna TECNICO da cláusula SELECT. SELECT NOME FROM LISTA_DE_HOSPEDES WHERE TECNICO = ‘BRUNA’; Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 10 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA NOME MARCELO FREITAS BIANCA OLIVEIRA ALEXANDRE GOMES 3.2.1. Predicados Relacionais No exemplo anterior, TECNICO = ‘BRUNA’ é um predicado relacional. O sinal de igualdade (=) é um operador relacional simples. Existem nove operadores relacionais simples, que podem formar nove tipos de predicados relacionais simples para expressar condições de pesquisa. Existem ainda cinco outros tipos de predicados relacionais. Discutiremos todos os tipos existentes nos próximos tópicos. Predicados Relacionais Simples A query utilizada no último exemplo foi: SELECT NOME FROM LISTA_DE_HOSPEDES WHERE TECNICO = ‘BRUNA’; Como já foi dito, a query contém um operador relacional simples, o sinal de igualdade. Seu significado seria traduzido assim: SELECT o valor de NOME e TECNICO FROM tabela LISTA_DE_HOSPEDES somente nas linhas WHERE o valor de TECNICO seja igual a ‘BRUNA’; Os operadores relacionais simples são os nove abaixo: = != <> igual a não igual a não igual a > !> < maior que não maior que menor que !< >= <= não menor que maior ou igual a menor ou igual a 3.2.2. Outros Predicados Relacionais Além dos operadores já discutidos, há outros cinco que também podem ser usados para formar predicados relacionais. São eles: BETWEEN...AND IS NULL LIKE IN O operador BETWEEN especifica os dados compreendidos em uma determinada faixa. Pode ser usado tanto com números quanto com datas. Por exemplo, poderíamos obter os nomes e os percentuais de desconto de todos os hóspedes que tenham recebido de 10 a 20 por cento inclusive, como se segue: SELECT NOME, DESCONTO FROM LISTA_DE_HOSPEDES WHERE DESCONTO BETWEEN .10 AND .20; NOME JANE FYUNDAI MARCELO FREITAS MAURÍCIO DE SOUZA STELLA SHIELDS ALEXANDRE GOMES DESCTO 0.20 0.10 0.15 0.15 0.20 Podemos solicitar também os nomes e as datas de saída de todos os hóspedes que saíram do Spa entre 19 e 24 de agosto: Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 11 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA SELECT NOME, SAIDA FROM LISTA_DE_HOSPEDES WHERE SAIDA BETWEEN 19-08-1997 AND 24-08-1997; NOME JOSE AUGUSTO BIANCA OLIVEIRA ALEXANDRE GOMES SAIDA 19-08-1997 20-08-1997 23-08-1997 O operador IS NULL nos permite selecionar as linhas em que o valor de um determinado campo seja desconhecido. Por exemplo, as linhas de vários hóspedes ficaram com a SAIDA em branco. Podemos selecionar os nomes destes hóspedes utilizando o operador IS NULL. SELECT NOME, SAIDA FROM LISTA_DE_HOSPEDES WHERE SAIDA IS NULL; NOME MARCELO FREITAS JANE FYUNDAI STELLA SHIELDS SAIDA O operador LIKE nos permite utilizar caracteres máscara para comparar dados em uma condição de pesquisa. Em vez de os dados terem que ser idênticos, podemos especificar que sejam apenas semelhantes em algum aspecto. Podemos usar os dois caracteres máscara abaixo com o operador LIKE: _ (sublinhado) * (asterisco) Vale por qualquer caractere único Vale por qualquer seqüência de caracteres No contexto de um LIKE, o caractere de sublinhado ( _ ) funciona analogamente ao ponto de interrogação (?) do MS-DOS, que serve de caractere máscara em nomes de arquivos, e o símbolo de percentual (%) funciona analogamente ao asterisco (*). O exemplo de query abaixo usa o operador LIKE e um caractere máscara para selecionar todos os nomes que comecem com a seqüência de caracteres ‘MA%’; SELECT NOME FROM LISTA_DE_HOSPEDES WHERE NOME LIKE ‘MA%’; NOME MARCELO FREITAS MAURICIO DE SOUZA A próxima query seleciona todos os nomes que tenham a letra J na primeira posição e N na quarta, não importando quais sejam os outros caracteres. SELECT NOME FROM LISTA_DE_HOSPEDES WHERE NOME LIKE ‘J__N’; NOME JANE FYUNDAI Mais um exemplo: SELECT NOME FROM LISTA_DE_HOSPEDES WHERE NOME LIKE ‘_AR_E%’; Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 12 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA NOME MARCELO FREITAS O último operador a ser discutido neste tópico é o IN, que nos permite selecionar dados que se encaixem em um conjunto ou uma lista de valores. Os valores podem ser indicados explicitamente em uma declaração, como nos exemplos a seguir. A query abaixo seleciona o nome, o técnico e o quarto de cada hóspede cujo o técnico esteja presente na lista ‘BRUNA’, ‘JULIO’: SELECT NOME, TECNICO, QUARTO FROM LISTA_DE_HOSPEDES WHERE TECNICO IN (‘BRUNA’, ‘JULIO’); NOME JANE FYUNDAI MARCELO FREITAS JOSÉ AUGUSTO BIANCA OLIVEIRA ALEXANDRE GOMES TÉCNICO JÚLIO BRUNA JÚLIO BRUNA BRUNA QUARTO 3 2 4 6 9 Todos os operadores relacionais também podem ser utilizados com o NOT. Na query abaixo, selecionamos o nome, o técnico e o quarto dos hóspedes cujo o técnico não esteja incluído na lista: SELECT NOME, TECNICO, QUARTO FROM LISTA_DE_HOSPEDES WHERE TECNICO NOT IN (‘BRUNA’, ‘JULIO’); NOME ALEXANDRE GOMES MAURÍCIO DE SOUZA JANE FYUNDAI STELLA SHIELDS QUARTO 1 5 7 8 TÉCNICO RICARDO RICARDO SERENA SERENA 3.2.3. Vinculando Vários Predicados: AND e OR Podemos restringir ainda mais a seleção de linhas usando uma cláusula WHERE com mais de uma condição de pesquisa. Isto se faz possível através dos operadores AND e OR. Na query abaixo, selecionamos o nome, o técnico e o desconto dos hóspedes que ainda estão no Spa e cujo o técnico seja Serena: SELECT NOME, TECNICO, DESCONTO FROM LISTA_DE_HOSPEDES WHERE SAIDA IS NULL AND TECNICO = ‘SERENA’ NOME JANE FYUNDAI STELLA SHIELDS TÉCNICO DESCTO SERENA SERENA 0.15 Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 13 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA Podemos acrescentar inúmeras condições à cláusula WHERE usando os operadores AND e OR. A próxima query acrescenta vários componentes: SELECT NOME, QUARTO, TECNICO, CHEGADA, SAIDA FROM LISTA_DE_HOSPEDES WHERE SAIDA IS NULL AND TECNICO = ‘ROBERTO’ AND QUARTO > 16 AND CHEGADA < 20-08-97; 4.Queries: Manipulando Dados A linguagem SQL não nos limita a selecionar os dados exatamente na forma que aparecem nas tabelas. Como mencionamos anteriormente, podemos usar queries também para selecionar os resultados de operações realizadas sobre os dados. Neste tópico, descrevemos três elementos que viabilizam as operações realizadas sobre os dados em uma query. São eles: Operador aritmético; Funções agregadas; Funções não agregadas. Em cada caso, o operador ou função é usado com constantes, nomes de colunas e assim por diante para formar uma expressão nova. 4.1. Operadores Aritméticos São quatro os operadores aritméticos que podem formar expressões: + * / adição subtração multiplicação divisão A query abaixo, usamos o operador de soma para adicionar 0.05 (uma constante) ao valor corrente de DESCONTO na linha de Marcelo Freitas. A cláusula SELECT contém duas expressões: NOME e a expressão formada pelo operador aritmético, DESCONTO + 0.05. A tabela resultado deverá conter duas colunas, uma para cada expressão: SELECT NOME, DESCONTO + 0.05 FROM LISTA_DE_HOSPEDES WHERE NOME = ‘MARCELO FREITAS’ NOME MARCELO FREITAS DESCTO 0.15 Embora as regras variem de implementação para implementação, algumas permitem ainda o uso de operadores aritméticos com dados do tipo data e hora. Em SQL Base, por exemplo, a query abaixo pode ser usada para determinar por quantos dias ficaram no Spa os hóspedes que já foram embora. Este número é obtido subtraindo-se a data de chegada de saída. Outras implementações permitem queries semelhantes, mas não idênticas. SELECT NOME, SAIDA - CHEGADA FROM LISTA_DE_HOSPEDES WHERE NOME = ‘MARCELO FREITAS’ Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 14 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA 4.2. Funções As funções constituem mais uma forma de usar queries para manipular os dados das tabelas. Uma função retorna o valor resultante de uma determinada operação realizada sobre o seu argumento (ou argumentos). Uma função, como o seu argumento, representa um valor e é portanto uma expressão. 4.2.1. Funções Agregadas A característica marcante das funções agregadas é que produzem um único valor a partir de uma coluna inteira de dados. Portanto, enquanto qualquer outro tipo de expressão retorna um valor para cada linha, as funções agregadas retornam um valor que representa um agregado dos valores referentes às várias linhas. Por esta razão, são também chamadas de funções de colunas. Existem cinco funções agregadas. São elas: AVG(argumento) MAX(argumento) MIN(argumento) SUM(argumento) COUNT(argumento) Retorna a média dos valores do argumento Retorna o maior valor do argumento Retorna o menor valor do argumento Retorna o somatório dos valores do argumento Retorna a número de linhas do argumento As funções agregadas normalmente usam como argumento um nome de coluna ou uma expressão que tenha um nome de coluna como componente, mas podemos usá-las com qualquer expressão numérica ou de datas. A query a seguir lê todos os valores da coluna DESCONTO e fornece os percentuais médio, máximo e mínimo de desconto oferecidos aos hóspedes do Visual Spa. Como as função AVG, MÁX, MIN e SUM ignoram valores nulos, o valor AVG (média) é realmente o desconto médio apenas daqueles hóspedes que obtiveram algum desconto: SELECT AVG(DESCONTO), MAX(DESCONTO), MIN(DESCONTO) FROM LISTA_DE_HOSPEDES; AVG(DESCONTO) 0.115635 MAX(DESCONTO) 0.20 MIN(DESCONTO) 0.05 Outros exemplos: SELECT MIN(DESCONTO) * AVG(SAIDA-CHEGADA) FROM LISTA_DE_HOSPEDES WHERE TECNICO = ‘SENERA’; 4.2.2. Funções Não Agregadas As funções não agregadas diferem das agregadas pelo fato de que não fornecem um único valor a partir de uma coluna inteira de dados. Em vez disto, as funções não agregadas, como todas as expressões que já discutimos (exceto as funções agregadas), retornam um valor para cada linha. Em SQL Base, as funções agregadas começam sempre com o caractere “@”, mas esta convenção só pertence ao SQL Base. Nos outros aspectos, a sintaxe das funções não agregadas é igual a das agregadas: a função é seguida de seu argumento entre parênteses, por exemplo, @PROPER(‘JOSE AUGUSTO’). Da mesma forma que as funções agregadas, as não agregadas podem ser usadas uma dentro da outra, de modo que o resultado da função interna seja usado como argumento da externa. Por exemplo, na função: @PROPER(@LEFT(‘JOSE AUGUSTO’, 4)) @LEFT retorna os cinco primeiros caracteres da seqüência ‘JOSE AUGUSTO’ (‘JOSE’), os quais compões o argumento da função @PROPER. Esta função coloca apenas a primeira letra de cada palavra de seu argumento em letra maiúscula e as restantes em letra minúscula, como na representação de nomes próprios. Neste caso, @PROPER converte ‘JOSE’ em ‘Jose’. Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 15 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA 4.2.3. Funções de Seqüências de Caracteres Como as funções não agregadas variam muito de implementação para implementação, esta apostila não se dispões a examiná-las detalhadamente. Apresentamos neste próximo tópico apenas alguns exemplos representativos oferecidos pelo SQL Base. O exemplo abaixo usa a função @LENGTH (seqüência de caracteres). Colocamos a expressão seqüência de caracteres entre parênteses para indicar que esta função utiliza seqüências de caracteres como argumentos. Ela retorna o número de caracteres existentes no argumento. Neste caso, usamos a função para informar o número de caracteres de cada NOME da tabela LISTA_DE_HOSPEDES: SELECT NOME, @LENGTH(NOME) FROM LISTA_DE_HOSPEDES; NOME JANE FYUNDAI MARCELO FREITAS JOSÉ AUGUSTO BIANCA OLIVEIRA ALEXANDRE GOMES @LENGTH (NOME) 12 15 12 15 15 SELECT NOME, @PROPER(@LENGTH(NOME,5)) FROM LISTA_DE_HOSPEDES; NOME JANE FYUNDAI MARCELO FREITAS JOSÉ AUGUSTO BIANCA OLIVEIRA ALEXANDRE GOMES @PROPER(@LENGTH (NOME,5)) jane marce josé bianc alexan 4.2.4. Funções de Data e Hora São funções que retornam informações sobre uma coluna de dados do tipo data ou hora ou geram resultados do tipo data ou hora. A função de data @DAY(data), por exemplo, seleciona apenas o dia do mês da DATA: SELECT NOME, CHEGADA, @DAY(CHEGADA) FROM LISTA_DE_HOSPEDES; NOME JANE FYUNDAI MARCELO FREITAS ALEXANDRE GOMES JOSÉ AUGUSTO CHEGADA 15-08-1997 26-08-1997 14-08-1997 15-08-1997 @DAY(CHEGADA) 15 26 14 15 Queries semelhantes podem ser criadas com as funções @MONTH, @YEAR, @HOUR, @MINUTE e @SECOND. Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 16 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA 5.Organizando o Resultado 5.1. Cláusula GROUP BY A cláusula GROUP BY reúne diferentes linhas do resultado de uma query em conjuntos de acordo com as colunas nela mencionadas, chamadas colunas formadoras de grupos. As linhas são “agrupadas” de duas formas, ou em dois aspectos. A query abaixo exemplifica a primeira forma, na qual todas as linhas que contêm o mesmo valor na primeira coluna especificada são exibidas em grupos no resultado. Neste caso, a primeira coluna formadora de grupo é TECNICO. Todas as linhas que tenham o mesmo valor na coluna TECNICO aparecerão juntas no resultado: SELECT TECNICO, NOME FROM LISTA_DE_HOSPEDES GROUP BY TECNICO, NOME; TÉCNICO BRUNA BRUNA BRUNA JÚLIO JÚLIO RICARDO RICARDO SERENA SERENA NOME MARCELO FREITAS BIANCA OLIVEIRA ALEXANDRE GOMES JANE FYUNDAI JOSÉ AUGUSTO ALEXANDRE GOMES MAURÍCIO DE SOUZA JANE FYUNDAI STELLA SHIELDS Se houvesse linhas em que a coluna TECNICO estivesse em branco, ou seja, com um valor nulo para TECNICO, também seriam agrupadas. E as linhas são agrupadas da mesma maneira para cada coluna formadora de grupos subseqüente, embora isto não esteja aparente no exemplo dados pois só contém duas colunas. Obs.: As funções agregadas — AVG, SUM, MAX, MIN e COUNT — não podem ser usadas em cláusulas GROUP BY pois geram um único valor e por isso não podem agrupar linhas. A cláusula GROUP BY também pode ser usada em queries contendo uma cláusula WHERE. Neste caso, a GROUP BY é codificada depois da cláusula WHERE. Por exemplo, a query abaixo exibe os nomes dos hóspedes que chegaram depois do dia 15 de agosto por técnico: SELECT TECNICO, NOME FROM LISTA_DE_HOSPEDES WHERE CHEGADA > 15-08-97 GROUP BY TECNICO, NOME; 5.2. Cláusula HAVING A cláusula HAVING nos permite estreitar a área de atuação da cláusula GROUP BY da mesma forma que a cláusula WHERE estreita a área de atuação da cláusula SELECT, ou seja, através de uma condição de pesquisa. Ao contrário da cláusula WHERE, no entanto, a cláusula HAVING pode conter funções agregadas. Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 17 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA Uma nova tabela, HOSPEDES_PS, será usada nos exemplos deste tópico. Criamos uma tabela com a declaração CREATE TABLE abaixo. Esta tabela se destina a registrar as pesagens periódicas dos hóspedes do Visual Spa. CREATE TABLE HOSPEDE_PS (HOSPEDE VARCHAR(25) NOT FULL, PESO DECIMAL(4,1), QUANDO DATE); Chamamos a coluna DATE de QUANDO porque “DATE” é uma palavra reservada. As palavras reservadas não podem ser usadas como nomes de colunas ou outros identificadores, a não ser que entre aspas. Após a inclusão dos dados, a tabela HOSPEDE_PS tem a seguinte aparência: SELECT * FROM HOSPEDE_PS NOME JANE FYUNDAI MARCELO FREITAS ALEXANDRE GOMES JOSÉ AUGUSTO MAURÍCIO DE SOUZA JANE FYUNDAI MARCELO FREITAS ALEXANDRE GOMES JOSÉ AUGUSTO MAURÍCIO DE SOUZA PESO 68 59 86 87 68.5 67.5 55 84 84 67 QUANDO 14-08-97 14-08-97 15-08-97 15-08-97 15-08-97 16-08-97 16-08-97 17-08-97 17-08-97 17-08-97 A tabela contém dois registros de peso para cada estada: um na data de entrada e outro na data de saída. A query a seguir indica os hóspedes que tiveram uma diferença acima de um entre seu peso mínimo e seu peso máximo. Observe a presença de funções agregadas na cláusula HAVING. SELECT HOSPEDE, MIN(PESO), MAX(PESO) – MIN(PESO) FROM HOSPEDE_PS GROUP BY HOSPEDE HAVING MAX(PESO) – MIN(PESO) > 1; NOME MARCELO FREITAS ALEXANDRE GOMES JOSÉ AUGUSTO MAURÍCIO DE SOUZA MIN(PESO) 55 84 84 67 MAX(PESO MAX(PESO)-MIN(PESO) ) 59 4 86 2 87 3 68.5 1.5 Passemos para um outro exemplo. Esta query solicita o número de hóspedes orientados por cada técnico que trabalhou com mais de dois hóspedes: SELECT HOSPEDE, COUNT(NOME) FROM HOSPEDE_PS GROUP BY HOSPEDE HAVING CONT(NOME) > 2; 5.3. Cláusula ORDER BY A cláusula ORDER BY nos permite classificar as linhas do resultado alfabética e numericamente, em ordem crescente ou decrescente. O default é a ordem crescente. A cláusula ORDER BY é sempre a última cláusula da query. No exemplo a seguir, obtemos os nomes dos hóspedes classificados em ordem decrescente colocando a palavra DESC na cláusula ORDER BY depois do nome da coluna a ser ordenada. Usamos a palavra-chave DISTINCT para suprimir as linhas duplicadas: Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 18 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA SELECT DISTINCT NOME FROM LISTA_DE_HOSPEDES ORDER BY NOME DESC; NOME STELLA SHIELDS MAURÍCIO DE SOUZA MARCELO FREITAS JOSÉ AUGUSTO JANE FYUNDAI JANE FYUNDAI BIANCA OLIVEIRA ALEXANDRE GOMES ALEXANDRE GOMES As classificações são, por default, efetuadas em ordem crescente, a não ser que seja indicada a palavrachave DESC após o nome da coluna. Porém, podemos também explicitar a ordem crescente para uma determinada coluna, usando-se a palavra-chave ASC após o nome da coluna na cláusula ORDER BY. 6.Junções: Queries que Envolvem Mais de uma Tabela Por muitas vezes, os dados que desejamos não estão contidos em uma só tabela. Por exemplo, para obter a altura e o nome do técnico de Bianca Oliveira, temos que pesquisar em duas tabelas. O nome de seu técnico está registrado na tabela LISTA_DE_HOSPEDES, mas sua altura só está contida na tabela HOSPEDES. Esta última, a qual já foi vista em tópicos anteriores, tem a seguinte aparência: SELECT * FROM HOSPEDES; NOME JOSÉ AUGUSTO MAURÍCIO DE SOUZA BIANCA OLIVEIRA JANE FYUNDAI STELLA SHIELDS ROGÉRIO NUNES SEXO M M F F F M BIOTIPO M M G G M M ALTURA 1,67 1,72 1,65 1,80 1,65 1,78 A query a seguir obtém a altura de Rogério Nunes : SELECT NOME, ALTURA FROM HOSPEDES WHERE NOME = ‘BIANCA OLIVEIRA’; NOME BIANCA OLIVEIRA ALTURA 1,65 A próxima query obtém seu técnico da tabela LISTA_DE_HOSPEDES: SELECT NOME, TECNICO FROM LISTA_DE_HOSPEDES WHERE NOME = ‘BIANCA OLIVEIRA’; NOME BIANCA OLIVEIRA TECNICO BRUNA Podemos, no entanto, obter as mesmas informações de uma só vez através de uma query chamada junção. Uma junção é uma query que obtém dados de mais de uma tabela ao mesmo tempo, baseando-se na condição de junção indicada na cláusula WHERE. Temos abaixo uma junção que fornece a altura e o técnico de todos os hóspedes: SELECT HOSPEDES.NOME, ALTURA, TECNICO Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 19 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA FROM HOSPEDES, LISTA_DE_HOSPEDES WHERE HOSPEDES.NOME = LISTA_DE_HOSPEDES.NOME; NOME JANE FYUNDAI JOSÉ AUGUSTO MAURÍCIO DE SOUZA BIANCA OLIVEIRA STELLA SHIELDS TÉCNICO ALTURA JÚLIO 1,80 JÚLIO 1,67 RICARDO 1,72 BRUNA 1,65 SERENA 1,65 Podemos traduzir a query da seguinte maneira: “Para todas as linhas de HOSPEDES e LISTA_DE_HOSPEDES cujo o valor de HOSPEDES.NOME seja igual ao de LISTA_DE_HOSPEDES.NOME, obtenha os respectivos NOME e ALTURA de HOSPEDES e o TECNICO de LISTA_DE_HOSPEDES.” 6.1. Equijunções A última query que analisamos é um exemplo de “equijunção” — uma junção baseada em uma condição de igualdade. Outros tipos de predicados relacionais podem constituir outros tipos de condição de junção, dos quais veremos alguns exemplos. Porém de antemão sabemos que o tipo mais comum é o de igualdade — a “equijunção”. Para que possamos dar um exemplo um pouco diferente, criaremos uma nova tabela, QUARTOS, que irá conter detalhes das acomodações do Visual Spa. A declaração utilizada para criá-la é a seguinte: CREATE TABLE QUARTOS (QUARTO VARCHAR(3), NOME VARCHAR(15), TAXA FLOAT, DESCRICAO LONG VARCHAR); A tabela em questão preenchida com dados, excetuando-se a coluna de tipo LONG, tem a seguinte aparência: SELECT QUARTO, NOME, TAXA FROM QUARTOS; QUARTO 1 2 3 4 5 NOME ANA PAULA CARMEM SOUZA CRISTIANO BEZERRA MARCONE ALMEIDA MARIA FERREIRA Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira TAXA 300 300 250 325 250 Página 20 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA Segue-se então o exemplo de “equijunção”. Para efeito de demonstração, a “equijunção” encontra-se em uma cláusula AND. Observe, também, que nenhuma das duas colunas unidas, QUARTO da tabela QUARTOS e da LISTA_DE_HOSPEDES, aparece na lista do SELECT. SELECT LISTA_DE_HOSPEDES.NOME, QUARTOS.NOME, QUARTOS.TAXA, LISTA_DE_HOSPEDES.DESCONTO FROM QUARTOS, LISTA_DE_HOSPEDES WHERE LISTA_DE_HOSPEDES.NOME = ‘JANE FYUNDAI’ AND QUARTOS.QUARTO = LISTA_DE_HOSPEDES.QUARTO; LISTA_DE_HOSPEDES. QUARTOS.NOME NOME JANE FYUNDAI MARCONE ALMEIDA 6.2. QUARTOS.TAXA 325 LISTA_DE_HOSPEDES. DESCTO 0.20 Junções Externas Suponhamos que quiséssemos saber o nome, o sexo, o biotipo, a altura e o técnico de cada um dos hóspedes do Visual Spa. Os técnicos são indicados na tabela LISTA_DE_HOSPEDES, a qual contém informações sobre hóspedes atuais; as outras informações estão contidas na tabela HOSPEDES, que contém os registros de todos os hóspedes, atuais e passados. Podemos, para isso, usar esta query, uma simples “equijunção”: SELECT HOSPEDES.NOME, SEXO, BIOTIPO, ALTURA, TECNICO FROM HOSPEDES, LISTA_DE_HOSPEDES WHERE HOSPEDES.NOME = LISTA_DE_HOSPEDES.NOME; NOME JOSÉ AUGUSTO MAURÍCIO DE SOUZA BIANCA OLIVEIRA JANE FYUNDAI STELLA SHIELDS ROGÉRIO NUNES CLINT WESTWOOD SEXO M M F F F M M BIOTIPO M M G G M M M ALTURA 1,67 1,72 1,65 1,80 1,65 1,78 1,85 TECNICO JULIO RICARDO BRUNA JULIO SERENA SERENA RICARDO Uma junção externa nos permite unir tabelas através de colunas com números diferentes de linhas, sem que as linhas comuns às duas sejam excluídas da tabela resultado. Ao contrário, as linhas exclusivas de apenas uma das tabelas são incluídas no resultado, com valores nulos em quaisquer colunas da outra tabela, onde aquelas linhas não existem. O recurso de junções externas só existe em poucas implementações da linguagem SQL. Entretanto, por considerá-lo importante e como possivelmente será implementado em maior escala no futuro, vamos analisar como é efetuado este tipo de junção no SQL Base. A sintaxe SQL Base para converter o exemplo anterior em uma junção externa a fim de incluir as demais linhas da tabela não contidas no resultado é simples: basta acrescentar um sinal de adição (+) ao lado do nome da coluna que não possui as linhas externas, ou seja, aquela na qual incluiremos valores nulos no resultado, na condição de junção. Ex.: SELECT HOSPEDES.NOME, SEXO, BIOTIPO, ALTURA, TECNICO FROM HOSPEDES, LISTA_DE_HOSPEDES WHERE HOSPEDES.NOME = LISTA_DE_HOSPEDES.NOME(+); 6.3. Auto-Junções Por muitas vezes, precisamos fazer uma junção de uma tabela com ela mesma. Esta é uma forma de tratarmos uma única tabela como se fosse na verdade duas tabelas, a fim de possibilitar certos tipos de queries. Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 21 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA Suponhamos que quiséssemos selecionar todos os hóspedes que tenham obtido o mesmo percentual de desconto que Maurício de Souza. Todas as informações que desejamos estão na tabela LISTA_DE_HOSPEDES, que tem a seguinte aparência: SELECT * FROM LISTA_DE_HOSPEDES; NOME JANE FYUNDAI MARCELO FREITAS JANE FYUNDAI ALEXANDRE GOMES JOSÉ AUGUSTO MAURÍCIO DE SOUZA BIANCA OLIVEIRA STELLA SHIELDS ALEXANDRE GOMES QUARTO 3 2 4 1 7 5 6 8 9 TÉCNICO JÚLIO BRUNA SERENA RICARDO JÚLIO RICARDO BRUNA SERENA BRUNA CHEGADA 15-08-1997 26-08-1997 24-08-1997 14-08-1997 15-08-1997 25-08-1997 15-08-1997 25-08-1997 17-08-1997 SAÍDA 17-08-1997 DESCTO 0.20 0.10 16-08-1997 19-08-1997 20-08-1997 23-08-1997 0.15 0.05 0.15 0.20 Poderíamos, evidentemente, usar uma query para selecionar DESCONTO onde NOME fosse igual a “MAURICIO DE SOUZA” e, em seguida, uma outra que selecionasse NOME e DESCONTO onde DESCONTO fosse igual ao resultado da primeira query. Mais digamos que quiséssemos optar por uma forma mais elegante e menos trabalhosa – usar uma única query. Esta tarefa parece bastante simples. Poderíamos começar a construir a query assim: SELECT NOME, DESCONTO FROM LISTA_DE_HOSPEDES WHERE DESCONTO = ...? Entretanto, neste ponto chegamos a um impasse. Queremos dizer WHERE DESCONTO = (o desconto de Maurício de Souza), mas não vemos como. Observe como seria fácil resolver este problema se, ao invés de lida com apenas uma tabela, estivéssemos lidando com duas, a fim de obter o desconto de Maurício de Souza de uma e as informações sobre os outros hóspedes da outra. Então, usando as letras A e B para distinguir duas tabelas na realidade idênticas, teríamos a seguinte query: SELECT A.NOME, A.DESCONTO FROM LISTA_DE_HOSPEDES A, LISTA_DE_HOSPEDES_B WHERE A.DESCONTO = B.DESCONTO AND B.NOME = ‘MAURICIO DE SOUZA’; NOME MAURÍCIO DE SOUZA STELLA SHIELDS DESCTO 0.15 0.15 Como você pode comprovar através do resultado, esta é a forma que temos para resolver este tipo de query — chamada “auto-junção”. Os nomes de tabelas temporários, denominados nomes correlatos ou títulos (labels), são os elementoschaves que permitem que a junção ocorra a partir de uma única tabela. Os nomes correlatos são definidos na lista do FROM, na qual estabelecemos que a tabela em questão passa a ser conhecida por estes nomes. A partir daí, todos os nomes de colunas que quisermos usar terão como prefixo estes nomes correlatos. Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 22 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA 6.4. Outros Tipos de Junções Quando a condição de pesquisa utilizada não está baseada em uma relação de igualdade e sim de “maior que” (>). Eventualmente junções como esta, não baseadas em uma relação de igualdade, são conhecidas como “não equijunções”. O termo engloba todas as junções que utilizem qualquer operador relacional exceto o de igualdade ( = ). Nem todas as implementações SQL comportam este tipo de junção. 7.Queries em Outras Declarações 7.1. Declaração UNION A palavra-chave UNION vincula queries sucessivas e une os seus resultados. As linhas duplicadas são suprimidas. As queries vinculadas têm que ter o mesmo número de elementos na lista do SELECT, e os tipos de dados e tamanho têm que coincidir coluna a coluna. Por exemplo, se a primeira coluna da lista do SELECT da primeira query for do tipo VARCHAR(25), então a primeira coluna da lista do SELECT de cada uma das queries subseqüentes na declaração UNION tem que ser também do tipo VARCHAR(25). Não poderiam ser colunas VARCHAR(8) e nem colunas numéricas ou de data e hora. Se, por fim, uma das colunas for definida como NOT NULL, todas as colunas a serem unidas a ela terão que ser também como NOT NULL. O exemplo a seguir une os nomes dos hóspedes da tabela HOSPEDES com os da tabela LISTA_DE_HOSPEDES. Como as linhas duplicadas são eliminadas, o resultado será exatamente o mesmo que o da primeira query. Ambas da colunas são do tipo VARCHAR. SELECT NOME FROM HOSPEDES UNION SELECT NOME FROM LISTA_DE_HOSPEDES; NOME JOSÉ AUGUSTO MAURÍCIO DE SOUZA BIANCA OLIVEIRA JANE FYUNDAI STELLA SHIELDS ROGÉRIO NUNES As declarações SELECT em uma UNION podem conter funções e cláusulas WHERE e GROUP BY, e uma cláusula ORDER BY também pode ser acrescentada à UNION como um todo. Não há limites para o número de queries cujos os resultados podem ser unidos através de uma UNION. 7.2. Utilizando Queries para Incluir Dados Abordemos agora o último uso do SELECT embutido em outra declaração. Além de servir para selecionar dados para uma query externa, pode ser usado para incluir dados quando a declaração externa for um INSERT. Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 23 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA Suponhamos que quiséssemos criar uma tabela HOSPEDES_HOMENS, idêntica à HOSPEDES, à exceção de que, ao invés de listar o sexo, o biotipo e a altura de todos os hóspedes, antigos e atuais, HOSPEDES_HOMENS contém apenas os dados dos hóspedes do sexo masculino (e, portanto, não listará o sexo). A tabela é criada pela declaração abaixo: CREATE TABLE HOSPEDES_HOMENS (NOME VARCHAR(25), BIOTIPO VARCHAR(1), ALTURA INTEGER); Agora temos que incluir dados. Os dados que desejamos já estão cadastrados na tabela HOSPEDES e podem ser extraídos e incluídos através de uma declaração INSERT contendo uma query. INSERT INTO HOSPEDES_HOMENS SELECT NOME, BIOTIPO, ALTURA FROM HOSPEDES WHERE SEXO = ‘M’; As únicas restrições existentes neste caso são as seguintes: — O número de colunas do SELECT tem que ser o mesmo que o da declaração INSERT ou, como nosso exemplo, o mesmo número de colunas contidas na tabela, se as colunas não forem mencionadas. — O tipo e o tamanho dos dados selecionados têm que ser compatíveis com as especificações das colunas na tabela de destino. Por exemplo, números podem ser incluídos em uma coluna de tipo caractere, mas o contrário não é aceito. 8.Alterando Tabelas e Dados Até agora lidamos a maior parte do tempo com as queries — declarações SELECT que nos permitem, de uma forma ou de outra, obter dados de uma tabela. Nesta etapa da apostila, discutiremos exemplos de dois outros tipos de declarações SQL: declarações de manipulação de dados, usadas para alterar os dados de um banco de dados, e declarações de definição de dados, que servem para fazer alterações na estrutura do banco de dados. 8.1. Alterando os Dados Uma declaração de manipulação de dados que já vimos é o INSERT, cuja função é incluir novas linhas. Além do INSERT, há mais duas outras declarações de manipulação de dados: UPDATE e DELETE. Como o INSERT as duas declarações nos permitem alterar o conteúdo do banco de dados. UPDATE altera linhas existentes e DELETE as exclui do banco de dados. 8.1.1. Atualizando Dados em uma Linha Suponhamos que um dia Alexandre nos informasse que teria mudado seu nome para André e que gostaria que trocássemos também em nossos registros o seu nome antigo pelo nome novo. Poderíamos usar a declaração UPDATE abaixo para fazer esta alteração na tabela LISTA_DE_HOSPEDES: UPDATE LISTA_DE_HOSPEDES SET NOME = ‘ANDRE’ WHERE NOME = ‘ALEXANDRE’; O nome da tabela ou visão a ser atualizada é indicado na primeira linha do exemplo. Na segunda linha aparece o nome da coluna a ser atualizada e o tipo de alteração, e na terceira a condição de pesquisa. Como nas queries, se não houver condições de pesquisa, a operação será executada em todas as linhas. Suponhamos que André também queira trocar o quarto 9, o qual teve que dividir com Jane Fyundai, pelo 7, que espera poder ocupar sozinha; e digamos que também consiga obter mais 2% de desconto, além dos 20 originais. Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 24 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA Podemos usar a declaração UPDATE para realizar as duas alterações de uma só vez. A segunda condição de pesquisa, especificando a data de chegada, é necessária pois existem dois quartos ocupados pelo André em LISTA_DE_HOSPEDES, e só queremos alterar um deles. UPDATE LISTA_DE_HOSPEDES SET QUARTO = ‘7’, DESCONTO = DESCONTO + 0.02 WHERE NOME = ‘ALEXANDRE’ AND CHEGADA = 17-08-97; Como podemos observar no exemplo, é possível alterar mais de uma coluna ao mesmo tempo e usar expressões aritméticas para indicar o valor novo. 8.1.2. Eliminando Linhas Podemos remover linhas de uma tabela, desde que seja atualizável, através da declaração DELETE. Da mesma forma que com o UPDATE, qualquer linha que seja eliminada de uma visão será também eliminada da tabela original. A declaração abaixo elimina da tabela LISTA_DE_HOSPEDES todas as linhas de hóspedes que tenham uma data de saída registrada: DELETE FROM LISTA_DE_HOSPEDES WHERE SAIDA IS NOT NULL; Para eliminar todas as linhas de uma tabela, não especifique uma condição de pesquisa. 8.1.3. Gravando e Desfazendo Alterações Nos dois tópicos anteriores, fizemos várias alterações no banco de dados. Podemos desfazê-las através da declaração: ROLLBACK; Com esta declaração recuperamos de volta as linhas que havíamos excluído, e os dados alterados voltaram a ser exatamente o que eram antes da alteração. Se tivéssemos eliminado as tabelas por inteiro, elas também seriam recuperadas. 8.2. Alterando uma Tabela Além de alterar os dados de uma tabela, a SQL nos permite também alterar a sua estrutura, através da declaração ALTER TABLE. Uma outra declaração, DROP, que será discutida no final deste tópico, serve para eliminar a tabela completamente. O número exato de características da tabela que podemos alterar varia em função da implementação da declaração ALTER TABLE. Ela possui várias cláusulas ou continuações, correspondentes às operações que serão executadas, que variam de implementação para implementação. A SQL padrão, assim como a maioria das implementações, limita as opções em duas, ADD e MODIFY. O SQL Base complementa este padrão com três outras continuações. Suponhamos, por exemplo, que começássemos uma declaração ALTER TABLE da seguinte maneira: ALTER TABLE LISTA_DE_HOSPEDES Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 25 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA Em SQL Base, temos cinco opções de cláusulas ou continuações para complementar a declaração, dependendo da operação desejada: ADD (incluir) MODIFY (modificar) DROP (eliminar) RENAME (trocar o nome de) RENAME TABLE (trocar nome tabela) uma nova coluna o tamanho de uma coluna ou se a coluna deverá aceitar valores nulos. uma coluna existente uma coluna existente Comecemos pela primeira opção: eliminar uma coluna. 8.2.1. Eliminando uma Coluna Suponhamos que decidíssemos não dar mais descontos a nenhum hóspede. Podemos eliminar a coluna DESCONTO da LISTA_DE_HOSPEDES da seguinte forma: ALTER TABLE LISTA_DE_HOSPEDES DROP DESCONTO; Poderíamos, se desejado, eliminar mais de uma coluna da tabela em uma só declaração, separando os nomes das colunas por vírgulas, da mesma forma que na lista do SELECT. Por exemplo: ALTER TABLE LISTA_DE_HOSPEDES DROP QUARTO, SAIDA; Entretanto, não poderíamos usar a declaração ALTER TABLE para alterar mais de uma tabela ao mesmo tempo. Uma coluna que possua um índice não pode ser eliminada, a não ser que o índice seja eliminado antes. 8.2.2. Incluindo uma Coluna Usamos a cláusula ADD da declaração ALTER TABLE para incluir uma coluna. Incluir uma coluna é mais trabalhoso do que apagar uma outra, pois temos que especificar o tipo de dado que irá conter, o tamanho (quando necessário) e se aceitará ou não valores nulos, exatamente da mesma forma que procedemos quando definimos as colunas de uma tabela ao criá-la. A declaração a seguir inclui uma nova coluna DESCONTO igual à que eliminamos: ALTER TABLE LISTA_DE_HOSPEDES ADD DESCONTO DECIMAL(2,2); Especificamos que a nova coluna é do tipo DECIMAL e o seu tamanho é (2,2). Como queríamos que a coluna aceitasse valores nulos, não mencionamos NOT NULL, mas poderíamos tê-lo feito. A nova coluna DESCONTO está vazia, isto é, só contém valores nulos, porque até agora não foram incluídos dados nela. Mesmo que tivéssemos especificado NOT NULL, a coluna conteria valores nulos iniciais. NOT NULL apenas garante que não serão aceitos valores nulos em futuras atualizações. Como na exclusão poderíamos incluir mais de uma coluna de uma só vez. A declaração a seguir inclui as colunas SAIDA e GARCOM: ALTER TABLE LISTA_DE_HOSPEDES ADD SAIDA DATE, GARCOM VARCHAR(10); Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 26 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA 8.2.3. Modificando uma Coluna A cláusula MODIFY da declaração ALTER TABLE é que nos permite aumentar o tamanho de uma coluna de tamanho variável. No entanto, não podemos reduzir o seu tamanho e alterar o seu tipo. Por exemplo, podemos fazer com que uma coluna VARCHAR(5) passe a ser VARCHAR(10), mas não que passe a ser do tipo INTEGER. Podemos, ainda, fazer com que uma coluna que não aceite valores nulos passe a aceitar e também podemos fazer o inverso, desde que a coluna não contenha nulos. Por exemplo, não contém valores nulos na coluna TECNICO de LISTA_DE_HOSPEDES; então poderíamos, se necessário, fazer com que TECNICO passasse a ser NOT NULL. Já não podemos fazer o mesmo com a coluna DESCONTO, pois ela contém valores nulos. A declaração abaixo altera o tamanho da coluna TECNICO de 8 para 25 e define a coluna como NOT NULL: ALTER TABLE LISTA_DE_HOSPEDES MODIFY TECNICO VARCHAR(25) NOT NULL; Podemos alterar mais de uma coluna ao mesmo tempo, separando-as por vírgulas na cláusula MODIFY: ALTER TABLE LISTA_DE_HOSPEDES MODIFY TECNICO VARCHAR(30) NULL, NOME NULL; 8.2.4. Trocando o Nome de uma Tabela ou Coluna As duas últimas opções da declaração ALTER TABLE são RENAME, para trocar o nome de colunas, RENAME TABLE de tabelas. Os exemplos a seguir trocam o nome da coluna GARCOM para SERVENTE: ALTER TABLE LISTA_DE_HOSPEDES RENAME GARCOM SERVENTE; Não é necessário informar o tipo de dado ou o tamanho da coluna, porque estes mantêm-se os mesmos. RENAME TABLE funciona da mesma forma. A única diferença é que como o nome da tabela já esta indicado na cláusula ALTER TABLE, só temos que especificar o novo nome na cláusula RENAME TABLE. A declaração abaixo altera o nome da tabela LISTA_DE_HOSPEDES para LISTA: ALTER TABLE LISTA_DE_HOSPEDES RENAME TABLE LISTA; 8.2.5. Eliminando uma Tabela Para eliminar totalmente uma tabela, usamos a declaração DROP. DROP se assemelha ao ALTER TABLE quanto ao fato de serem várias declarações em uma só. Dependendo de como você o formula, o DROP pode eliminar uma tabela, uma visão, um índice ou um sinônimo. Neste tópico, descrevemos apenas a eliminação de tabelas e visões. Índices e sinônimos serão estudados mais adiante. A declaração a seguir apaga a tabela QUARTOS: DROP TABLE QUARTOS; Quando uma tabela é eliminada do banco de dados, todas as visões derivadas dela e índices e sinônimos definidos para ela, assim como os privilégios designados em função dela, também desaparecem. Se tentarmos executar uma query na tabela QUARTOS agora, receberemos uma mensagem de erro indicando que a tabela não existe. Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 27 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA 9.Utilizando Índice para Melhorar a Performance Observe que as linhas da tabela LISTA_DE_HOSPEDES estão listadas em uma ordem aleatória, ou seja, em nenhuma das colunas os valores seguem a uma ordem alfabética ou numérica. Ao invés disso, aparecem na ordem em que foram incluídas. Se quisermos procurar um determinado nome, teremos que percorrer toda a coluna NOME até encontrá-lo. O mecanismo de busca do sistema de banco de dados não difere em muito nosso método. Ele também percorreria os dados da coluna até localizar o nome desejado. O uso de índices acelera a procura. Quando criamos índices para uma coluna, ela é classificada de tal forma que, sempre que for mencionada em uma query, o sistema usará o índice para ter acesso direto aos dados desejados, ao invés de vasculhar a coluna toda. Os índices são então muito úteis às queries que se referem a uma única linha. Em termos gerais os índices são úteis em qualquer coluna que seja consultada freqüentemente. Criamos um índice com a declaração CREATE INDEX, e ele é automaticamente atualizado quando a coluna (ou colunas) a ele associada (s) sofre (m) alguma alteração. Um índice só deixa de existir se for executada a declaração DROP INDEX ou se a tabela para qual foi criada foi eliminada. Podemos criar um índice para apenas uma coluna ou várias em conjunto. A segunda forma de índice é conhecida como concatenado ou composto. Podemos criar quantos índices quisermos, não há limites. No entanto, devemos considerar o fato de que ocupam bastante espaço em disco e seria aconselhável não criar tantos índices a ponto de confundir o otimizador do banco de dados. O otimizador é um subsistema do sistema de banco de dados que seleciona os caminhos de acesso e decide qual a melhor maneira de extrair os dados solicitados por uma query. É o otimizador que escolhe quais índices disponíveis deve usar, se houver; o usuário não precisa se preocupar com isso. 9.1. Utilizando um Índice A query abaixo pesquisa duas tabelas para obter o nome, o técnico e a altura de todos os hóspedes. SELECT A.NOME, TECNICO, ALTURA FROM LISTA_DE_HOSPEDES A, HOSPEDES B WHERE A.NOME = B.NOME; Usaremos a declaração CREATE INDEX para criar um índice, especificando primeiro o nome da tabela, LISTA_DE_HOSPEDES, e, em seguida, entre parênteses, a coluna ou as colunas a serem indexadas. Podemos incluir também a palavra-chave ASC ou DESC ao lado do nome da coluna para identificar a indexação em ordem crescente ou decrescente. O default é a ordem crescente. CREATE INDEX NOME_ID ON LISTA_DE_HOSPEDES (NOME); O índice acelera a execução da query anterior em 13% em um PC/AT. 9.2. Utilizando um Índice Único A query que utilizamos envolve uma junção de duas tabelas. Podemos criar um índice na segunda tabela também. Não especificamos que NOME_ID deveria ser um índice único, pois a coluna LISTA_DE_HOSPEDES.NOME contém nomes repetidos. “Existem hóspedes que já fizeram duas visitas no Spa”. Um índice único não pode ser criado em uma coluna ou grupo de colunas que contenha linhas duplicadas. A tabela HOSPEDES, porém, representa o nosso arquivo contendo todos os hóspedes passados e atuais, no qual cada hóspede só aparece uma vez. Além disso, queremos nos certificar de que a coluna NOME da tabela HOSPEDES só contém o nome de cada hóspede uma única vez, para que possamos tornar o nosso índice único. Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 28 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA A declaração abaixo cria um índice único na coluna NOME da tabela HOSPEDES: CREATE UNIQUE INDEX NOME1_IND ON HOSPEDES (NOME); Chamamos este índice de NOME1_IND porque já temos o NOME_IND, e os índices têm que ter nomes diferentes, mesmo que sejam criados em colunas de tabelas diferentes. Devido a presença de um índice único, qualquer valor duplicado não será aceito. Agora com os dois índices que criamos, a query do início deste tópico tem a sua execução acelerada em 20% em um PC/AT. 9.3. Utilizando um Índice Concatenado Para exemplificar o nosso próximo exemplo criaremos uma nova tabela chamada QUADRO_DE_PESOS, a qual fornece os pesos mínimo e máximo aceitáveis para homens e mulheres de acordo com o biotipo, e a altura em metros. A declaração para criá-la é a seguinte: CREATE TABLE QUADRO_DE_PESOS (ALTURA DECIMAL(3,2), SEXO CHAR(1), BIOTIPO CHAR(1), PS_MIN DECIMAL(3,1), PS_MAX DECIMAL (3,1)); Com os dados incluídos separadamente, a tabela tem o seguinte aspecto: SELECT * FROM QUADRO_DE_PESOS; ALTURA 1,67 1,72 1,65 1,80 1,65 1,78 1,85 SEXO M M F F F M M BIOTIPO M M G G M M M PS_MIN 56 57 57.5 72 73.5 75 60 PS_MAX 58.5 59.5 60 78.5 80 82.5 66 Sempre que quisermos consultar a faixa aceitável de peso de uma pessoa na tabela QUADRO_DE_PESOS, teremos que fornecer ao sistema os valores das três colunas ALTURA, SEXO e BIOTIPO. A query a seguir executa esta consulta. Seleciona o nome, o técnico e a faixa aceitável de peso de todos os hóspedes. NOME e TECNICO vêm da LISTA_DE_HOSPEDES; a altura, o sexo e o biotipo são obtidos da tabela HOSPEDES e são usados para localizar a respectiva faixa no QUADRO_DE_PESOS: SELECT A.NOME, TECNICO, PS_MIN, PS_MAX FROM LISTA_DE_HOSPEDES A, HOSPEDES B, QUADRO_DE_PESOS C WHERE A.NOME = B.NOME AND B.SEXO = C.SEXO AND B.ALTURA = C.ALTURA AND B.BIOTIPO = C.BIOTIPO; Podemos reduzir significamente o tempo de execução da query criando um índice concatenado abrangendo as colunas ALTURA, SEXO e BIOTIPO: CREATE INDEX PESO_IND ON QUADRO_DE_PESOS (ALTURA, SEXO, BIOTIPO); O índice concatenado reduz o tempo de execução da query em 38% em um PC/AT. 9.4. Apagando um Índice Qualquer índice de uma tabela é eliminado automaticamente quando a tabela é excluída. Para eliminar um índice manualmente, usamos a declaração DROP INDEX, que é a mesma declaração usada para apagar tabelas. Só agora concluiremos a explicação desta declaração. A declaração abaixo apaga o índice PESO_IND que criamos na tabela QUADRO_DE_PESOS: DROP INDEX PESO_IND; A tabela onde foi criado o índice não é afetada pela sua eliminação. Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 29 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA 10.Programando em SQL No início desta apostila, vimos como usar a linguagem SQL de modo interativo, ou seja, como executar as declarações SQL diretamente do teclado. Agora, focalizaremos o tópico programação em SQL — declarações SQL embutidas em programas escritos em outra linguagem, como por exemplo, C ou COBOL. 10.1. Porque SQL Embutida Como foi mencionado na introdução, SQL não é uma linguagem de programação e nem uma linguagem interativa. Não podemos escrever programas em SQL diretamente. Temos que executá-las através de um programa que “converse” com o sistema de banco de dados e realize as operações que a SQL não foi projetada para realizar. 10.2. Utilizando a Ferramenta ACCESS Para que possamos entender melhor a SQL, utilizaremos um Sistema de Gerenciamento de Banco de Dados bem conhecido o Microsoft Access. A ferramenta Access permite-nos utilizar comandos SQL para manipulação de dados, portanto poderemos utilizar os comandos aprendidos até agora. O Microsoft Access possui um arquivo de exemplo de banco de dados chamado NorthWind, o qual iremos utilizado para manipulação de dados. Ao iniciar o Access aparecerá a seguinte tela: Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 30 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA Clique na opção "Abrir banco de dados existentes", selecione o arquivo Northwind e clique em "OK". Caso o arquivo não esteja na relacionado na lista de arquivos, selecione a opção "Mais arquivos..." e em seguida o botão OK. O arquivo encontra-se na seguinte pasta "C:\Arquivos de Programas\Microsoft Office\Exemplos". Após o arquivo aberto aparecerá a seguinte tela: Esta janela possui toda estrutura do arquivo Nortwind, esta estrutura é dividida pelas seguintes guias: Tabela / Consulta / Formulário / Relatórios / Macros / Módulos, a guia tabela possui todas as tabelas do Northwind, que utilizaremos nos nossos exercícios. Clique na guia Consulta, exclua todas as consultas existentes nesta caixa ( Shift+Delete). A caixa deverá ficar com a seguinte aparência: Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 31 SQL - Structure Query Language ESCOLA TÉCNICA DE INFORMÁTICA Clique no botão NOVO, em seguida na aparecerá a seguinte tela: Selecione a opção Modo estrutura e clique no botão OK. Em seguida clique no botão Cancelar na próxima Caixa de Diálogo. Pronto! Você deverá esta com a janela de consulta aberta. (observe a figura abaixo) Antes de iniciarmos os nossos exercícios, precisaremos alterar para a janela MODO SQL. Siga as seguintes instruções: Clique no Menu Exibir, opção Modo SQL. Esta janela será utilizada para criarmos nossas consultas através da SQL. Para executar cada consulta clique no botão "Executar" na barra de ferramentas. Obs1.: Para cada consulta criada utilizaremos um arquivo, ou seja, gravaremos a consulta atual e abriremos uma nova. Obs2.: Caso necessário consulte os anexos de tabelas para resolução dos exercícios. Luis Fernando Calábria/Erick Franklin/Leonardo Bandeira Página 32