Buscar

Uma Introdução à SQL

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 36 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 36 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 36 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

CAPÍTULO 4
Uma introdução à SQL 
4.1 INTRODUÇÃO 
Como mencionamos no Capítulo 1, a SQL é a linguagem padrão para se lidar com bancos de dados relacionais, e é aceita por quase todos os produtos existentes no mercado. A SQL foi desenvolvida originalmente na IBM Research no início da década de 1970 (consulte as referências [4.8-4.9] e [4.28]); ela foi implementada pela primeira vez em grande escala em um protótipo da IBM chamado System R (consulte as referências [4.1—4.3] e [4.11—4.13]), e reimplementada depois disso em numerosos produtos comerciais da IBM (ver referência [4.20]) e de muitos outros fornecedores. Neste capítulo, apresentaremos uma introdução à linguagem SQL; aspectos adicionais, relacionados com assuntos como integridade, segurança, etc., serão descritos em capítulos subseqüentes dedicados a esses tópicos. Todas as nossas descrições serão baseadas (exceto onde for indicado algo em contrário) na versão atual do padrão, conhecida informalmente como SQL/92, também como SQL—92 ou apenas SQL2 [4.22—4.23]; o nome oficial é International Standard Database Language SQL (1992). 
Nota: devemos acrescentar imediatamente que está próximo da conclusão o trabalho na SQL3, a proposta de prosseguimento para o padrão atual; a ratificação era esperada para o final de 1999. Então, quando este livro for impresso, o padrão atual deverá ser possivelmente a “SQL/99”, e não a SQL/92. Porém, consideramos que seria muito confuso empregar a SQL3 como base de nossas discussões, pelo simples fato de que — obviamente — ainda não há nenhum produto que a reconheça; por essa razão, decidimos descrever a SQL3 separadamente em um apêndice (o Apêndice B). Em todo caso, também devemos assinalar que nenhum produto atual admite nem mesmo a SQL/92 em sua totalidade;* em vez disso, os produtos em geral admitem aquilo que se poderia chamar “um superconjunto de um subconjunto” da SQL/92 (isto é, a maioria deles deixa de oferecer suporte a determinados aspectos do padrão e ainda de ir além do padrão em outros aspectos). Por exemplo, o produto DB2 da IBM não admite no momento todos os recursos de integridade da SQL/92, mas vai além da SQL/92 em suas regras relativas à atualização de visões. 
Aqui estão algumas observações preliminares adicionais: 
• Em sua forma original, a SQL pretendia ser especificamente uma “sublinguagem de dados”. Porém, com a incorporação do recurso de Módulos Armazenados Persistentes (PSM — Persistent Stored Modules) ao padrão no final de 1996, a SQL se tornou completa em termos computacionais (ela agora inclui instruções ou declarações como CALL, RETURN, SET, CASE, IF, LOOP, LEAVE, WHILE e REPEAT, bem como diversas características inter-relacionadas, como variáveis e tratadores de exceções). Como conseqüência, já não há mais qualquer necessidade de combinar a SQL com alguma linguagem hospedeira distinta para se desenvolver uma aplicação completa. No entanto, optamos por não descrever o recurso PSM em qualquer nível de detalhe neste livro. 
*De fato, nenhum produto poderia oferecer suporte à SQL/92 em sua totalidade porque a SQL/92 especificada no momento contém numerosos furos, equívocos e incoerências. Consulte a referência [4.19] para ver uma descrição detalhada desse assunto. 71 
• Não se surpreenda ao descobrir que a SQL utiliza o termo tabela em lugar dos termos relação e variável de relação (ver Capítulo 3). Por essa razão, para manter a coerência com o padrão SQL e os produtos de SQL, faremos o mesmo neste capítulo (e em qualquer outro lugar neste livro, sempre que estivermos preocupados especificamente com a SQL). Além disso, a SQL não usa os termos cabeçalho e corpo (de uma tabela ou relação). 
• A SQL é uma linguagem enorme. O próprio documento padrão [4.22] tem bem mais de 600 páginas (e as especificações da SQL3 ocupam mais de duas vezes esse tamanho). Em conseqüência, não é possível esgotar o assunto em um livro desta natureza; tudo o que podemos esperar fazer é descrever os aspectos mais importantes de modo razoavelmente amplo, mas prevenimos o leitor de que nossas discussões são necessariamente superficiais. Em particular, não hesitamos em omitir material irrelevante ao propósito pretendido, nem em fazer simplificações no interesse da brevidade. Descrições mais completas (mas ainda assim tutoriais) podem ser encontradas nas referências [4.4], [4.19] e [4.27]. 
• Finalmente, deve ser dito que (conforme indicado em diversos pontos nos Capítulos de 1 a 3) a SQL está muito longe de ser a linguagem relacional perfeita — ela se ressente de pecados de omissão e comissão. Não obstante, ela é o padrão, é admitida por quase todos os produtos existentes no mercado, e todo profissional de banco de dados precisa conhecer algo sobre ela. Daí a cobertura feita neste livro. 
4.2 VISÃO GERAL 
A SQL inclui operações de definição de dados e operações de manipulação de dados. Consideraremos primeiro as operações de definição. A Figura 4.1 oferece uma definição de SQL para o banco de dados de fornecedores e peças (compare-a com a Figura 3.9). Como podemos observar, a definição inclui uma instrução CREATE TABLE para cada das três tabelas básicas (conforme notamos no Capítulo 3, a palavra-chave TABLE em CREATE TABLE indica especificamente uma tabela básica). Cada uma dessas instruções CREATE TABLE especifica o nome da tabela básica a ser criada, os nomes e os tipos de dados das colunas dessa tabela, e ainda a chave primária e quaisquer chaves estrangeiras na tabela (e, possivelmente, também algumas informações adicionais não ilustradas na Figura 4.1). Há ainda alguns detalhes sintáticos a assinalar: 
• Observe que fazemos uso freqüente do símbolo “#“ em (por exemplo) nomes de colunas mas, na realidade, esse símbolo não é válido em SQL/92. 
• Usamos o ponto-e-vírgula (;) como indicador de término de instrução. Na realidade, o uso desses indicadores pela SQL/92 dependerá do contexto. Os detalhes específicos estão além do escopo deste livro. 
Uma diferença importante entre a Figura 4.1 e sua equivalente (a Figura 3.9) no Capítulo 3 é o fato de que a Figura 4.1 não inclui nada que corresponda às definições de tipos (isto é, declarações TYPE) da Figura 3.9. É claro que a razão é que a SQL não permite que os usuários definam seus próprios tipos;* assim, as colunas devem ser definidas somente em termos de tipos embutidos ou internos (definidos pelo sistema). A SQL admite os seguintes tipos embutidos, mais ou menos auto-explicativos: 
CHARACTER [ VARYING ] (n) INTEGER DATE 
BIT E VARYING ] (n) SMALLINT TIME 
NUMERIC (p,q) FLOAT (p) TIMESTAMP 
DECIMAL (p,q) INTERVAL 
Ela permite que os usuários definam aquilo que se chama domínios, mas esses “domínios” não são na realidade domínios — isto é, tipos — no sentido relacional (ver Capítulo 5). Nota: porém, os tipos definidos pelo usuário são admitidos na SQL3 (ver Apêndice B). 
CREATE TABLE F 
( F# CHAR(5), 
FNOME CHAR(20), 
STATUS NUMERIC(S), 
CIDADE CHAR(15), 
PRIMARY KEY ( F# ) ) ; 
CREATE TABLE P 
( P# CHAR(6), 
PNOME CHAR(20), 
COR CHAR(6), 
PESO NUMERIC(5.1), 
CIDADE CHAR(15), 
PRIMARY KEY ( P# ) ) ; 
CREATE TABLE FP 
( F# CHAR(5), 
P# CHAR(6), 
QDE NUMERIC(9), 
PRIMARY KEY ( F#, P# ), 
FOREIGN KEY ( F# ) REFERENCES F, 
FOREIGN KEY ( P# ) REFERENCES P ; 
FIGURA 4.1 O banco de dados de fornecedores e peças (definição de SQL) 
Uma série de padrões, abreviações e grafias alternativas — por exemplo, CHAR em lugar de CHARACTER — também têm suporte; omitimos os detalhes aqui. Além disso, os colchetes “[“ e “]“ em CHARACTER e BIT são usados para indicar que o material que eles incluem é opcional (como é normal na notação BNF, é claro). Observe finalmente que a SQL exige que certos comprimentos ou precisões sejam declarados para determinados tipos (por exemplo, CHAR), o que não foi feito em nossa sintaxe hipotética do Capítulo 3. De fato, a SQL aparentemente considera esses comprimentos e essas precisões como partes dos tipos (implicando, por exemplo, que CHAR(3) e CHAR(4) são tipos diferentes); acreditamos que é melhor considerá-losrestrições de integridade (e assim o fizemos — consulte o Capítulo 8, em especial o Exercício 8.4). 
Tendo definido o banco de dados, podemos agora começar a operar sobre ele por meio das operações de manipulação de SQL SELECT, INSERT, UPDATE e DELETE. Em particular, podemos executar operações relacionais de restrição, projeção e junção sobre os dados, utilizando em cada caso a instrução de manipulação de dados SELECT de SQL. A Figura 4.2 mostra como certas operações de restrição, projeção e junção podem ser formuladas em SQL. Nota: o exemplo de junção na figura ilustra o fato de que nomes qualificados (por exemplo, F.F#, FP.F#) são às vezes necessários em SQL para “tirar a ambigüidade” de referências a colunas. A regra geral é a de que esses nomes qualificados são sempre aceitáveis, mas nomes não qualificados também são aceitáveis, desde que não causem nenhuma ambigüidade. 
Observamos que a SQL também admite uma forma abreviada da cláusula SELECT, como ilustra o exemplo seguinte: 
SELECT * — ou “SELECT F.*’ (isto é, o * pode ser qualificado) 
FROM F ; 
O resultado é uma cópia da tabela F inteira; o asterisco é a abreviação para uma lista separada por vírgulas de todos nomes de colunas na(s) tabela(s) referenciada(s) na cláusula FROM, na ordem da esquerda para a direita em que essa(s) coluna(s) é (são) definida(s) dentro da(s) tabela(s). A propósito, note o comentário nesse exemplo (introduzido com um hífen duplo e encerrado com um caractere de nova linha). Nota: a expressão SELECT * FROM T, onde T é um nome de tabela, pode ser abreviada ainda mais, tornando-se apenas TABLE T. 
A instrução SELECT é discutida em extensão muito maior no Capítulo 7 (Seção 7.7). 
FIGURA 4.2 Exemplos de restrição, projeção e junção em SQL 
Vamos examinar agora as operações de atualização: já foram dados exemplos de instruções de SQL INSERT, UPDATE e DELETE no Capítulo 1, mas esses exemplos envolviam deliberadamente apenas operações de uma única linha. Contudo, como SELECT, as operações INSERT, UPDATE e DELETE em geral são todas operações em nível de conjunto (e alguns dos exercícios e respostas no Capítulo 1 de fato ilustravam esse detalhe). Aqui estão alguns exemplos de operações de atualização de alto nível para o banco de dados de fornecedores e peças: 
INSERT 
INTO TEMP ( P#, PESO 
SELECT P#, PESO 
FROM P 
WHERE COR = ‘Vermelha’ 
Esse exemplo pressupõe que já criamos outra tabela TEMP com duas colunas, P# e PESO. A instrução INSERT insere nessa tabela números de peças e pesos correspondentes a todas as peças vermelhas. 
UPDATE F 
SET STATUS = STATUS * 2 
WHERE CIDADE = ‘Paris’ 
Restrição: Resultado: 
SELECT F#, P#, QDE 
FROM FP 
WHERE QDE < 150 	F# 	# QDE 	
Fi Fi 	P5 100 
P6 100 	
		
Projeção: Resultado: 
SELECT F#, CIDADE 
FROM F ; 		CIDADE 	
F1
F2 
F3 
F4 
F5 	Londres 
Paris 
Paris 
Londres 
Atenas 	
Junção: 
SELECT F.F#, FNOME, STATUS» CIDADE, P#, QDE 
FROM F, FP 
WHERE F.F# = FP.F# 
Resultado: F# FNOME STATUS CIDADE r p# QDE 
F1 Smith 20 Londres P1 300 
F1 Smith 20 Londres P2 200 
F1 Smith 20 Londres P3 400 
F4 Clark 20 Londres P5 400 
A instrução UPDATE duplica o status para todos os fornecedores em Paris. 
DELETE 
FROM FP 
WHERE P# = ‘2’
A instrução DELETE elimina todas as remessas correspondentes à peça P2. 
Nota: a SQL não inclui uma analogia direta da operação de atribuição relacional. Porém, podemos simular essa operação eliminando primeiro todas as linhas da tabela de destino, e depois executando uma operação INSERT ... SELECT ... (como no primeiro exemplo anterior) nessa tabela. 
4.3 O CATÁLOGO 
O padrão SQL inclui especificações para um catálogo padrão chamado Information Schema (esquema de informações). De fato, os termos convencionais “catálogo” e “esquema” são ambos usados em SQL, mas com significados altamente específicos de SQL; em termos informais, um catálogo de SQL consiste nos descritores para um banco de dados individual,* e um esquema de SQL, nos descritores para a parte desse banco de dados que pertence a algum usuário individual. Em outras palavras, pode haver um número qualquer de catálogos (um por banco de dados), cada qual dividido em um número qualquer de esquemas. Entretanto, cada catálogo deve incluir exatamente um esquema chamado INFORMATIONSCHEMA e, da perspectiva do usuário, é esse esquema (como já mencionamos) que executa a função normal de catálogo. 
Desse modo, o Information Schema consiste em um conjunto de tabelas SQL cujo conteúdo reproduz efetivamente, de uma forma definida com precisão, todas as definições de todos os outros esquemas no catálogo em questão. De um modo mais exato, o Information Schema é definido para conter um conjunto de visões de um hipotético “Definition Schema” (esquema de definições). A implementação não tem a obrigatoriedade de fornecer suporte ao Definition Schema como tal, mas deve (a) dar suporte a algum tipo de “Definition Schema” e (b) dar suporte a visões desse “Definition Schema” semelhantes a visões do Information Schema. Surgem alguns pontos importantes: 
1. As razões para se enunciar a exigência em termos de dois itens separados (a) e (b) como acabamos de descrever é que, em primeiro lugar, os produtos existentes certamente oferecem suporte para algo semelhante ao “Definition Schema”. No entanto, esses “Definition Schemas” variam amplamente de um produto para outro (até mesmo quando os produtos em questão vêm do mesmo fabricante). Daí, faz sentido a idéia de exigir apenas que a implementação admita certas visões predefinidas de seu “Definition Schema”. 
2. Na realidade, devemos dizer “um” (e não “o”) Information Schema pois, como vimos, existe um esquema desse tipo em cada catálogo. Desse modo, em geral a totalidade de dados disponíveis para um determinado usuário não será descrita por um único Information Schema. Porém, por questão de simplicidade, continuaremos a falar como se existisse apenas um. 
Não vale a pena entrarmos em muitos detalhes sobre o conteúdo do Information Schema; em vez disso, simplesmente vamos relacionar algumas visões mais importantes do Information Schema, na esperança de que apenas seus nomes sejam suficientes para dar alguma idéia do conteúdo dessas visões. Entretanto, devemos dizer que a visão TABLE contém informações sobre todas as tabelas nomeadas, tanto visões quanto tabelas básicas, enquanto a visão VIEWS contém informações apenas sobre visões. 
* Mais precisamente, devemos mencionar que realmente não existe nada semelhante a um “banco de dados” no padrão SQL! O 
modo exato como é chamada a coleção de dados descrita por um catálogo é definido pela implementação. Porém, não é sem razão que ela é considerada um banco de dados. 75 
SCHEMATA REFERENTIALCONSTRAINTS A ( 
DOMAINSCHECKCONSTRAINTS 
TABLES KEYCOLUMNUSAGE DEL 
VIEWS ASSERTIONS FRC 
COLUMNS VIEWTABLEUSAGE WHE 
TABLEPRIVILEGES VI EWCOLUMNUSAGE AN[ 
COLUMNPRIVILEGES CONSTRAINTTABLEUSAGE 
USAGE PRIVILEGES CONSTRAINTCOLUMNUSAGE 
DOMAINCONSTRAINTS CONSTRAINTDOMAINUSAGE 4. 
TABLECONSTRAINTS 
A referência [4.19] oferece mais detalhes; em particular, mostra como formular consultas sobre o Information Schema (o processo não é tão direto quanto se poderia esperar). 
4.4 VISÕES 
Aqui está um exemplo de uma definição de visão em SQL: 
CREATE VIEW BOM_FORNECEDOR 
AS SELECT F#, STATUS, CIDADE 
FROM F 
WHERE STATUS > 15 
E aqui está um exemplo de uma consulta de SQL sobre essa visão: 
SELECT F#, STATUS 
FROM BOM FORNECEDOR 
WHERE CIDADE = Londres 
Substituindo a referência ao nome da visão pela definição da visão, obtemos uma expressão semelhant a esta (observe a subconsulta aninhada na cláusula FROM):
SELECT BOM_FORNECEDOR. F#, BOM_FORNECEDOR. STATUS 
FROM ( SELECT F#, STATUS, CIDADE 
FROM F 
WHERE STATUS > 15 ) AS BOM_FORNECEDOR 
WHERE BOM FORNECEDOR.CIDADE = Londres’ 
E essa expressão pode então ser simplificada, resultando em algo como isto: 
SELECT F#, STATUS 
FROM F 
WHERE STATUS > 15 
AND CIDADE = ‘Londres 
Essa última é a consulta realmenteexecutada. 
Como outro exemplo, considere a operação DELETE a seguir: 
DELETE 
FROM BOM_FORNECEDOR 
WHERE CIDADE = Londres’ 
76 
A operação DELETE realmente executada é semelhante a esta: 
DELETE 
FROM F 
WHERE STATUS > 15 
AND CIDADE = Londres’ 
4.5 TRANSAÇÕES 
Os análogos em SQL às nossas instruções COMMIT e ROLLBACK são chamados COMMIT WORK e ROLLBACK WORK, respectivamente (a palavra-chave WORK é opcional em ambos os casos). Entretanto, a SQL não inclui nenhuma instrução BEGIN TRANSACTION explícita. Em vez disso, uma transação é iniciada de forma implícita, sempre que o programa executa uma instrução de “inicialização de transação” e ainda não há uma transação em andamento. Os detalhes exatos sobre as instruções de SQL que inicializam transações estariam fora de lugar aqui; é suficiente dizer que todas as instruções descritas neste capítulo são de inicialização de transações (com exceção, é claro, das próprias COMMIT e ROLLBACK). 
4.6 SQL EMBUTIDA 
A maioria dos produtos de SQL permite que as instruções SQL sejam executadas diretamente (ou seja, interativamente a partir de um terminal on-line) e como parte de um programa aplicativo (isto é, as instruções de SQL podem estar embutidas, significando que elas podem estar entremeadas com as instruções da linguagem de programação de um tal programa). Além disso, no caso das instruções embutidas, o programa aplicativo em geral pode ser escrito em uma variedade de linguagens hospedeiras, como COBOL, Java, PL/I etc.* Nesta seção, consideraremos especificamente o caso das instruções embutidas. 
O princípio fundamental subjacente à SQL embutida, ao qual nos referimos como o princípio da dualidade, é que qualquer instrução de SQL que pode ser usada interativamente também pode ser empregada em um programa aplicativo. É claro que existem várias diferenças de detalhes entre uma determinada instrução SQL interativa e sua equivalente embutida, e operações de busca em particular exigem um tratamento significativamente estendido em um ambiente de programa hospedeiro (ver mais adiante nesta seção) mas, apesar disso, o princípio é amplamente verdadeiro. (A propósito, o inverso não é verdadeiro — várias instruções de SQL embutidas não podem ser usadas de modo interativo, conforme veremos.) 
Antes de podermos descrever as instruções reais da SQL embutida, é necessário abordar uma série de detalhes preliminares. A maioria desses detalhes é ilustrada pelo fragmento de programa mostrado na Figura 4.3. (Para fixarmos nossas idéias, supomos que a linguagem hospedeira é PL/I. A maior parte das idéias se traduz em outras linguagens hospedeiras, com pequenas alterações.) Vários pontos se destacam: 
1. As instruções de SQL embutida têm o prefixo EXEC SQL, a fim de distingui-las de instruções da linguagem hospedeira, e são encerradas por um símbolo terminador especial (um ponto-e-vírgula, no caso da linguagem PL/I). 
2. Uma instrução SQL executável (no restante desta seção, deixaremos de lado o qualificador “embutido”) poderá surgir sempre que uma instrução executável da hospedeira também puder aparecer. A propósito, note esse “executável”: diferente da SQL interativa, a SQL embutida inclui algumas instruções que são puramente declarativas e não executáveis.** Por exemplo, DECLARE CURSOR não é uma instrução executável (consulte a subseção “Operações que envolvem cursores”, mais adiante neste capítulo), nem as instruções BEGIN e END DECLARE SECTION (consulte o parágrafo 5 mais adiante), e nem a instrução WHENEVER (consulte o parágrafo mais adiante). 
* O padrão SQL [4.22] admite atualmente Ada, C, COBOL, Fortran, M (anteriormente chamada MUMPS), Pascal e PL/I. O suporte ao Java não estava incluído no momento em que este livro era escrito, mas ele deve ser acrescentado em breve (consulte a 
referência [4.6] e também o Apêndice B), e alguns produtos já o reconhecem. 
**Exatamente por esse motivo, essas instruções específicas também podem ser chamadas declarações. (N.T.) 77 
EXEC SQL BEGIN DECLARE SECTION 
DCL SQLSTATE CHAR(5) 
DCL P1 CHAR(6) 
DCL PESO FIXED DECIMAL(5,1); 
EXEC SQL END DECLARE SECTION 
= ‘P2 ; /* por exemplo */ 
EXEC SQL SELECT P.PESO 
INTO :PESO 
FROM P 
WHERE P.P# = :P# 
IF SQLSTATE = ‘00000 
THEN ... /* PESO = valor obtido pela busca / 
ELSE ... ; /* ocorreu alguma exceção */
FIGURA 4.3 Fragmento de um programa PL/I com SQL embutida 
3. As instruções de SQL podem incluir referências a variáveis hospedeiras; essas referências devem incluir um prefixo de dois-pontos para distingui-las dos nomes de colunas de SQL. As variáveis hospedeiras podem aparecer em SQL embutida onde quer que um literal possa surgir em SQL interativa. Elas também podem surgir em uma cláusula INTO em uma instrução SELECT (ver parágrafo 4 a seguir) ou FETCH (consulte novamente a subseção “Operações que envolvem cursores” mais adiante) para designar destinos de operações de busca. 
4. Note a cláusula INTO na instrução SELECT da Figura 4.3. A finalidade dessa cláusula é (como acabamos de mencionar) especificar as variáveis de destino nas quais os valores devem ser atribuídos; a i-ésima variável de destino mencionada na cláusula TNTO corresponde ao i-ésimo valor a ser retornado, como especifica a cláusula SELECT. 
5. Todas as variáveis hospedeiras referenciadas em instruções SQL devem ser declaradas (DCL em PL/I) dentro de uma seção de declaração de SQL embutida, delimitada pelas instruções BEGIN e 
END DECLARE SECTION. 
6. Todo programa que contém instruções SQL embutidas deve incluir uma variável hospedeira chamada SQLSTATE. Após a execução de qualquer instrução de SQL, um código de status é retornado ao programa nessa variável; em particular, o código de status 00000 significa que a instrução foi executada com sucesso, e o valor 02000 significa que a instrução foi executada, mas que não foram encontrados dados que satisfizessem o pedido. Por essa razão, em princípio, toda instrução SQL no programa deve ser seguida por um teste em SQLSTATE, e devem ser executadas ações apropriadas se o valor não for o esperado. Contudo, na prática, esses testes podem com freqüência ser implícitos (consulte o parágrafo 9 a seguir). 
7. Variáveis hospedeiras devem ter um tipo de dado apropriado para os usos a que elas se destinam. Em particular, uma variável hospedeira que tenha de ser usada como destino (por exemplo, em SELECT) deve ter um tipo de dados compatível com o da expressão que fornece o valor a ser atribuído a esse destino; da mesma forma, uma variável hospedeira que tenha de ser usada como origem (por exemplo, em INSERT) deve ter um tipo de dados compatível com o da coluna de SQL à qual os valores dessa origem devem ser atribuídos. Comentários semelhantes se aplicam a uma variável hospedeira que deva ser usada em uma comparação ou, na verdade, em qualquer tipo de operação. Para obter detalhes sobre o significado exato da compatibilidade dos tipos de dados no sentido anterior, consulte a referência [4.22]. 
78
8. Variáveis hospedeiras e colunas de SQL podem ter o mesmo nome. 
9. Como já mencionamos, toda instrução SQL deve, em princípio, ser seguida por um teste do valor retornado em SQLSTATE. A instrução WHENEVER é fornecida para simplificar esse processo. A instrução WHENEVER assume a forma: 
EXEC SQL WHENEVER <condição> <ação> 
Aqui, <condição> é SQLERROR ou NOT FOUND, e <ação> é uma instrução CONTINUE ou GO TO. A instrução WHENEVER não é uma instrução executável, mas sim uma diretiva para o compilador de SQL. A expressão “WHENEVER <condição> GO TO <rótulo>” faz o compilador inserir uma instrução da forma “IF <condição> GO TO <rótulo> END IF” após cada instrução de SQL executável que encontrar; já “WHENEVER <condição> CONTINUE” faz com que não seja inserida nenhuma dessas instruções; nesse caso, a implicação é que o programador fará a inserção manual de tais instruções. Os dois argumentos <condição> são definidos da seguinte maneira: 
NOT FOUND significa não foram encontrados dados 
— SQLSTATE = 02000 (normalmente) 
SQLERROR significa ocorreuum erro 
— ver referência [4.22] sobre SQLSTATE 
Cada instrução WHENEVER que o compilador de SQL encontra em sua busca seqüencial pelo texto do programa (para uma determinada condição) anula a anterior que ele encontrou (para essa condição). 
10. Por fim, observe que — para usar a terminologia do Capítulo 2 — a SQL embutida constitui um acoplamento fraco entre a SQL e a linguagem hospedeira. 
Aqui terminam os conceitos preliminares. No restante desta seção, iremos concentrar nossa atenção especificamente em operações de manipulação de dados. Conforme já indicamos, a maioria dessas operações pode ser tratada de forma bastante direta (isto é, com apenas algumas alterações em sua sintaxe). No entanto, as operações de busca exigem um tratamento especial. O problema é que essas operações retornam muitas linhas (em geral), não apenas uma, e as linguagens hospedeiras normalmente não estão equipadas para manipular mais de uma linha de cada vez. Por esse motivo, é necessário fornecer alguma espécie de ponte entre o processamento orientado a conjuntos da SQL e o processamento orientado a tuplas (ou linhas) da linguagem hospedeira, e os cursores fornecem tal ponte. Um cursor é um tipo especial de objeto da SQL que só se aplica à SQL embutida (porque a SQL interativa não precisa dele). Em essência, ele consiste em uma espécie de ponteiro (lógico) que pode ser usado para examinar uma coleção de linhas, apontando para cada uma das linhas de cada vez e fornecendo assim a possibilidade de endereçar essas linhas uma a uma. Porém, adiaremos a descrição detalhada dos cursores para uma seção posterior, e consideraremos primeiro as instruções que não necessitam deles. 
Operações que não envolvem cursores 
As instruções de manipulação de dados que não necessitam de cursores são: 
• SELECT unitária. 
• INSERT. 
• UPDATE (exceto na forma CURRENT — ver mais adiante). 
• DELETE (novamente, exceto na forma CURRENT — ver mais adiante). 
Daremos exemplos de cada dessas instruções, uma por vez. 
79 
SELECT unitária: obter o status e a cidade para o fornecedor cujo número de fornecedor é dado pela variável hospedeira DADOF#. 
EXEC SQL SELECT STATUS, CIDADE 
INTO :GRAU, :CIDADE 
FROM F 
WHERE F# : DADOF# 
Usamos o termo SELECT unitária para indicar uma expressão SELECT que é avaliada como uma tabela contendo no máximo uma linha. No exemplo, se houver exatamente uma linha na tabela F que satisfaça à condição da cláusula WHERE, então os valores de STATUS e CIDADE dessa linha serão atribuídos às variáveis hospedeira GRAU e CIDADE como solicitado, e SQLSTATE será definida como 00000. Se nenhuma linha de F satisfazer à condição de WHERE, SQLSTATE será definida como 02000. Além disso, se mais de uma linha satisfazer à condição, o programa tem erro e SQLSTATE será definida como um código de erro. 
INSERT: inserir uma nova peça (número de peça, nome e peso dados pelas variáveis hospedeiras P#, PNOME e PPS, respectivamente; cor e cidade desconhecidos) na tabela P. 
EXEC SQL INSERT 
INTO P ( P#, PNOME, PESO 
VALUES ( :P#, :PNOME, :PPS ) ; 
Os valores de COR e CIDADE para a nova peça serão definidos como os valores default aplicáveis. Consulte o Capítulo 5, Seção 5.5, para ver uma descrição dos valores default da SQL. 
UPDATE: aumentar o status de todos os fornecedores de Londres de acordo com a proporção dada pela variável hospedeira AUMENTO. 
EXEC SQL UPDATE F 
SET STATUS = STATUS + :AUMENTO 
WHERE CIDADE = ‘Londres 
Se nenhuma linha de fornecedor satisfizer à condição WHERE, SQLSTATE será definida como 02000. 
DELETE: eliminar todas as remessas correspondentes a fornecedores cuja cidade é dada pela variável hospedeira CIDADE. 
EXEC SQL DELETE 
FROM FP 
WHERE :CIDADE = 
SELECT CIDADE 
FROM F 
WHERE F.F# = FP.F# ) ; 
Novamente, SQLSTATE será definida como 02000 se nenhuma linha de FP satisfizer à condição WHERE. Mais uma vez, observe a subconsulta aninhada (dessa vez na cláusula WHERE). 
Operações que envolvem cursores 
Agora vamos examinar a questão da busca em nível de conjunto — isto é, o retorno de um conjunto con80 tendo um número arbitrário de linhas, em vez de no máximo uma linha, como no caso da SELECT unitária. Como explicamos antes, o que é necessário aqui é um mecanismo para obter acesso às linhas do conjunto uma a uma, e os cursores oferecem esse mecanismo. O processo é ilustrado de forma geral pelo exemplo da Figura 4.4 (a seguir), o qual pretende buscar detalhes de fornecedores (F#, FNOME e STATUS) para todos os fornecedores na cidade dada pela variável hospedeira Y. 
Explicação: a instrução “DECLARE X CURSOR...” define um cursor chamado X, com uma expressão de tabela associada (ou seja, uma expressão avaliada como uma tabela), especificada pela instrução SELECT que forma parte dessa DECLARE. Essa expressão de tabela não é avaliada nesse momento; DECLARE CURSOR é uma instrução puramente declarativa. A expressão é avaliada quando o cursor é aberto (“OPEN X”). A instrução “FETCH X INTO...” é usada então para recuperar as linhas uma de cada vez no conjunto resultante, atribuindo os valores retornados a variáveis hospedeiras de acordo com as especificações da cláusula INTO nessa instrução. (Por simplicidade, demos às variáveis hospedeiras os mesmos nomes das colunas correspondentes do banco de dados. Note que a instrução SELECT na declaração do cursor não tem uma cláusula INTO própria.) Tendo em vista que haverá muitas linhas no conjunto de resultados, a instrução FETCH aparecerá normalmente dentro de um loop; o loop será repetido desde que ainda existam outras linhas a serem incluídas no conjunto de resultados. Na saída do loop, o cursor X é fechado (“CLOSE X”). 
EXEC SQL DECLARE X CURSOR FOR /* define o cursor /
SELECT F.F#, F.FNOME, F.STATUS 
FROM F 
WHERE F.CIDADE = 
ORDER BY F# ASC ; 
EXEC SQL OPEN X ; /* executa a consulta /
DO /*para todas as linhas de F acessíveis via X*/ 
EXEC SQL FETCH X INTO :F#, :FNOME, :STATUS ; 
/*vai buscar próximo fornecedor /
END ; 
EXEC SQL CLOSE X ; /* desativa o cursor X */
FIGURA 4.4 Exemplo de busca retornando várias linhas 
Agora vamos considerar os cursores e as operações de cursores com mais detalhes. Em primeiro lugar, um cursor é declarado por meio de uma instrução DECLARE CURSOR, que assume o formato geral: 
EXEC SQL DECLARE <nome do cursor> CURSOR 
FOR <expressão de tabela> { <ordenação> 
(estamos ignorando algumas especificações opcionais no interesse da brevidade). Para ver uma explicação completa de <expressão de tabela>, consulte o Apêndice A. O parâmetro opcional <ordenação> toma a forma: 
ORDER BY <lista_com_vírgulas de itens de ordenação> 
onde (a) a lista com vírgulas de <itens de ordenação> não deve estar vazia — ver o parágrafo imediatamente seguinte — e (b) cada <item de ordenação> individual consiste em um nome de coluna (não qualificado, devemos observar), seguido opcionalmente por ASC (ascendente ou crescente) ou DESC (descendente ou decrescente); ASC é o default. 
Nota: definimos o termo lista_com_vírgulas como a seguir. Considere que <xyz> denote uma categoria sintática arbitrária (isto é, qualquer coisa que apareça no lado esquerdo de alguma regra de produção 81 
da BNF). Então, a expressão <lista_com_vírgulas de xyz> denota uma seqüência de zero ou mais <xyz>s, na qual cada par de <xyz>.s adjacentes está separado por uma vírgula (e possivelmente por um ou mais espaços em branco). Observe que faremos uso extensivo do recurso da lista de vírgulas em regras de sintaxe futuras (na verdade, em todas as regras de sintaxe, não apenas nas de SQL). 
Conforme afirmamos anteriormente, a instrução DECLARE CURSOR é declarativa, e não-executável; ela declara um cursor com o nome especificado e que tem a expressão de tabela e a ordenação especificadas associadas permanentemente a ele. A expressão de tabela pode incluir referências a variáveis hospedeiras. Um programa pode incluir qualquer número de instruções DECLARE CURSOR, cada uma das quais deve (é claro) servir a um cursor diferente. 
Três instruções executáveis sãofornecidas para operação sobre cursores: OPEN, FETCH e 
CLOSE. 
A instrução: 
EXEC SQL OPEN <nome de cursor> 
abre ou ativa o cursor especificado (que não deve estar aberto no momento). Na verdade, a expressão de tabela associada com o cursor é avaliada (usando-se os valores atuais de quaisquer variáveis hospedeiras referenciadas dentro dessa expressão); um conjunto de linhas é portanto identificado e se torna o conjunto ativo corrente para o cursor. O cursor também identifica uma posição dentro desse conjunto ativo, ou seja, a posição imediatamente antes da primeira linha. (Conjuntos ativos sempre são considerados como tendo uma ordenação; desse modo, o conceito de posição tem significado.* A ordenação é a definida pela cláusula ORDER BY ou uma ordenação determinada pelo sistema, na ausência de tal cláusula.) 
A instrução: 
EXEC SQL FETCH <nome de cursor> 
INTO <lista_com—vírgulas de referências a variáveis hospedeiras> 
avança o cursor especificado (que deve estar aberto) para a próxima linha no conjunto ativo, e depois atribui o i-ésimo valor dessa linha à i-ésima variável hospedeira referenciada na cláusula INTO. Se não houver uma próxima linha quando FETCH for executada, SQLSTATE será definida como 02000 e nenhum dado será retornado. 
A instrução: 
EXEC SQL CLOSE <nome de cursor> 
fecha ou desativa o cursor especificado (que deve estar aberto no momento). Agora, o cursor não tem nenhum conjunto ativo atual. Porém, ele pode ser novamente aberto em seguida; nesse caso, ele irá obter outro conjunto ativo — talvez não exatamente o mesmo conjunto de antes, em especial se os valores de quaisquer variáveis hospedeiras referenciadas na declaração do cursor tiverem sido alteradas nesse meio tempo. Observe que a alteração dos valores dessas variáveis hospedeiras enquanto o cursor está aberto não tem nenhum efeito sobre o conjunto ativo atual. 
Duas instruções adicionais podem incluir referências a cursores, isto é, as formas CURRENT de UPDATE e DELETE. Se um cursor, digamos X, estiver posicionado no momento sobre uma determinada linha, é possível a operação UPDATE (de alterar) ou DELETE (de excluir) “o valor atual de X”, ou seja, a linha na qual X está posicionado. Por exemplo: 
EXEC SQL UPDATE F 
SET STATUS = STATUS + :AUMENTO 
WHERE CURRENT OF X ; 
* É claro que conjuntos propriamente ditos não têm uma ordenação (ver Capítulo 5); assim, um “conjunto ativo” na realidade não é de modo algum um conjunto em si. Seria melhor considerá-lo uma lista ordenada ou um array (de linhas). 
Nota: as formas CURRENT de UPDATE e DELETE não serão permitidas se a expressão de tabela na declaração do cursor definir uma visão não atualizável, caso ela faça parte de uma instrução CREATE VIEW (consulte o Capítulo 9, Seção 9.6). 
SQL dinâmica 
A SQL dinâmica consiste em um conjunto de recursos embutidos de SQL que se destinam a oferecer suporte à construção de aplicações generalizadas, on-line e possivelmente interativas. (Lembramos que, no Capítulo 1, uma aplicação on-line foi definida como uma aplicação capaz de fornecer suporte para o acesso ao banco de dados a partir de um terminal on-line.) Considere o que uma típica aplicação on-line tem de fazer. Em linhas gerais, os passos que ela deve percorrer são: 
1. Aceitar um comando do terminal. 
2. Analisar esse comando. 
3. Executar instruções SQL apropriadas sobre o banco de dados. 
4. Retornar uma mensagem e/ou resultados ao terminal. 
Se o conjunto de comandos que o programa pode aceitar no Passo 1 for razoavelmente pequeno, como no caso de (talvez) um programa que lida com reservas de passagens aéreas, então o conjunto de instruções SQL passíveis de serem executadas provavelmente também será pequeno e poderá ser “embutido no código” do programa. Nesse caso, os Passos 2 e 3 anteriores consistirão apenas na lógica para examinar o comando de entrada, e depois no desvio para a parte do programa que emite a(s) instrução(ões) SQL predefinida(s). Por outro lado, se houver possibilidade de grandes variações na entrada, então poderá não ser prático predefinir e “embutir no código” instruções SQL para cada comando possível. Em vez disso, talvez seja muito mais conveniente construir as instruções SQL necessárias de forma dinâmica e, em seguida, compilar e executar essas instruções. Os recursos de SQL dinâmica são fornecidos para auxiliá-lo nesse processo. 
As duas principais instruções dinâmicas são PREPARE e EXECUTE. Seu uso está ilustrado no seguinte exemplo (irrealista e simples, porém preciso). 
DCL SQLSOURCE CHAR VARYING (65000) 
SQLSOURCE = ‘DELETE FROM FP WHERE QDE < 300 
EXEC SQL PREPARE SQLPREPPED FROM :SQLSOURCE 
EXEC SQL EXECUTE SQLPREPPED 
Explicação: 
1. O nome SQLSOURCE identifica uma variável de string de caracteres de comprimento variável em PL/I, na qual o programa construirá de algum modo o formato fonte (isto é, a representação do string de caracteres) de alguma instrução SQL — uma instrução DELETE em nosso exemplo específico. 
2. Em contraste, o nome SQLPREPPED identifica uma variável SQL, não uma variável PL/I, que será usada (conceitualmente) para guardar a forma compilada da instrução SQL cujo fonte é dado em SQLSOURCE. (Os nomes SQLSOURCE e SQLPREPPED são naturalmente arbitrários.) 
3. A instrução de atribuição em PL/I “SQLSOURCE = ...;“ atribui a SQLSOURCE a forma fonte de uma instrução DELETE da SQL. É claro que, na prática, o processo de construção de uma instrução fonte como essa provavelmente será muito mais complexo — envolvendo talvez a entrada e a análise de alguma solicitação do usuário final, expressa em linguagem natural ou de algum outro modo mais amistoso para o usuário que a SQL. 
83 
4. A instrução PREPARE recebe então essa instrução fonte e a “prepara” (isto é, compila) para produzir uma versão executável, a qual é armazenada em SQLPREPPED. 
5. Finalmente, a instrução EXECUTE executa essa versão de SQLPREPPED e, desse modo, realiza a operação DELETE de fato. As informações de SQLSTATE da instrução DELETE são retornadas como se DELETE tivesse sido executada diretamente da maneira normal. 
Observe que, pelo fato de denotar uma variável SQL e não uma variável PL/I, o nome SQLPREPPED não tem o prefixo de dois-pontos quando é referenciado nas instruções PREPARE e EXECUTE. Observe também que essas variáveis SQL não precisam ser declaradas de modo explícito. 
A propósito, o processo que acabamos de descrever é exatamente o que acontece quando as próprias instruções SQL são introduzidas de modo interativo. A maioria dos sistemas oferece alguma espécie de processador de consultas de SQL interativa. Na verdade, esse processador de consultas é apenas um tipo particular de aplicação on-line generalizada; ele está preparado para aceitar uma variedade extremamente ampla de formas de entrada, ou seja, qualquer instrução SQL válida (ou não-válida!). Ele utiliza os recursos da SQL dinâmica para construir instruções SQL convenientes que correspondem à sua entrada, para compilar e executar essas declarações construídas, e ainda para retornar mensagens e resultados ao terminal. 
Concluímos esta subseção (e esta seção) com uma breve menção a um acréscimo mais recente (de 1995) ao padrão, conhecido como SQL Call-Level Interface (“SQL/CLI”, sendo CLI a abreviatura da expressão em inglês correspondente a interface de nível de chamada). A CLI se baseia fortemente na interface Open Database Connectivity (ODBC) da Microsoft. A CLI permite que uma aplicação escrita em uma das linguagens hospedeiras usuais emita solicitações invocando certas rotinas da CLI fornecidas pelo fabricante. Essas rotinas, que devem ter sido vinculadas à aplicação em questão, utilizam então a SQL dinâmica para executar as operações de banco de dados solicitadas em favor da aplicação. (Em outras palavras, do ponto de vista do SGBD, as rotinas da CLI podem ser consideradas apenas como outra aplicação.) 
Como podemos ver, a SQL/CLI (e também a ODBC, é bom frisar) procura resolver o mesmo problema geral que a SQL dinâmica: ambas permitem que sejam escritasaplicações para as quais as instruções SQL exatas a serem executadas não são conhecidas até o momento da execução. Entretanto, na realidade elas representam uma abordagem melhor que a SQL dinâmica para o problema. Há duas razões principais para isso: 
• Em primeiro lugar, a SQL dinâmica é um padrão de código-fonte. Assim, qualquer aplicação que usa a SQL dinâmica exige os serviços de algum tipo de compilador de SQL para processar as operações — PREPARE, EXECUTE, etc. — prescritas por esse padrão. Em contraste, a CLI simplesmente padroniza os detalhes de certas invocações de rotina (isto é, basicamente chamadas de sub-rotinas); não é necessário nenhum serviço especial do compilador, apenas os serviços normais do compilador padrão da linguagem hospedeira. Como resultado, as aplicações podem ser distribuídas (talvez por fornecedores de software independentes) sob a forma de código-objeto “empacotado”. 
• Segundo, essas aplicações podem ser independentes do SGBD; ou seja, a CLI inclui recursos que permitem a criação (novamente, talvez por fornecedores de software independentes) de aplicações genéricas que podem ser usadas com vários SGBDs diferentes, em vez de terem de ser específicas para algum SGBD em particular. 
Interfaces como CLI, ODBC e JDBC (uma variante em Java da ODBC) estão se tornando cada vez mais importantes na prática, por razões que serão discutidas (em parte) no Capítulo 20. 
4.7 A SQL NÃO É PERFEITA 
Como afirmamos na introdução a este capítulo, a SQL está muito longe de ser a linguagem relacional “perfeita” — ela sofre de numerosos pecados de omissão e comissão. Serão oferecidas críticas específicas em pontos apropriados de 
84
capítulos subseqüentes, mas a questão fundamental é simplesmente a de que a SQL apresenta falhas em um número muito grande de aspectos para fornecer suporte apropriado ao modelo relacional. Em conseqüência disso, não está claro de modo algum que os produtos SQL de hoje realmente devam merecer o rótulo de “relacionais”! De fato, pelo menos até onde o autor tem conhecimento, não existe nenhum produto no mercado atual que ofereça suporte a todos os detalhes do modelo relacional. Isso não quer dizer que algumas partes do modelo não tenham importância; pelo contrário, todo detalhe do modelo é importante e, mais ainda, é importante por razões genuinamente práticas. É importante frisar que, na realidade, o propósito da teoria relacional não é apenas teórico; em vez disso, a finalidade dessa teoria é fornecer uma base sobre a qual serão elaborados sistemas 100% práticos. Porém, o triste fato é que os fornecedores não têm ainda a exata noção do desafio de implementar a teoria em sua totalidade. Em conseqüência disso, todos os produtos “relacionais” de hoje apresentam falhas, de um modo ou de outro, quando se trata de fornecer todos os benefícios da tecnologia relacional. 
4.8 RESUMO 
Isso conclui nossa introdução a alguns dos principais recursos do padrão SQL (“SQL/92”). Enfatizamos o fato de que a SQL é muito importante do ponto de vista comercial, embora infelizmente ela seja um pouco deficiente sob a ótica relacional pura. 
A SQL inclui um componente de linguagem de definição de dados (DDL — data definition language) e um componente de linguagem de manipulação de dados (DML — data manipulation language). A DML de SQL pode operar tanto no nível externo (sobre visões) quanto no nível conceitual (sobre tabelas básicas). Do mesmo modo, a DDL de SQL pode ser usada para definir objetos no nível externo (visões), no nível conceitual (tabelas básicas), e mesmo — na maioria dos sistemas comerciais, embora não no padrão em si — no nível interno (isto é, em índices e outras estruturas físicas de armazenamento). Além disso, a SQL também oferece certos recursos de controle de dados — ou seja, recursos que na realidade não podem ser classificados como pertencentes à DDL ou à DML. Um exemplo desses recursos é a instrução GRANT, que permite aos usuários concederem privilégios de acesso uns aos outros (consulte o Capítulo 16). 
Mostramos como a SQL pode ser usada para criar tabelas básicas, com a utilização da instrução CREATE TABLE. Em seguida, apresentamos alguns exemplos de instruções SELECT, INSERT, UPDATE e DELETE, mostrando em particular como SELECT pode ser usada para expressar as operações relacionais de restrição, projeção e junção. Também descrevemos brevemente o Information Schema, que consiste em um conjunto de visões prescritas a partir de um hipotético “Definition Schema”. Além disso, examinamos os recursos da SQL para lidar com visões e transações. 
Uma parte bem grande do capítulo tratou da SQL embutida. A idéia básica que rege a SQL embutida é o princípio da dualidade, isto é, o princípio segundo o qual (na medida do possível) qualquer instrução SQL que possa ser utilizada interativamente também possa ser usada em um programa aplicativo. A principal exceção a esse princípio surge em conexão com operações de busca com retorno de várias linhas, que exigem o uso de um cursor para servir de ponte sobre o abismo entre o processamento orientado a conjuntos da SQL e o processamento orientado a tuplas ou linhas das linguagens hospedeiras, como PL/I. 
Depois de um certo número de temas preliminares necessários (embora relacionados principalmente com a sintaxe) — incluindo em particular uma breve explicação de SQLSTATE — consideramos as operações, como SELECT unitária, INSERT, UPDATE e DELETE, que não precisam de cursores. Depois voltamos nossa atenção para as operações que precisam de cursores, e discutimos DECLARE CURSOR, OPEN, FETCH, CLOSE e as formas CURRENT (atuais) de UPDATE e DELETE. (O padrão se refere às formas CURRENT desses operadores como UPDATE e DELETE posicionados e usa o termo UPDATE e DELETE pesquisados para as formas não CURRENT ou “caídas do céu”.) Finalmente, fornecemos uma introdução muito breve do conceito de SQL dinâmica, descrevendo em especial as instruções PREPARE e EXECUTE, e mencionamos também a CLI, ou Call-Level Interface (Interface de nível de chamada) de SQL. 85 
EXERCÍCIOS 
4.1 A Figura 4.5 (a seguir) mostra alguns valores de dados de amostra para uma forma estendida do banco de dados de fornecedores e peças que chamamos banco de dados de fornecedores, projetos e peças. Fornecedores (F), peças (P) e projetos (J) são identificados de forma exclusiva por número de fornecedor (F#), número de peça (P#) e número de projeto (J#), respectivamente. O significado de uma linha de FPJ (remessa) é que o fornecedor especificado fornece a peça especificada para o projeto especificado na quantidade especificada (e a combinação F#-P#-J# identifica de modo exclusivo tal linha). Escreva um conjunto apropriado de definições SQL para esse banco de dados. Nota: esse banco de dados será usado como base para numerosos exercícios em capítulos subseqüentes. 
4.2 Na Seção 4.2, descrevemos a instrução CREATE TABLE conforme ela é definida pela SQL padrão [4.11. Muitos produtos comerciais de SQL oferecem suporte para opções adicionais sobre essa instrução; porém, em geral elas estão relacionadas com índices, alocação de espaço de disco e outras questões de implementação (prejudicando com isso os objetivos de independência física de dados e compatibilidade entre sistemas). Examine qualquer produto SQL que possa estar disponível para você. As críticas precedentes se aplicam a esse produto? Especificamente, quais opções adicionais de CREATE TABLE o produto admite? 
4.3 Mais uma vez, investigue qualquer produto de SQL que possa estar disponível para você. Esse produto oferece suporte para o Information Schema? Se não, que aspecto tem o seu suporte de catálogo? 
4.4 Apresente formulações de SQL para os seguintes problemas de atualização do banco de dados de fornecedores-peças-projetos: 
a. Inserir um novo fornecedor FiO na tabela F. O nome e a cidade são Smith e Nova York, respectivamente; o status ainda não é conhecido. 
b. Mudar a cor de todas as peças vermelhas para alaranjado. 
c. Eliminar (excluir) todos os projetos para os quais não há remessas.FIGURA 4.5 O banco de dados de fornecedores, peças e projetos (amostras de valores) 
FPJ 
F 
P 
J 
86 
	F# 
	ENOME 
	STATUS 
	CIDADE 
	F1 
	Smith 
	20 
	Londres 
	F2 
	Jones 
	10 
	Paris 
	F3 
	Blake 
	30 
	Paris 
	F4 
	Clark 
	20 
	Londres 
	F5 
	Adams 
	30 
	Atenas 
	P# 
	PNOME 
	COR 
	PESO 
	CIDADE 
	P1 
	Porca 
	Vermelho 
	12.0 
	Londres 
	P2 
	Pino 
	Verde 
	17.0 
	Paris 
	P3 
	Parafuso 
	Azul 
	17.0 
	Roma 
	P4 
	Parafuso 
	Vermelho 
	14.0 
	Londres 
	P5 
	Came 
	Azul 
	12.0 
	Paris 
	P6 
	Tubo 
	Vermelho 
	19.0 
	Londres 
	J# 
	JNOME 
	CIDADE 
	Ji 
	Classificador 
	Paris 
	J2 
	Monitor 
	Roma 
	J3 
	OCR 
	Atenas 
	34 
	Console 
	Atenas 
	35 
	RAID 
	Londres 
	J6 
	EDS 
	Oslo 
	J7 
	Fita 
	Londres 
	F# 
	P# 
	J# 
	QDE 
	Fi 
	P1 
	Ji 
	200 
	Fi 
	P1 
	J4 
	700 
	F2 
	P3 
	Ji 
	400 
	F2 
	P3 
	J2 
	200 
	F2 
	P3 
	33 
	200 
	F2 
	P3 
	J4 
	500 
	F2 
	P3 
	J5 
	600 
	F2 
	P3 
	J6 
	400 
	F2 
	P3 
	37 
	800 
	F2 
	P5 
	32 
	100 
	F3 
	P3 
	Ji 
	200 
	F3 
	P4 
	32 
	500 
	F4 
	P6 
	J3 
	300 
	F4 
	P6 
	37 
	300 
	F5 
	P2 
	J2 
	200 
	F5 
	P2 
	J4 
	100 
	F5 
	P5 
	35 
	500 
	F5 
	P5 
	J7 
	100 
	F5 
	P6 
	J2 
	200 
	F5 
	P1 
	J4 
	100 
	F5 
	P3 
	34 
	200 
	F5 
	P4 
	J4 
	800 
	F5 
	P5 
	34 
	400 
	F5 
	P6 
	34 
	500 
4.5 Usando o banco de dados fornecedores-peças-projetos, escreva um programa com instruções de SQL embutida para listar todas as linhas de fornecedores, em ordem de número de fornecedor. Cada linha de fornecedor deve ser seguida imediatamente na listagem por todas as linhas de projetos fornecidos por esse fornecedor, em ordem de número de projeto. 
4.6 Considere as tabelas PEÇA e ESTRUTURA_PEÇA definidas como a seguir: 
CREATE TABLE PEÇA 
DESCRIÇÃO 
PRIMARY KEY ( P# ) ) ; 
CREATE TABLE ESTRUTURA_PEÇA 
( PRINCP# ... , SECP# ... , QDE 
PRIMARY KEY ( PRINCP#, SECP# ), 
FOREIGN KEY ( PRINCP# ) REFERENCES PEÇA, 
FOREIGN KEY ( SEC P# ) REFERENCES PEÇA 
A tabela ESTRUTURA_PEÇA mostra quais peças (PRINC_P#) contêm quais outras peças (SEC_P#) como componentes de primeiro nível. Escreva um programa SQL para listar todas as peças componentes de uma dada peça, para todos os níveis (o problema conhecido como part explosion). Nota: os dados de amostra apresentados na Figura 4.6 poderão ajudá-lo a visualizar esse problema. Observamos que a tabela ESTRUTURA_PEÇA mostra como os dados da lista de materiais (bili-o [-materiais) consulte o Capítulo 1, Seção 1.3, subseção “Entidades e relacionamentos” são representados tipicamente em um sistema relacional. 
FIGURA 4.6 A tabela ESTRUTURA_PEÇA (amostra de valores) 
REFERÊNCIAS E BIBLIOGRAFIA 
4.1 M. M. Astrahan e R. A. Lorie: “SEQUEL-XRM: A Relational System”, Proc. ACM Pacific Regional Conf., San Francisco, Calif. (abril de 1975). 
Descreve a implementação do primeiro protótipo de SEQUEL, a versão original de SQL [4.8]. Ver também as referências [4.2 e 4.3], que realizam função análoga para o System R. 
4.2 M. M. Astrahan et ai.: “System R: Relational Approach to Database Management”, ACM TODS 1, Número 
2 (junho de 1976). 
O System R era a implementação de protótipo principal da linguagem SEQUEL/2 (mais tarde chamada SQL) [4.8]. Esse artigo descreve a arquitetura do System R, como ela foi originalmente planejada. Ver também a referência [4.3]. 
4.3 M. W. Blasgen et ai.: “System R: An Architectural Overview”, IBM Sys. J. 20, Número 1 (fevereiro de 
1981). 
Descreve a arquitetura do System R, como ela se tornou quando o sistema foi completamente implemen tad (compare com a referência [4.2]). 87 
	ESTRUTURA_PEÇA 
	PRINCP# 
	SEC_P# 
	QDE 
	P1 
	P2 
	2 
	
	P1 
	P3 
	4 
	
	P2 
	P3 
	1 
	
	P2 
	P4 
	3 
	
	P3 
	P5 
	9 
	
	P4 
	P5 
	8 
	
	P5 
	P6 
	3 
4.4 Stephen Cannan e Gerard Otten: SQL — The Standard Handbook. Maidenhead, Reino Unido: McGraw-Hill International (1993). 
“[Nosso] objetivo ... é fornecer uma obra de referência explicando e descrevendo [a SQL/92 em sua definição original] de um modo muito menos formal e muito mais legível que o próprio padrão” (da introdução do livro). 
4.5 Joe Celko: SQL for Smarties: Advanced SQL Programming. San Francisco, Calif.: Morgan Kaufmann (1995). 
“Esse é o primeiro livro avançado de SQL disponível que oferece uma apresentação completa das técnicas necessárias para dar suporte a seu progresso de usuário casual de SQL até se tornar um programador especialista” (da própria capa do livro). 
4.6 Andrew Eisenberg e Jim Melton: “SQLJ Part 0, Now Known as SQL/OLB (Object Language Bindings)”, ACM SIGMOD Record 27, Número 4 (dezembro de 1998). Ver também Gray Clossman et ai.: “Java and Relational Databases: SQLJ”, Proc. 1998 ACM SIGMOD Int. Conf. on Management of Data, Seattle, Wash. (junho de 1998). 
4.7 Don Chamberlin: Using the New DB2. San Francisco. Calif.: Morgan Kaufmann (1996). 
Uma descrição legível e completa de um produto comercial de SQL de última geração, feita por um dos dois principais projetistas da linguagem SQL original [4.8]. 
Nota: o livro também descreve “algumas decisões controvertidas” tomadas no projeto de SQL — principalmente (a) a decisão de oferecer suporte a nulos e (b) a decisão de permitir a duplicação de linhas. “Meu [isto é, o de Chamberlin] propósito... é histórico, em vez de persuasivo — reconheço que nulos e duplicatas são questões religiosas... Em sua maioria, os projetistas [de SQL] eram pessoas práticas, e não teóricas, e essa orientação se refletiu em muitas decisões [de projeto].” Essa posição é muito diferente da que é mantida por este autor! Nulos e duplicatas são questões científicas, não religiosas; elas são discutidas cientificamente neste livro nos Capítulos 18 e 5, respectivamente. No caso de “práticas... e não [teóricas]”, rejeitamos categoricamente a sugestão de que a teoria não é prática; já afirmamos (na Seção 4.5) nossa posição de que pelo menos a teoria relacional é, de fato, muito prática. 
4.8 Donald D. Chamberlin e Raymond F. Boyce: “SEQUEL: A Structured English Query Language”, Proc. 
1974 ACM SIGMOD Workshop on Data Description, Access, and Control, Ann Arbor, Mich. (maio de 
1974). 
O artigo que primeiro introduziu a linguagem SQL (ou SEQUEL, como ela foi chamada originalmente; o nome foi modificado mais tarde por razões legais). 
4.9 Donald D. Chamberlin et ai.: “SEQUEL/2: SEQUEL/2: A Unified Approach to Data Definition, Manipulation, and Control”. IBMJ. R&D. 20, Número 6 (novembro 1976). Ver também a errata em IBMJ. R&D. 21, Número 1 (janeiro 1977). 
A experiência da implementação do protótipo original de SEQUEL discutida na referência [4.1] e os resultados dos testes de facilidade de uso relatados na referência [4.28] levaram ao projeto de uma versão revisada da linguagem, chamada SEQUEL/2. A linguagem admitida pelo System R [4.2 e 4.3] era basicamente SEQUEL/2 (com a ausência notável dos recursos chamados “assertion” e “trigger” — ver Capítulo 18) além de certas extensões sugeridas pela experiência dos primeiros usuários [4.10]. 
4.10 Donald D. Chamberlin: “A Summary of User Experience with the SQL Data Sublanguage”, Proc. Int. Conf. on Databases, Aberdeen, Escócia (julho de 1980). Também disponível como IBM Research Report RJ2767 (abril de 1980). 
Descreve a experiência dos primeiros usuários com o System R e propõe algumas extensões para a linguagem SQL à luz dessa experiência. Algumas dessas extensões — EXISTS, LIKE, PREPARE e EXECUTE 
— foram de fato implementadas na versão final do System R. Nota: consulte o Capítulo 7 e o Apêndice A para ver uma descrição de EXISTS e LIKE, respectivamente. 
4.11 Donald D. Chamberlin et ai.: “Support for Repetitive Transactions and Ad Hoc Queries in System R”, ACM TODS 6, Número 1 (março de 1981). 
Apresenta algumas medidas de desempenhodo System R, tanto nos ambientes de consulta ad hoc quanto de “transação condensada” (canned transaction). (Uma “transação condensada” é uma aplicação simples 
88 que tem acesso apenas a uma pequena parte do banco de dados e é compilada antes do momento da exe 
cução. Ela corresponde ao que chamamos requisição planejada no Capítulo 2, Seção 2.8.) As medições foram feitas em um IBM System 370 Model 158, executando o System R sob o sistema operacional VM. Elas são descritas como “preliminares”; porém, com essa advertência, o artigo mostra entre outras coisas que (a) a compilação é quase sempre superior à interpretação, mesmo no caso de consultas ad hoc, e (b) um sistema como o System R é capaz de processar diversas transações condensadas por segundo, desde que existam índices apropriados no banco de dados. 
O artigo é notável porque foi um dos primeiros a negar a reivindicação, ouvida freqüentemente na época, de que “os sistemas relacionais nunca terão bom desempenho”. E claro que, desde que esse trabalho foi publicado pela primeira vez, produtos relacionais comerciais alcançaram taxas de transações na casa de centenas e até milhares de transações por segundo. 
4.12 Donald D. Chamberlin eta!.: “A History and Evaluation of System R”, CACM 24, Número 10 (outubro de 
1981). 
Descreve as três principais fases do projeto do System R (protótipo preliminar, protótipo multiusuário, avaliação) com ênfase nas tecnologias de compilação e otimização nas quais o System R foi o pioneiro. Há alguma superposição entre esse artigo e a referência [4.131. 
4.13 Donald D. Chamberlin, Arthur M. Gilbert e Robert A. Yost: “A History of System R and SQL/Data System”, Proc. 7th Int. Conf. on Very Large Data Bases, Cannes, França (setembro de 1981). 
Discute as lições aprendidas a partir do protótipo do System R e descreve a evolução desse protótipo até chegar ao primeiro produto da família de produtos DB2 da IBM, o SQL/DS (mais tarde renomeado “DB2 para VM e VSE”). 
4.14 C. J. Date: “A Critique of the SQL Database Language”, ACM SIGMOD Record 14, Número 3 (novembro de 1984). Republicado em Relational Database: Selected Writings. Reading, Mass.: Addison-Wesley (1986). 
Como observamos no corpo do capítulo, a SQL não é perfeita. Esse artigo apresenta uma análise crítica de um bom número das principais deficiências da linguagem (principalmente sob o ponto de vista das linguagens formais de computador em geral, em vez de linguagens de bancos de dados especificamente). Nota: certas críticas desse artigo não se aplicam à SQL/92. 
4.15 C. J. Date: “What’s Wrong with SQL?”, em Relationa! Database Writings 1985 — 1989. Reading, Mass.: 
Addison-Wesley (1990). 
Descreve algumas deficiências adicionais da SQL, além daquelas identificadas na referência [4.14], sob os títulos “What’s Wrong with SQL per se”, “What’s Wrong with the SQL Standard” e “Application Portability”. Nota: novamente, certas críticas desse artigo não se aplicam à SQL/92. 
4.16 C. J. Date: “SQL Dos and Don’ts”, em Relational Database Writings 1985 — 1989. Reading, Mass.: Addison-Wesley (1990). 
Esse artigo oferece alguns conselhos práticos sobre como usar a SQL de modo a (a) evitar algumas armadilhas potenciais que surgem dos problemas discutidos nas referências [4.14-4.15] e [4.181 e (b) obter os maiores benefícios possíveis em termos de produtividade, portabilidade, conectividade e assim por diante. 
4.17 C. J. Date: “How We Missed the Relational Boat”, em RelationalDatabase Writings 1991 — 1994. Reading, Mass.: Addison-Wesley (1995). 
Um resumo sucinto das deficiências da SQL relacionadas com seu suporte (ou com a falta dele) para os aspectos estruturais, de integridade e manipulativos do modelo relaciona!. 
4.18 C. J. Date: “Grievous Bodily Harm” (em duas partes), DBP&D 11, NúmeroS (maio de 1998) e 11, Número 
6 (junho de 1998); “Fifty Ways to Quote Your Query”, no Web site DBP&D, em www.dbpd.com (julho de 
1998). 
A SQL é uma linguagem extremamente redundante, no sentido de que tudo, exceto as consultas mais triviais, pode ser expresso de muitas maneiras diferentes. Esses artigos ilustram esse ponto e discutem algumas de suas implicações. Em particular, eles mostram que a cláusula GROUP BY, a cláusula HAVING e as variáveis de intervalos, poderiam ser todas descartadas da linguagem sem nenhuma perda efetiva de funcionalidade (e o mesmo também é verdadeiro no caso da construção “IN subconsulta”). Nota: todas essas construções de SQL são explicadas no Capítulo 7 (Seção 7.7) e/ou no Apêndice A. 
89 
4.19 C. J. Date e Hugh Darwen: A Guide to the SQL Standard (4 edição). Reading, Mass.: Addison-Wesley (1997). 
Um tutorial completo sobre SQL/92, incluindo CLI e PSM. Em particular, o livro contém um apêndice, o Apêndice D, que documenta “muitos aspectos do padrão que parecem estar definidos de modo inadequado, ou mesmo incorretamente, neste momento”. Nota: as referências [4.4J e [4.271 também são tutoriais de SQL/92. 
4.20 C. J. Date e Colin J. White: A Guide to DB2 (4 edição). Reading, Mass.: Addison-Wesley (1993). 
Fornece uma visão extensa e completa do produto DB2 original da IBM (como ele era em 1993) e alguns de seus produtos complementares. O DB2, como o SQLIDS [4.131, se baseava no System R. 
4.21 Neal Fishman: “SQL du Jour”, DBP&D 10, Número 10 (outubro 1997). 
Uma pesquisa desanimadora de algumas incompatibilidades encontradas entre produtos de SQL reconhecidos por todos como tendo “suporte para o padrão SQL”. 
4.22 International Organization for Standardization (ISO): Database Language SQL, documento ISO/IEC 
9075:1992. Também disponível como o documento ANSI (American National Standards Institute) ANSI X3. 135-1992. 
A definição da SQL/92 original do ISO/ANSI (conhecida como ISO/IEC 9075, ou às vezes apenas ISO 9075). O documento original de uma única parte foi desde então expandido em uma série de partes separadas, sob o título geral Information Technology — Database Languages — SQL. Na época em que este livro era escrito, as seguintes partes haviam sido definidas (embora certamente não estejam concluídas): 
Parte 1: Arcabouço geral (SQL/Framework). 
Parte 2: Fundamentos (SQL/Foundation). 
Parte 3: Interface de nível de chamada (SQL/CLI). 
Parte 4: Módulos armazenados persistentes (SQL/PSM). 
Parte 5: Acoplamentos da linguagem hospedeira (SQL/Bindings). 
Parte 6: Especialização em XA (SQL/Transaction). 
Parte 7: Temporal (SQL/Temporal). 
Parte 8: Não existe nenhuma Parte 8. 
Parte 9: Gerência de dados externos (SQL/MED). 
Parte 10: Acoplamentos de linguagem objeto (SQL/OLB). 
As propostas da SQL3 que esperamos que sejam ratificadas em 1999 pertencem logicamente às Partes 1, 2, 4 e 5. Esboços de trabalho que descrevem essas propostas podem ser encontrados na Internet em ftp://jeriy. ece. umassd. edu/isowg3/dbl/BASEdocs/public. 
Nota: vale a pena mencionar que, embora a SQL seja amplamente reconhecida como o padrão internacional de bancos de dados “relacionais”, o documento padrão não se descreve como tal; na verdade, ele jamais utiliza o termo “relação”! (A propósito, conforme mencionamos em uma nota de rodapé antiga, o documento também não menciona em momento algum a expressão “banco de dados”.) 
4.23 International Organization for Standardization (ISO): Information Technology — Database Languages — SQL — Technical Corrigendum 2. Documento ISO/IEC 9075: 1992/Cor.2: 1996(E). 
Contém um grande número de revisões e correções para a versão original da referência [4.22]. Infelizmente, essas revisões e correções não corrigem quase nenhum dos problemas identificados na referência [4.19]. 
4.24 Raymond A. Lorie e Jean-Jacques Daudenarde: SQL and Its Applications. Englewood Cliffs, N.J.: Prentice-HaIl (1991). 
Um livro prático de SQL (quase metade do livro consiste em uma série detalhada de estudos de casos envolvendo aplicações realistas). 
4.25 Raymond A. Lorie e J. F. Nilsson: “An Access Specification Language for a Relational Data Base System”, 
90 IBMJ. R&D. 23, Número 3 (maio de 1979). 
Oferece mais detalhessobre um determinado aspecto do mecanismo de compilação do Sistema R [4.11, 4.25—4.26]. Para qualquer instrução de SQL dada, o otimizador do Sistema R gera um programa em uma linguagem interna chamada ASL (Access Specification Language). Essa linguagem serve como interface entre o otimizador e o gerador de código. (O gerador de código, como seu nome sugere, converte um programa ASL em código de máquina.) A ASL consiste em operadores como “scan” e “insert” sobre objetos como índices e arquivos armazenados. O propósito da ASL era tornar o processo de tradução global mais gerenciável, decompondo-o em uma série de subprocessos bem definidos. 
4.26 Raymond A. Lorie e Bradford W. Wade: “The Compilation of a High-Level Data Language”, IBM Research Report RJ2598 (agosto de 1979). 
O Sistema R foi o pioneiro em um esquema para compilar consultas antes do momento da execução, e 
depois recompilar automaticamente essas consultas se a estrutura física do banco de dados tivesse sofrido 
alterações significativas nesse ínterim. Esse ensaio descreve com certos detalhes o mecanismo de compilação e recompilação do Sistema R, sem contudo entrar em questões relacionadas com a otimização (ver 
a referência [17.34] para obter informações sobre esse último tópico). 
4.27 Jim Melton e Alan R. Simon: Understanding the New SQL: A Complete Guide. San Mateo, Calif.: Morgan Kaufmann (1993). 
Um tutorial sobre a SQL/92 (como foi originalmente definida). Melton foi o editor da especificação original da SQL/92 [4.22]. 
4.28 Phyllis Reisner, Raymond F. Boyce e Donald D. Chamberlin: “Human Factors Evaluation of Two Data Base Query Languages: SQUARE and SEQUEL”, Proc. NCC 44. Anaheim, Calif. Montvale, N.J.: AFIPS Press (maio de 1975). 
A predecessora da SQL, chamada SEQUEL [4.8], se baseava em uma linguagem anterior, denominada SQUARE. Na verdade, as duas linguagens eram fundamentalmente idênticas, mas SQUARE usava uma sintaxe bastante matemática, enquanto SEQUEL se baseava em palavras-chave em inglês, como SELECT, FROM, WHERE etc. Esse ensaio relata uma série de experimentos sobre a facilidade de uso das duas linguagens, com o emprego de alunos da escola superior como participantes. Diversas revisões foram feitas em SEQUEL como resultado desse trabalho [4.9]. 
4.29 David Rozenshtein, Anatoly Abramovich e Eugene Birger: Optimizing Transact-SQL: Advanced Programming Techniques. Fremont. Calif.: SQL Forum Press (1995). 
A Transact-SQL é o dialeto de SQL admitido pelos produtos Sybase e SQL Server. Esse livro apresenta uma série de técnicas de programação para Transact-SQL, baseadas no uso de funções características (definidas pelos autores como “dispositivos que permitem aos programadores codificarem a lógica condicional como.., expressões dentro de cláusulas SELECT, WHERE, GROUP BY e SET”). Embora expressas especificamente em termos de Transact-SQL, as idéias têm na realidade uma aplicação mais ampla. Nota: talvez devamos acrescentar que a “otimização” mencionada no título do livro se refere não ao componente otimizador do SGBD, mas sim à “otimização” que pode ser feita manualmente pelos próprios usuários. 
RESPOSTAS A EXERCÍCIOS SELECIONADOS 
4.1 CREATE TABLE F 
( F# CHAR(5), 
FNOME CHAR(20), 
STATUS NUMERIC(5), 
CIDADE CHAR(15), 
PRIMARY KEY ( F# ) ) 
CREATE TABLE P 
( P# CHAR(6), 
PNOME CHAR(20), 
COR CHAR(6), 
PESO NUMERIC(5,1), 
CIDADE CHAR(15), 
PRIMARY KEY ( P# ) ) ; 91 
CREATE TABLE J 
( J# CHAR(4), 
JNOME CHAR(20), 
CIDADE CI-IAR(15), 
PRIMARY KEY ( J# ) ) ; 
CREATE TABLE FPJ 
( F# CHAR(5), 
P# CHAR(6), 
J# CHAR(4), 
QDE NUMERIC(9), 
PRIMARY KEY ( F#, P#, J# ), 
FOREIGN KEY ( F# ) REFERENCES F, 
FOREIGN KEY ( P# ) REFERENCES P, 
FOREIGN KEY ( J# ) REFERENCES J ) ; 
4.4 a. INSERT INTO F ( F#, FNOME, CIDADE 
VALUES ( ‘FiO’, ‘Smith’, ‘Nova York’ 
Aqui STATUS é definido como o valor default aplicável. 
b. UPDATE P 
SET COR = ‘Alaranjado’ 
WHERE COR = ‘Vermelho’ 
c. DELETE 
FROM J 
WHERE J# NOT IN 
( SELECT J# 
FROM FPJ ) 
Observe a subconsulta aninhada e o operador IN (na realidade, o operador IN negado) na solução da parte c., nesse caso. Consulte o Capítulo 7 para ver uma explicação adicional. 
4.5 Observe que poderiam existir alguns fornecedores que não fornecessem absolutamente nenhum projeto; a solução a seguir lida de modo satisfatório com esses fornecedores (exatamente de que modo?). Primeiro, definimos dois cursores, CF e CJ, da seguinte forma: 
EXEC SQL DECLARE CF CURSOR FOR 
SELECT F.F#, F.FNOME, F.STATUS, F.CIDADE 
FROM F 
ORDER BY F# 
EXEC SQL DECLARE CJ CURSOR FOR 
SELECT J.J#, J.JNOME, J.CIDADE 
FROM J 
WHERE J.J# IN 
( SELECT FPJ.J# 
FROM FPJ 
WHERE FPJ.F# = :CFF# ) 
ORDER BY J# 
(Note uma vez mais a subconsulta aninhada e o operador IN.) 
Quando o cursor CJ for aberto, a variável hospedeira CF_F# conterá um valor de número de fornecedor, obtido por meio do cursor CF. A lógica procedural é essencialmente a seguinte: 
EXEC SQL OPEN CF 
DO para todas as linhas F acessíveis via CF 
EXEC SQL FETCH CF INTO :CFF#, :CF_FN, :CFFT, :CF_FC ; 
imprimir CFF#, CFFN. CFFT, CF_FC 
92 EXEC SQL OPEN CJ ; 
DO para todas as linhas J acessíveis via CJ 
EXEC SQL FETCH CJ INTO :CJJ#, :CJJN, :CJJC ; 
imprimir CJJ#, CJJN, CJJC 
END DO ; 
EXEC SQL CLOSE CJ ; 
END DO ; 
EXEC SQL CLOSE CF ; 
4.6 Esse é um bom exemplo de um problema com o qual a SQL em sua forma corrente não lida muito bem. A dificuldade básica é a seguinte: precisamos “explodir” a peça dada até n níveis, onde o valor de n é desconhecido no momento em que se escreve o programa. Um modo comparativamente direto de executar tal “explosão” de nível n — se ele fosse possível — seria através de um programa recursivo, no qual cada chamada recursiva criaria um novo cursor, como este: 
CALL RECURSÃO ( DADOP# ) 
RECURSÃO: PROC ( SUPER_P# ) RECURSIVE ; 
DCL SUPERP# 
DCL INFERP# ... 
EXEC SQL DECLARE C reabrível” CURSOR FOR 
SELECT SECP# 
FROM ESTRUTURA_PEÇA 
WHERE PRINCP# = :SUPER_P# ; 
imprimir SUPERP# 
EXEC SQL OPEN C ; 
DO para todas as linhas de ESTRUTURA_PEÇA acessíveis via C 
EXEC SQL FETCH C INTO :INFERP# ; 
CALL RECURSÃO ( INFERP# ) 
END DO 
EXEC SQL CLOSE C 
END PROC ; 
Nesse caso, fizemos a suposição de que a especificação (fictícia) “reabrível” sobre DECLARE CURSOR significa que é válido OPEN (abrir) esse cursor mesmo que ele já esteja aberto, e que o efeito de tal operação OPEN é o de criar uma nova instância do cursor para a expressão de tabela especificada (usando-se os valores atuais de quaisquer variáveis hospedeira referenciadas nessa expressão). Fizemos ainda a suposição de que as referências a tal cursor em FETCH (etc.) são referências à instância “atual”, e que CLOSE (fechar) destrói essa instância e restabelece a instância anterior como “atual”. Em outras palavras, supusemos que um cursor “reabrível” forma uma pilha, com OPEN e CLOSE servindo como operadores de inserção “push” e obtenção “pop” para essa pilha. 
Infelizmente, essas suposições são hoje puramente hipotéticas. Não há nada semelhante a um cursor “reabrível” em SQL atualmente (na verdade, uma tentativa de usar OPEN para abrir um cursor já aberto irá falhar). O código anterior é inválido. Porém, o exemplo torna claro que “cursores reabríveis” seriam uma extensão muito desejável da SQL atual. 
Como o procedimento anterior não funciona, damos aqui um esboço de uma abordagem possível (embora muito ineficiente) que funciona. 
CALL RECURSÃO ( DADOP# ) ; 
RECURSÃO: PROC ( SUPER_P# ) RECURSIVE 
DCL SUPERP# 
DCL INFERP# .. . ; INITIAL ( ) ; 
EXEC SQL DECLARE C CURSOR FOR 
SELECT SECP# 
FROM ESTRUTURA_PEÇA 
WHERE PRINCP# = :SUPERP# 
AND SECP# > :INFERP# 
ORDER BY SECP# ; 
93 
imprimir SIJPERP# 
DO para sempre” 
EXEC SQL OPEN C 
EXEC SQL FETCH C INTO :INFERP# 
EXEC SQL CLOSE C 
IF nenhum “P# inferior recuperado THEN RETURN ; END IF 
IF “P# inferior’ recuperado THEN 
CALL RECURSÃO ( INFERP# ) ; END IF 
END DO 
END PROC ; 
Observe nessa solução que o mesmo cursor é usado em cada chamada deRECURSÃO. (Em contraste, novas instâncias de SUPER_P# e INFER_P# são criadas dinamicamente cada vez que RECURSAO é 
invocada; essas instâncias são destruídas ao se concluir essa chamada.) Devido a esse fato, temos de usar 
um artificio — 
AND SEC P# > :INFERP# ORDER BY SECP# 
— de modo que, a cada invocação de RECURSÃO, possamos ignorar todos os componentes imediatos (INFERP#s) do SUPER P# atual que já tenham sido processados. 
Consulte (a) as referências [4.5J e [4.71 para ver uma descrição de algumas abordagens alternativas no estilo de SQL para esse problema, (b) o Capítulo 6 (final da Seção 6.7) para ver uma descrição de um operador relacional pertinente chamado fecho transitivo, e (c) Apêndice B para ter uma visão geral de alguns recursos relevantes de SQL3. 
94

Continue navegando