(Structured Query Language) I DDL (Definição de Esquemas Relacionais)... 2 I.2 Domínios... 2 I.3 Criação de Tabelas... 2 I.4 Triggers... 4 II DML Linguagem para manipulação de dados... 5 II.2 Comando SELECT... 5 II.3 Comando UPDATE... 9 II.4 Comando DELETE... 9 II.5 Comando INSERT...10
(Structured Query Language) Norma ANSI criada em 1986 (revista em 1989 e 1992). A linguagem tem duas vertentes: DDL (Data Definition Language) e DML (data Manipulation Language). Na vertente DDL o possui um conjunto de comandos para criação e alteração de tabelas, chaves estrangeiras, regras de integridade referencial e views. Através dos comandos DML é possível efectuar interrogações a uma base de dados, bem como alterar, anular ou inserir registos em tabelas. I DDL (Definição de Esquemas Relacionais) I.2 Domínios Em é possível especificar o domínio (tipo de dados) de um atributo (Integer, Smallint, Decimal, Char, VarChar, Date, Time, Etc.). Através da cláusula DOMAIN é possível definir um domínio genérico ao qual podem ser atribuídos vários atributos. O seguinte comando define o domínio morada: CREATE DOMAIN dm_morada VARCHAR(100) I.3 Criação de Tabelas O comando para criar tabelas é CREATE TABLE, cuja sintaxe é a seguinte: CREATE TABLE nome databela ( definição das colunas, restrições de integridade) Na definição das colunas é necessário indicar o domínio e a obrigatoriedade (NULL), podendo-se opcional definir um valor por omissão (DEFAULT). Caso não seja referido se o atributo é ou não aobrigatório, assume-se que não é. Nas restrições de integridade pode-se definir a chave primária (PRIMARY KEY), cahves candadatas (UNIQUE), restrições sobre valores de colunas (CHECK), Chaves estrangeiras (FOREIGN KEY) e as restrições de integridade associadas (REFERENCES ON UPDATE, REFERENCES ON DELETE). Através da cláusula CONSTRAINT é Pedro Ramos DCTI/ISCTE 2
possível, mas não obrigatório, atribuir nomes às restrições (esses nomes apenas são uteis em termos de clareza de leitura, nomeadamente nas mensagens de erro retornadas pelo motor de base de dados). Os seguintes comandos criam quatro tabelas que exemplifica as várias cláusulas referidas. CREATE TABLE Factura ( num_factura INTEGER NOT NULL, data DATE NOT NULL, valor DECIMAL(10,2) NOT NULL, cod_cliente INTEGER NOT NULL, CONSTRAINT prim_key PRIMARY KEY (num_factura), CONSTRAINT for_key_cliente FOREIGN KEY (cod_cliente) REFERENCES Cliente (cod_cliente) ON UPDATE CASCADE ON DELETE RESTRICT) CREATE TABLE Cliente ( cod_cliente INTEGER NOT NULL, bi INTEGER NOT NULL, nome VARCHAR(100), morada dm_morada, CONSTRAINT prim_key PRIMARY KEY (cod_cliente), CONSTRAINT cand_key UNIQUE (bi)) CREATE TABLE Item ( num_factura INTEGER NOT NULL, num_item INTEGER NOT NULL, quantidade INTEGER NOT NULL, valor DECIMAL (4,2) NOT NULL, cod_produto INTEGER NOT NULL, CONSTRAINT prim_key PRIMARY KEY (num_factura, num_item), CONSTRAINT for_key_factura FOREIGN KEY (num_factura) REFERENCES Factura (num_factura) ON UPDATE CASCADE ON DELETE CASCADE, CONSTRAINT for_key_produto FOREIGN KEY (cod_produto) REFERENCES Produto (cod_produto) ON UPDATE CASCADE ON DELETE RESTRICT, CHECK (quantidade > 0)) CREATE TABLE Produto ( cod_produto INTEGER NOT NULL, tipo CHAR(2) DEFAULT MP NOT NULL, designação VARCHAR(100), CONSTRAINT prim_key PRIMARY KEY (cod_produto), CHECK (tipo IN ( MP, PA ))) Notas: (i) (ii) (iii) Para além das opções CASCADE e RESTRICT (chaves estrangeiras) existe a opção SET NULL; A cláusula CONSTRAINT (no Sybase Anywhere) não se aplica à cláusula CHECK; As cláusulas PRIMARY KEY (sem CONSTRAINT) e CHECK (qualdo este se aplica apenas a uma coluna e não a uma expressão que envolva mais que uma coluna) podem ser colocadas na mesma linha da definição da coluna. Pedro Ramos DCTI/ISCTE 3
Para apagar uma tabela utiliza-se o comando DROP TABLE DROP TABLE CLIENTE Para alterar uma tabela (por exemplo, acrescentar uma coluna ou apagar uma coluna), utiliza-se o comando ALTER TABLE ALTER TABLE cliente ADD COLUMN telefone VARCHAR (10) DROP COLUMN bi Nota: É conveniente ter um ficheiro com a definição completa da base de dados. Esse ficheiro pode ser executado sempre que seja necessário reconstruir a base de dados. O uso sistemático dos comandos ALTER e DROP TABLE pode dificultar a reconstrução da base de dados. I.4 Triggers Os triggers são procedimentos armazenados junto da base de dados que são associados a eventos que ocorrem nas tabelas. Através dos triggers o motor de base de dados reage automaticamente quando esses eventos (alterações dos dados nas tabelas) ocorrem, a forma como reagem é definida pelo procedimento associado ao trigger. Note-se que um trigger apenas pode estar associado a um evento de uma tabela. Os eventos aos quais podem se associar os triggers são Insert, Update, Delete e Update Of, sendo que para um deles é necessário discriminar se o evento ocorre antes ou depois da operação terminar. Os eventos Insert, Update e Delete ocorrem ao nível do registo completo, enquanto que o evento Update Of ocorre ao nível de um campo da tabela (é necessário indicar qual o atributo no momento da definição do trigger). Os triggers podem ainda ser row-level ou statement-level. Os triggers row-level ocorrem após cada linha da tabela ser alterada (anulada ou inserida). Os triggers statement-level ocorrem após uma operação sobre a tabela ser concluída (por exemplo, após um conjunto de registos ser inserido). O procedimento associado ao trigger obedece a uma sintaxe pré definida que não é abordada nestas folhas. A título de exemplo, considere-se o seguinte trigger (row-level) que é activado sempre que se insere uma matéria prima na tabela de produtos (insere um registo na tabela de matérias primas): create trigger "dba".materiaprima after insert on "DBA".Produto referencing new as new_produto for each row when(new_produto.tipo='mp') begin insert into MateriaPrima(cod_produto) values(new_produto.cod_produto) end Pedro Ramos DCTI/ISCTE 4
II DML Linguagem para manipulação de dados A linguagem DML implementa um subconjunto das operações da Álgebra Relacional, (nomeadamente o Produto Cartesiano, a União, a Selecção e a Projecção) e é composta por quatro comandos: SELECT, UPDATE, DELETE e INSERT, sendo o comando SELECT (permite a selecção de registos) o mais complexo e mais importante. II.2 Comando SELECT Um comando típico para selecção de linhas obedece à seguinte estrutura ( em que a cláusula SELECT corresponde à projecção, a cláusula FROM ao produto cartesiano e a cláusula WHERE à selecção): SELECT campos a seleccionar FROM tabelas onde constam os campos indicados em Select WHERE expressão lógica que indica quais as linhas que pretendemos seleccionar ORDER BY campo pelo qual a listagem virá ordenada; Por exemplo, para listar o nome e morada de uma tabela de clientes, o comando será: SELECT Nome, Morada FROM Cliente. Caso queiramos apenas os clientes cujo código postal seja 1300 (e queira que a lista venha ordenada por nome): SELECT Nome, Morada FROM Cliente WHERE Cod_Postal = 1300 ORDER BY Nome. É importante notar que qualquer comando SELECT devolve uma tabela (um conjunto de colunas e linhas). Sempre que ao longo deste texto referir-mos a palavra tabela, ela deve ser interpretada no sentido mais lato: uma tabela original (definida no esquema relacional) ou um comando SELECT. Cláusula SELECT Qualquer expressão sintacticamente válida pode ser argumento da cláusula SELECT. Por exemplo, os dois seguintes comandos são válidos: (i) SELECT Produto, Quantidade * Preço FROM Item (devolve duas colunas em que a segunda corresponde ao produto das colunas quantidade e preço); (ii) SELECT teste FROM Item (se a tabela item tiver 20 itens, o comando devolve 20 vezes a palavra teste). Pedro Ramos DCTI/ISCTE 5
Podem ser atribuídos aliases (sinónimos) às colunas. Por exemplo o comando anterior poderia ser escrito da seguinte forma (permite dar um nome Total - à segunda coluna devolvida): SELECT Produto, Quantidade * Preço AS Total FROM Item Caso pretendamos visualizar todos os campos de uma tabela, como alternativa a enumera-los todos, pode-se usar a constante *: SELECT * FROM Item. Caso pretendamos eliminar duplicados na listagem obtida, utiliza-se a cláusula DISTINCT (elimina linhas duplicadas) SELECT DISTINCT CodPostal FROM Aluno (devolve os códigos postais existentes). Caso se pretenda listar dois atributos com o mesmo nome (correspondentes a duas tabelas referidas na cláusula FROM) é necessário preceder o nome do campo pelo nome da tabela de onde ele é originário. Cláusula FROM Na cláusula FROM indicam-se os nomes das tabelas envolvidas na interrogação, separadas por vírgulas. Quando existe mais que uma tabela o executa automaticamente um produto cartesiano entre as tabelas. Por exemplo, o seguinte comando executa um produto cartesiano entre as tabelas Cliente e Cod_Postal, devolvendo todos os campos (das duas tabelas): SELECT * FROM Cliente, Cod_Postal. Caso queiramos obter um JOIN (ver secção II.1) é necessário explicitar a forma como o pretendemos obter, por exemplo: SELECT * FROM Cliente INNER JOIN Cod_Postal SELECT * FROM Cliente LEFT OUTER JOIN Cod_Postal SELECT * FROM Cliente, Cod_Postal WHERE Cliente.CodPostal = CodPostal.CodPostal (equivalente a um INNER JOIN) Á semelhança dos sinónimos dos atributos, é possível atribuir aliases às tabelas (os sinónimos nas tabelas são relevantes nas subquerys, analisadas mais adiante): Select * From Cliente AS Cliente_Empresa Cláusula WHERE Na cláusula WHERE pode constar qualquer expressão lógica. A expressão é avaliada linha a linha, isto é, para cada linha o avalia o valor da expressão, caso seja verdadeira devolve a linha. Os seguintes comandos são exemplos sintacticamente correctos: SELECT * FROM Cliente Where CodPostal > 1000 AND CodPostal < 2000 SELECT * FROM Cliente Where (CodPostal > 1000 AND CodPostal < 2000) OR CodPostal = 3000 Pedro Ramos DCTI/ISCTE 6
Select * FROM CodPostal WHERE 1 = 1 (devolve todos os registos) Os principais operadores utilizados na cláusula WHERE são: =, <, >, >=, <=, <>, AND, OR, NOT, IN, LIKE, BETWEEN e ISNULL. O operador IN é verdadeiro quando um elemento faz parte de um conjunto. O operador permite a utilização de wildcards. O operador ISNULL permite lidar com valores NULL. Alguns exemplos: SELECT * FROM CLIENTE WHERE CodPostal BETWEEN 1000,2000 SELECT * FROM CLIENTE WHERE Nome LIKE João% (todos os clientes começados por João SELECT * FROM Cliente WHERE Nacionalidade IN ( Portugal, Brasil ) (todos os clientes portugueses ou brasileiros) SELECT * FROM Cliente WHERE Nacionalidade NOT IN ( Portugal, Brasil ) (todos os clientes excepto os portugueses e brasileiros) SELECT * FROM Cliente WHERE Nacionalidade IS NOT NULL (todos os clientes com nacionalidade conhecida) Funções de Agregação e Cláusulas GROUP BY e HAVING Recorrendo apenas às cláusulas anteriores não é possível, por exemplo, efectuar certas operações estatísticas (somatórios, médias, etc.). Tal acontece porque as operações de agregação (que envolvem vários registos) não poderem ser calculadas linha a linha. Por exemplo, o comando para listar os códigos postais associados a mais do que dois clientes não pode ser efectuado tal como de seguida se apresenta: SELECT CodPostal FROM Cliente WHERE COUNT(CodPostal) > 2 O comando é incorrecto porque a cláusula WHERE é testada linha a linha e, numa linha não é possível obter o total de códigos postais. As cláusulas GROUP BY e HAVING permitem manipular valores agregados. A cláusula GROUP BY permite a definição de grupos. A cláusula HAVING é equivalente à cláusula WHERE só que o seu argumento são expressões lógicas relativas aos agrupamentos criados pela cláusula GROUP BY. O exemplo anterior encontra-se bem formulado com o seguinte comando: SELECT CodPostal FROM Cliente GROUP BY CodPostal HAVING COUNT(CodPostal) > 2 A cláusula GROUP BY agrupa os clientes por código postal e a cláusula HAVING selecciona os grupos cujo número de elementos é superior a dois. O seguinte Pedro Ramos DCTI/ISCTE 7
comando lista, para cada código postal, o número de clientes que a ele estão associados: SELECT CodPostal, COUNT(CodPostal) FROM Cliente GROUP BY CodPostal Sempre que existe uma função de agregação na cláusula SELECT, todos os restantes atributos da cláusula têm que estar incluídos na cláusula GROUP BY. O comando que de seguida se apresenta retorna o maior bilhete de identidade existente: SELECT MAX(Bi) FROM Cliente Caso pretendêssemos visualizar o nome desse cliente, não poderíamos simplesmente acrescentar o atributo nome à cláusula SELECT. Pela regra anteriormente referida, teríamos que considerar a cláusula GROUP BY: SELECT MAX(Bi), NOME FROM Cliente GROUP BY Nome. No entanto, o resultado do comando seria a listagem de todos os nomes com a indicação do BI associado a cada nome. Mais adiante apresenta-se a resolução desta interrogação. Para além das funções COUNT e MAX, existem outras, tais como SUM, AVG e MIN. Apenas a função COUNT não necessita de argumento: o primeiro comando retorna o total de registos de clientes enquanto o segundo devolve o total de clientes com o código postal conhecido. (i) (ii) SELECT COUNT(*) FROM Cliente SELECT COUNT(CodPostal) FROM Cliente Note-se que o segundo comando é equivalente ao seguinte: SELECT COUNT(*) FROM Cliente WHERE CodPostal IS NOT NULL SubQuerys Uma subquery é um comando SELECT dentro de um comando SELECT. Muitas interrogações apenas podem ser resolvidas através de subquerys. Um comando SELECT normalmente liga-se a outro através da cláusula WHERE. Os operadores IN e EXISTS são normalmente utilizadas nas subquerys. O operador IN devolve verdade quando um elemento pertence a um conjunto, e o operador EXISTS devolve verdade caso a subquery retorne pelo menos uma linha. Os dois comandos abaixo apresentados (equivalentes) devolvem os nomes que estão associados a pelo menos duas pessoas (dois BI s) (sem a cláusula DISTINCT o comando retornaria os nomes duplicados; os sinónimos das tabelas são necessários para evitar ambiguidades na condição WHERE da subquery): SELECT DISTINCT(Nome) FROM Cliente as Cliente1 WHERE NOME IN (SELECT NOME FROM Cliente as Cliente2 WHERE Cliente1.bi <> Cliente2.bi) Pedro Ramos DCTI/ISCTE 8
SELECT DISTINCT(Nome) FROM Cliente as Cliente1 WHERE EXISTS (SELECT * FROM Cliente as Cliente2 WHERE Cliente1.bi <> Cliente2.bi AND Cliente1.Nome = Cliente2.Nome) Os operadores ALL (todos) e ANY (pelo menos um) também são frequentes nas subquerys. O comando para retornar o maior bilhete de identidade (e nome associado) existente é: SELECT Nome, BI FROM Cliente WHERE BI >= ALL (SELECT BI FROM Cliente). Caso pretendêssemos um bilhete de identidade que não fosse o menor, o comando seria: SELECT Nome, BI FROM Cliente WHERE BI > ANY (SELECT BI FROM Cliente). As subquerys também podem ser colocadas na cláusula SELECT. O seguinte exemplo devolve, para cada cliente, o total de facturas associadas: SELECT Nome, (SELECT COUNT(*) FROM Factura WHERE Factura.BI = Cliente.BI) FROM Cliente Uniões A união de comandos SELECT é efectuada através do operador UNION. O seguinte comando devolve os nomes dos clientes e fornecedores: SELECT Nome FROM Cliente UNION SELECT Nome FROM Fornecedor. II.3 Comando UPDATE Um comando UPDATE para alteração de linhas obedece à seguinte estrutura: UPDATE tabela a alterar SET coluna a alterar = expressão WHERE expressão lógica que indica quais as linhas que pretendemos alterar O seguinte comando transforma os códigos postais 1200 em 1500: UPDATE Cliente SET CodPostal = 1500 WHERE CodPostal = 1200 II.4 Comando DELETE Um comando DELETE para anulação de linhas obedece à seguinte estrutura: DELETE FROM tabela a anular WHERE expressão lógica que indica quais as linhas que pretendemos alterar O seguinte comando apaga os códigos postais 1200 DELETE FROM Cliente WHERE CodPostal = 1200 Pedro Ramos DCTI/ISCTE 9
II.5 Comando INSERT Através do comando INSERT podem-se inserir uma linha ou várias linhas em simultâneo. Para inserir uma linha um comando INSERT obedece à seguinte estrutura: INSERT INTO tabela a inserir (colunas onde vão ser inseridos os valores) VALUES (valores a inserir) Para inserir um conjunto de linhas, um comando INSERT obedece à seguinte estrutura: INSERT INTO tabela a inserir (colunas onde vão ser inseridos os valores) SELECT valores a inserir FROM Exemplos INSERT INTO Produto (cod_produto, tipo) VALUES (123456, MP ) INSERT INTO Produto (cod_produto, tipo) SELECT cod_materia, MP FROM Materia_Prima Pedro Ramos DCTI/ISCTE 10