Skip to content

3. Introdução à linguagem SQL

Nesta secção do capítulo, apresentamos os primeiros comandos SQL que permitem criar e utilizar uma única tabela. Em geral, apresentamos uma versão simplificada dos mesmos. A sua sintaxe completa está disponível nos guias de referência do Firebird (ver parágrafo 2.2).

Uma base de dados é utilizada por pessoas com competências diversas:

  • o administrador da base de dados é, geralmente, alguém que domina a linguagem SQL e as bases de dados. É ele quem cria as tabelas, uma vez que esta operação é, normalmente, realizada apenas uma vez. Ao longo do tempo, poderá ter de alterar a sua estrutura. Uma base de dados é um conjunto de tabelas ligadas por relações. É o administrador da base de dados que definirá essas relações. É também ele quem concederá direitos aos diferentes utilizadores da base de dados. Assim, indicará que determinado utilizador tem o direito de visualizar o conteúdo de uma tabela, mas não de a alterar.
  • O utilizador da base de dados é quem dá vida aos dados. De acordo com os direitos concedidos pelo administrador da base de dados, irá adicionar, alterar e eliminar dados nas diferentes tabelas da base. Irá também explorá-los para extrair informações úteis para o bom funcionamento da empresa, da administração, etc.

No parágrafo 2.6, apresentámos o editor SQL da ferramenta [IB-Expert]. É esta ferramenta que vamos utilizar. Recorde-se alguns pontos:

  • O editor SQL acede-se através da opção de menu [Tools/SQL Editor] ou através da tecla [F12]

Image

Surge então uma janela [SQL Editor], na qual podemos introduzir um comando SQL:

Image

A captura de ecrã acima será frequentemente representada pelo texto abaixo:

SQL> select * from BIBLIO

3.1. Os tipos de dados do Firebird

Ao criar uma tabela, é necessário indicar o tipo de dados que uma coluna da tabela pode conter. Apresentamos aqui os tipos de dados mais comuns do Firebird. É importante referir que estes tipos de dados podem variar de um SGBD para outro.

SMALLINT
número inteiro no intervalo [-32768, 32767]: 4
INTEGER
número inteiro no domínio [–2 147 483 648, 2 147 483 647]: -100
NUMERIC(n,m)
DECIMAL(n,m)
número real com n dígitos, dos quais m após a vírgula
NUMERIC(5,2): -100,23, +027,30
FLOAT
número real aproximado com 7 algarismos significativos: 10,4
DOUBLE PRECISION
número real aproximado com 15 algarismos significativos: -100.89
CHAR(N)
CHARACTER(N)
cadeia de N caracteres exatamente. Se a cadeia armazenada tiver menos de N caracteres, é preenchida com espaços.
CHAR(10): «ANGERS » (4 espaços no final)
VARCHAR(N)
CHARACTER VARYING(N)
cadeia com, no máximo, N caracteres
VARCHAR(10): 'ANGERS'
DATE
uma data: '2006-01-09' (formato YYYY-MM-DD)
TIME
uma hora: '16:43:00' (formato HH:MM:SS)
TIMESTAMP
data e hora em simultâneo: '2006-01-09 16:43:00' (formato YYYY-MM-DD HH:MM:SS)

A função CAST() permite converter de um tipo para outro quando necessário. Para converter um valor V declarado como sendo do tipo T1 para o tipo T2, escreve-se: CAST(V,T2). É possível efetuar as seguintes conversões de tipo:

  • número para cadeia de caracteres. Esta alteração de tipo é feita implicitamente e não requer a utilização da função CAST. Assim, a operação 1 + '3' não requer a conversão do caractere '3'. O seu resultado é o número 4.
  • DATE, TIME, TIMESTAMP para cadeias de caracteres e vice-versa. Assim,
  • TIMESTAMP para TIME ou DATE e vice-versa

Numa tabela, uma linha pode ter colunas sem valor. Diz-se que o valor da coluna é a constante NULL. É possível verificar a presença deste valor utilizando os operadores

IS NULL / IS NOT NULL

3.2. Criação de uma tabela

Para descobrir como criar uma tabela, começamos por criar uma no modo [Design] com IBExpert. Para tal, seguimos o método descrito no parágrafo 2.3. Criamos assim a seguinte tabela:

Image

Esta tabela servirá para registar os livros adquiridos por uma biblioteca. O significado dos campos é o seguinte:

Name
Tipo
Restrição
Significado
ID
INTEGER
Primary Key
Identifiant du livre
 TITRE
VARCHAR(30)
NOT NULL UNIQUE
Titre du livre
 AUTEUR
VARCHAR(20)
NOT NULL
Son auteur
 GENRE
VARCHAR(30)
NOT NULL
Son genre (Roman, Poésie, Policier, BD, ..)
 ACHAT
DATE
NOT NULL
Date d'achat du livre
 PRIX
NUMERIC6,2)
NOT NULL
Son prix
 DISPONIBLE
CHAR(1)
NOT NULL
Est-il disponible ? O (oui), N (non)

Esta tabela, que foi criada com a ferramenta IBEXPERT como assistente, poderia ter sido criada diretamente através das ordens SQL. Para conhecer essas ordens, basta consultar o separador [DDL] da tabela:

Image

O código SQL que permitiu criar a tabela [BIBLIO] é o seguinte:

SET SQL DIALECT 3;

SET NAMES ISO8859_1;


CREATE TABLE BIBLIO (
    ID INTEGER NOT NULL,
    TITRE VARCHAR(30) NOT NULL,
    AUTEUR VARCHAR(20) NOT NULL,
   GENRE VARCHAR(30) NOT NULL,
   ACHAT DATE NOT NULL,
   PRIX NUMERIC(6,2) NOT NULL,
   DISPONIBLE  CHAR(1) NOT NULL
);

ALTER TABLE BIBLIO ADD CONSTRAINT UNQ1_BIBLIO UNIQUE (TITRE);
ALTER TABLE BIBLIO ADD CONSTRAINT PK_BIBLIO PRIMARY KEY (ID);
  • linha 1: proprietário Firebird — indica o nível do dialeto SQL utilizado
  • linha 2: proprietário Firebird — indica a família de caracteres utilizada
  • linhas 6 - 14: padrão SQL: cria a tabela BIBLIO, definindo o nome e o tipo de cada uma das suas colunas.
  • linha 16: padrão SQL: cria uma restrição que indica que a coluna TITRE não admite duplicados
  • linha 17: padrão SQL: indica que a coluna [ID] é a chave primária da tabela. Isto significa que duas linhas da tabela não podem ter o mesmo valor para ID. Estamos aqui próximos da restrição [UNIQUE NOT NULL] da coluna [TITRE] e, de facto, a coluna TITRE poderia ter servido como chave primária. A tendência atual é utilizar chaves primárias que não têm significado e que são geradas pelo SGBD.

A sintaxe do comando [CREATE TABLE] é a seguinte:

syntaxe
CREATE TABLE tabela (nom_colonne1 type_colonne1 contrainte_colonne1, nom_colonne2 type_colonne2 contrainte_colonne2, ..., nom_colonnen type_colonnen contrainte_colonnen, outras restrições)
action
cria a tabela table com as colunas indicadas
nom_colonnei
nome da coluna i a criar
type_colonnei
tipo de dados da coluna i:
char(30) numeric(6,2) data timestamp ...
contrainte_colonnei
restrições que os dados da coluna i devem respeitar. Aqui estão algumas delas:
PRIMARY KEY: a coluna é uma chave primária. Isto significa que duas linhas da tabela nunca têm o mesmo valor nesta coluna e, além disso, que é obrigatório preencher um valor nesta coluna. Uma chave primária serve principalmente para identificar uma linha de forma única.
NOT NULL : não são permitidos valores nulos nesta coluna.
UNIQUE : nenhum valor pode aparecer mais do que uma vez na coluna.
CHECK (condição): o valor da coluna deve satisfazer a condição.
autres contraintes
aqui podem ser definidas
- restrições em várias colunas: check(col1>col2)
- restrições de chaves estrangeiras

A tabela [BIBLIO] também poderia ter sido criada com a seguinte ordem SQL:

1
2
3
4
5
6
7
8
9
CREATE TABLE BIBLIO (
    ID INTEGER NOT NULL PRIMARY KEY,
    TITRE VARCHAR(30) NOT NULL UNIQUE,
    AUTEUR VARCHAR(20) NOT NULL,
   GENRE VARCHAR(30) NOT NULL,
   ACHAT DATE NOT NULL,
   PRIX NUMERIC(6,2) NOT NULL,
   DISPONIBLE  CHAR(1) NOT NULL
);

Vamos demonstrar isso. Retomemos esta ordem num editor SQL (F12) para criar uma tabela a que chamaremos [BIBLIO2]:

Image

Após a execução, é necessário validar a transação para ver o resultado na base de dados:

Image

Feito isto, a tabela aparece na base de dados:

Image

Ao clicar duas vezes no seu nome, é possível aceder à sua estrutura:

Image

Confirmamos que esta é, de facto, a definição que criámos para a tabela [BIBLIO2]

3.3. Eliminação de uma tabela

A ordem SQL para eliminar uma tabela é a seguinte:

syntaxe
DROP TABLE tabela
action
Elimina [table]

Para eliminar a tabela [BIBLIO2] que acabámos de criar, executamos agora o seguinte comando SQL:

Image

e validamo-la com [Commit]. A tabela [BIBLIO2] é eliminada:

Image

3.4. Preenchimento de uma tabela

Inserimos uma linha na tabela [BIBLIO] que acabámos de criar:

Image

Validemos a adição da linha através de [Commit] e, em seguida, cliquemos com o botão direito do rato na linha adicionada:

Image

e solicitemos, tal como mostrado acima, a cópia da linha inserida para a área de transferência sob a forma de um comando SQL INSERT. Em seguida, abramos qualquer editor de texto e coloquemos (Colar / Paste) o que acabámos de copiar. Obtemos o seguinte código SQL:

INSERT INTO BIBLIO (ID,TITRE,AUTEUR,GENRE,ACHAT,PRIX,DISPONIBLE) VALUES (1,'Candide','Voltaire','Essai','18-OCT-1985',140,'o');

A sintaxe de um comando de inserção SQL é a seguinte:

syntaxe
insert into table [(colonne1, colonne2, ..)] values (valor1, valor2, ....)
action
adiciona uma linha (valor1, valor2, ..) à tabela table. Estes valores são atribuídos às tabelas colonne1, colonne2, ... caso existam; caso contrário, são atribuídos às colunas da tabela na ordem em que foram definidas.

Para inserir novas linhas na tabela [BIBLIO], devem ser introduzidos os seguintes comandos INSERT no editor SQL. Executaremos e validaremos [Commit] estas ordens uma a uma. Utilizaremos o botão [New Query] para passar para a ordem INSERT seguinte.

1
2
3
4
5
6
7
insert into biblio(id,titre,auteur,genre,achat,prix,disponible) values (2,'Les fleurs du mal','Baudelaire','Poème','01-jan-78',120,'n');
insert into biblio(id,titre,auteur,genre,achat,prix,disponible) values (3,'Tintin au Tibet','Hergé','BD','10-nov-90',70,'o');
insert into biblio(id,titre,auteur,genre,achat,prix,disponible) values (4,'Du côté de chez Swann','Proust','Roman','08-dec-78',200,'o');
insert into biblio(id,titre,auteur,genre,achat,prix,disponible) values (5,'La terre','Zola','roman','12-jun-90',50,'n');
insert into biblio(id,titre,auteur,genre,achat,prix,disponible) values (6,'Madame Bovary','Flaubert','Roman','12-mar-88',130,'o');
insert into biblio(id,titre,auteur,genre,achat,prix,disponible) values (7,'Manhattan transfer','Dos Passos','Roman','30-aug-87',320,'o');
insert into biblio(id,titre,auteur,genre,achat,prix,disponible) values (8,'Tintin en Amérique','Hergé','BD','15-may-91',70,'o');

Após validar as diferentes ordens SQL, obtemos a seguinte tabela:

3.5. Consulta de uma tabela

3.5.1. Introdução

No editor SQL, introduzimos o seguinte comando:

Image

e executemo-lo. Obtemos o seguinte resultado:

Image

O comando SELECT permite consultar o conteúdo das tabelas da base de dados. Este comando tem uma sintaxe muito rica. Apresentamos aqui apenas a sintaxe que permite consultar uma única tabela. Abordaremos posteriormente a consulta simultânea de várias tabelas. A sintaxe do comando SQL [SELECT] é a seguinte:

syntaxe
SELECT [ALL|DISTINCT] [*|expression1 alias1, expression2 alias2, ...]
FROM table
action
exibe os valores de expressioni para todas as linhas da tabela. expressioni pode ser uma coluna ou uma expressão mais complexa. O símbolo * designa o conjunto de colunas. Por predefinição, são apresentadas todas as linhas da tabela (ALL). Se DISTINCT estiver presente, as linhas idênticas selecionadas são apresentadas apenas uma vez. Os valores de expressioni são apresentados numa coluna com o título expressioni ou aliasi, caso este tenha sido utilizado.

Exemplos:

SQL > select titre, auteur from biblio

Image

SQL> select titre,prix from biblio

Image

SQL> select titre TITRE_DU_LIVRE, prix PRIX_ACHAT from biblio

Image

Acima, associamos aliases (TITRE_DU_LIVRE, PRIX_ACHAT) às colunas solicitadas.

3.5.2. Exibição das linhas que cumprem uma condição

syntaxe
SELECT ....
WHERE condition
action
só são apresentadas as linhas que cumprem a condição condition

Exemplos

SQL> select titre,prix from biblio where prix>100

Image

SQL> select titre,prix,genre from biblio where genre='Roman'

Image

Um dos livros tem o género «romance» e não «Romance». Utilizamos a função upper, que transforma uma cadeia de caracteres em maiúsculas para obter todos os romances.

SQL> select titre,prix,genre from biblio where upper(genre)='ROMAN'

Image

Podemos combinar condições através de operadores lógicos

AND
ET lógica
OR
OU lógica
NOT
Negação lógica
SQL> select titre,prix,genre from biblio where upper(genre)='ROMAN' and prix<100

Image

SQL> select titre,genre from biblio

Image

SQL> select titre,genre from biblio where upper(genre)='ROMAN' or upper(genre)='BD'

Image

SQL> select titre,genre from biblio where not( upper(genre)='ROMAN' or upper(genre)='BD')

Image

SQL> select titre,achat from biblio

Image

SQL>select titre,achat from biblio where achat>'31-dec-1987'
SQL> select titre,prix from biblio where prix between 100 and 150

Image

3.5.3. Exibição das linhas numa ordem determinada

Às sintaxes anteriores, é possível adicionar uma cláusula ORDER BY que indique a ordem de exibição pretendida:

syntaxe
SELECT ....
ORDER BY expression1 [asc|desc], expression2 [asc|dec], ...
action
As linhas resultantes da seleção são apresentadas na ordem de
1: ordem crescente (asc / ascending, que é o valor por predefinição) ou decrescente (desc / descending) de expression1
2: em caso de igualdade de expression1, a exibição é feita de acordo com os valores de expression2
etc.

Exemplos:

SQL>select titre, genre,prix,achat from biblio order by achat desc

Image

SQL>select titre, genre,prix,achat from biblio order by prix

Image

SQL>select titre, genre,prix,achat from biblio order by genre desc

Image

SQL >select titre, genre,prix,achat from biblio order by genre desc, prix

Image

SQL>select titre, genre,prix,achat from biblio order by genre desc, prix desc

Image

3.6. Eliminação de linhas numa tabela

syntaxe
DELETE FROM table [WHERE condition]
action
elimina as linhas de table verificando condition. Se esta última estiver ausente, todas as linhas são eliminadas.

Exemplos:

SQL> select titre from biblio

Image

Os dois comandos abaixo são emitidos um após o outro:

SQL> delete from biblio where titre='Candide'
SQL> select titre from biblio

Image

3.7. Alteração do conteúdo de uma tabela

syntaxe
update table set coluna1 = expressão1, coluna2 = expressão2, ...
[where condition]
action
Para as linhas de table que verificam condition (todas as linhas, se não houver nenhuma condição), colonnei recebe o valor de expressioni.

Exemplos:

SQL> select genre from biblio

Escrevem-se todos os géneros em maiúsculas:

Image

SQL> update biblio set genre=upper(genre)

Verifica-se:

SQL> select genre from biblio

Image

Exibimos os preços:

SQL> select genre,prix from biblio;

Image

O preço dos romances aumenta 5%:

SQL> update biblio set prix=prix*1.05 where genre='ROMAN';

Verificamos:

SQL> select genre,prix from biblio

Image

3.8. Atualização definitiva de uma tabela

Quando se efetuam alterações numa tabela, o Firebird gera-as, na verdade, numa cópia da tabela. Estas alterações podem então ser tornadas definitivas ou anuladas através dos comandos COMMIT e ROLLBACK.

syntaxe
COMMIT
action
torna definitivas as atualizações efetuadas nas tabelas desde a última execução do COMMIT.
syntaxe
ROLLBACK
action
anula todas as alterações efetuadas nas tabelas desde a última execução do COMMIT.
Remarque
Um COMMIT é executado implicitamente nos seguintes momentos:
a) Ao terminar a sessão do Firebird
b) Após cada comando que afete a estrutura das tabelas: CREATE, ALTER, DROP.

Exemplos

No editor SQL, coloca-se a base de dados num estado conhecido, validando todas as operações realizadas desde o último COMMIT ou ROLLBACK:

SQL> commit

Solicita-se a lista de títulos:

SQL> select titre from biblio

Image

Eliminação de um título:

SQL> delete from biblio where titre='La terre'

Verificação:

SQL> select titre from biblio

Image

O título foi efetivamente eliminado. Agora, invalidamos todas as alterações efetuadas desde o último COMMIT / ROLLBACK:

SQL> rollback

Verificação:

SQL> select titre from biblio

Image

O título que tinha sido eliminado volta a aparecer. Vamos agora solicitar a lista de preços:

SQL> select prix from biblio

Image

Suponhamos que todos os preços foram zerados.

SQL> update biblio set prix=0

Vamos verificar os preços:

SQL> select prix from biblio

Image

Vamos eliminar as alterações feitas na base:

SQL> rollback

e vamos verificar novamente os preços:

SQL> select prix from biblio

Image

Recuperámos os preços iniciais.

3.9. Adicionar linhas de uma tabela a partir de outra tabela

É possível adicionar linhas de uma tabela a outra quando as suas estruturas são compatíveis. Para demonstrar isso, comecemos por criar uma tabela [BIBLIO2] com a mesma estrutura que a [BIBLIO].

No explorador de bases de dados de IBExpert, cliquemos duas vezes na tabela [BIBLIO] para aceder ao separador [DDL]:

Image

Nesta guia, encontra-se a lista de ordens SQL que permitem gerar a tabela [BIBLIO]. Copiem todo este código para a área de transferência (CTRL-A, CTRL-C). Em seguida, vamos aceder a uma ferramenta chamada [Script Executive] que permite executar uma lista de ordens SQL:

Image

Aparece um editor de texto, no qual podemos colar (CTRL-V) o texto que colocámos anteriormente na área de transferência:

Image

Uma lista de comandos SQL é frequentemente designada por script SQL. O [Script Executive] permite-nos executar um script deste tipo, ao passo que o editor SQL só permitia a execução de um único comando de cada vez. O script SQL atual permite criar a tabela [BIBLIO]. Vamos fazer com que crie uma tabela chamada [BIBLIO2]. Para isso, basta alterar [BIBLIO] para [BIBLIO2]:

SET SQL DIALECT 3;

SET NAMES ISO8859_1;

CREATE TABLE BIBLIO2 (
    ID          INTEGER NOT NULL,
    TITRE       VARCHAR(30) NOT NULL,
    AUTEUR      VARCHAR(20) NOT NULL,
    GENRE       VARCHAR(20) NOT NULL,
    ACHAT       DATE NOT NULL,
    PRIX        NUMERIC(6,2) DEFAULT 10 NOT NULL,
    DISPONIBLE  CHAR(1) NOT NULL
);

ALTER TABLE BIBLIO2 ADD CONSTRAINT UNQ1_BIBLIIO2 UNIQUE (TITRE);

ALTER TABLE BIBLIO2 ADD CONSTRAINT PK_BIBLIIO2 PRIMARY KEY (ID);

Vamos executar este script com o botão [Run Script] abaixo:

Image

O script é executado:

Image

e podemos ver a nova tabela no explorador de bases de dados:

Image

Se clicarmos duas vezes em [BIBLIO2] para verificar o seu conteúdo, verificamos que está vazia, o que é normal:

Image

Uma variante do comando SQL INSERT permite inserir numa tabela linhas provenientes de outra tabela:

syntaxe
INSERT INTO table1 [(colonne1, colonne2, ...)]
SELECT coluna, coluna, ... FROM table2 WHERE condition
action
As linhas de table2 que verificam condition são adicionadas a table1. As colunas colonnea, colonneb, ... de table2 são atribuídas, por ordem, às colunas colonne1, colonne2, ... de table1 e, por isso, devem ser de um tipo compatível.

Voltemos ao editor SQL:

Image

e emitamos a seguinte ordem SQL:

SQL> insert into BIBLIO2 select * from BIBLIO where upper(genre)='ROMAN'

que insere no [BIBLIO2] todas as linhas do [BIBLIO] correspondentes a um romance. Após a execução da ordem SQL, validemo-la com um [Commit]:

SQL> commit

Feito isto, consultemos os dados da tabela [BIBLIO2]:

SQL> select * from BIBLIO2

Image

3.10. Eliminação de uma tabela

syntaxe
DROP TABLE table
action
elimina table

Exemplo: elimina-se a tabela BIBLIO2

SQL> drop table BIBLIO2

Valida-se a alteração:

SQL> commit

No explorador de bases de dados, atualiza-se a visualização das tabelas:

Image

Verifica-se que a tabela [BIBLIO2] foi eliminada:

Image

3.11. Alteração da estrutura de uma tabela

syntaxe
ALTER TABLE table
[ ADD nom_colonne1 type_colonne1 contrainte_colonne1]
[ALTER nom_colonne2 TYPE type_colonne2]
[DROP nom_colonne3]
[ADD contrainte]
[DROP CONSTRAINT nom_contrainte]
action
permite adicionar (ADD), alterar (ALTER) e eliminar (DROP) colunas de uma tabela. A sintaxe nom_colonnei type_colonnei contrainte_colonnei é a mesma que a de CREATE TABLE. Também é possível adicionar/eliminar restrições da tabela.

Exemplo: Executemos sucessivamente os dois comandos SQL seguintes no editor SQL

SQL > alter table biblio add nb_pages numeric(4), alter genre type varchar(30)
SQL> commit

No explorador de bases de dados, verifiquemos a estrutura da tabela [BIBLIO]:

Image

As alterações foram aplicadas. Vamos ver como o conteúdo da tabela evoluiu:

SQL> select * from biblio

Image

A nova coluna [NB_PAGES] foi criada, mas não tem qualquer valor. Vamos eliminar esta coluna:

SQL> alter table biblio drop nb_pages
SQL> commit

Vamos verificar a nova estrutura da tabela [BIBLIO]:

Image

A coluna [NB_PAGES] desapareceu efetivamente.

3.12. As vistas

É possível ter uma vista parcial de uma tabela ou de várias tabelas. Uma vista funciona como uma tabela, mas não contém dados. Os seus dados são extraídos de outras tabelas ou vistas. Uma vista apresenta várias vantagens:

  1. Um utilizador pode estar interessado apenas em determinadas colunas e linhas de uma tabela específica. A vista permite-lhe ver apenas essas linhas e colunas.
  2. O proprietário de uma tabela pode querer autorizar apenas um acesso limitado a outros utilizadores. A vista permite-lhe fazê-lo. Os utilizadores que ele autorizar terão acesso apenas à vista que ele tiver definido.

3.12.1. Criação de uma vista

syntaxe
CREATE VIEW nom_vue
AS SELECT coluna1, coluna2, ... FROM table WHERE condition
[ WITH CHECK OPTION ]
action
cria a vista nom_vue. Esta é uma tabela cuja estrutura é composta pelas colunas coluna1, coluna2, ... de table e, nas linhas, pelas linhas de table que satisfazem a condição de condition (todas as linhas, caso não haja condição)
WITH CHECK OPTION
Esta cláusula opcional indica que as inserções e atualizações na vista não devem criar linhas que a vista não possa selecionar.

Nota A sintaxe de CREATE VIEW é, na verdade, mais complexa do que a apresentada acima e permite, nomeadamente, criar uma visualização a partir de várias tabelas. Para tal, basta que a consulta SELECT abranja várias tabelas (ver capítulo seguinte).

Exemplos

A partir da tabela «biblio», cria-se uma vista que inclui apenas os romances (seleção de linhas) e apenas as colunas «título», «autor» e «preço» (seleção de colunas):

SQL> create view romans as select titre,auteur,prix from biblio where upper(genre)='ROMAN';
SQL> commit

No explorador de bases de dados, atualizamos a vista (F5). Aparece uma vista:

Image

É possível saber a ordem SQL associada à vista. Para tal, cliquemos duas vezes na vista [ROMANS]:

Image

Uma vista é como uma tabela. Tem uma estrutura:

Image

e um conteúdo:

Image

Uma vista utiliza-se como uma tabela. É possível efetuar consultas SQL sobre ela. Aqui estão alguns exemplos para experimentar no editor SQL:

SQL> select * from romans

Image

SQL> insert into biblio values (10,'Le père Goriot','Balzac','Roman','01-sep-91',200,'o')

O novo romance está visível na vista [ROMANS]?

SQL> select * from romans

Image

Vamos adicionar algo mais do que um romance à tabela [BIBLIO]:

SQL> insert into biblio(id,titre,auteur,genre,achat,prix,disponible) values (11,'Poèmes saturniens','Verlaine','Poème','02-sep-92',200,'o');

Vamos verificar a tabela [BIBLIO]:

SQL> select titre, auteur from BIBLIO

Image

Vamos verificar a vista [ROMANS]:

SQL> select titre, auteur from ROMANS

Image

O livro adicionado não consta da vista [ROMANS] porque não tinha upper(género)='ROMAN'.

3.12.2. Atualização de uma vista

É possível atualizar uma vista da mesma forma que se faz com uma tabela. Todas as tabelas das quais são extraídos os dados da vista são afetadas por esta atualização. Aqui estão alguns exemplos:

SQL> insert into biblio(id,titre,auteur,genre,achat,prix,disponible) values (13,'Le Rouge et le Noir','Stendhal','Roman','03-oct-92',110,'o')
SQL> select * from romans

Image

SQL> select titre, auteur from biblio

Image

É eliminada uma linha da vista [ROMANS]:

SQL> delete from ROMANS where titre='Le Rouge et le Noir'
SQL> select * from romans

Image

SQL> select auteur, titre from BIBLIO

Image

A linha eliminada da vista [ROMANS] foi também eliminada na tabela [BIBLIO]. Passamos agora a aumentar o preço dos livros da vista [ROMANS]:

SQL> update romans set prix=prix*1.05

Verifica-se na [ROMANS]:

SQL> select * from romans

Image

Qual foi o impacto na tabela [BIBLIO]?

SQL> select titre, auteur, prix from biblio

Image

Os romances também registaram um aumento de 5% na tabela [BIBLIO].

3.12.3. Eliminar uma vista

syntaxe
DROP VIEW nom_vue
action
elimina a vista denominada

Exemplo

SQL> drop view romans
SQL> commit

No explorador de bases de dados, é possível atualizar a vista (F5) para verificar que a vista [ROMANS] desapareceu:

Image

3.13. Utilização de funções de grupos

Existem funções que, em vez de atuarem em cada linha de uma tabela, atuam em grupos de linhas. Trata-se essencialmente de funções estatísticas que nos permitem obter a média, o desvio-padrão, etc., dos dados de uma coluna.

syntaxe1
SELECT f1, f2, .., fn FROM table
[ WHERE condition ]
action
calcula as funções estatísticas fi em todas as linhas da tabela, verificando a eventual condition.
syntaxe2
SELECT f1, f2, .., fn FROM table
[ WHERE condition ]
[ GROUP BY expr1, expr2, ..]
action
A palavra-chave GROUP BY tem como efeito dividir as linhas da tabela em grupos. Cada grupo contém as linhas para as quais as expressões expr1, expr2, ... têm o mesmo valor.
Exemplo: GROUP BY género coloca num mesmo grupo os livros com o mesmo género. A cláusula GROUP BY autor,género colocaria no mesmo grupo os livros com o mesmo autor e o mesmo género. A cláusula WHERE condição elimina primeiro da tabela as linhas que não satisfazem a condição. Em seguida, os grupos são formados pela cláusula GROUP BY. As funções fi são então calculadas para cada grupo de linhas.
syntaxe3
SELECT f1, f2, .., fn FROM table
[ WHERE condition ]
[ GROUP BY expression]
[ HAVING condition_de_groupe]
action
A cláusula HAVING filtra os grupos formados pela cláusula GROUP BY. Por isso, está sempre ligada à presença desta cláusula GROUP BY. Exemplo: GROUP BY tipo HAVING tipo!='ROMAN'

As funções estatísticas fi disponíveis são as seguintes:

AVG(expression)
média da expressão
COUNT(expression)
número de linhas em que a expressão tem um valor
COUNT(*)
número total de linhas na tabela
MAX(expression)
valor máximo da expressão
MIN(expression)
mínimo de expressões
SUM(expression)
soma da expressão

Exemplos

SQL> select prix from biblio

Image

Preço médio? Preço máximo? Preço mínimo?

SQL> select avg(prix), max(prix), min (prix) from biblio

Image

SQL> select titre, prix,genre from biblio

Image

Preço médio de um romance? Preço máximo?

SQL> select avg(prix) moyenne, max(prix) prix_maxi from biblio where upper(genre)='ROMAN'

Image

Quantos BD?

SQL> select count(*) from biblio where upper(genre)='BD'

Image

Quantos romances custam menos de 100 F?

SQL> select count(*) from biblio where upper(genre)='ROMAN' and prix<100

Image

SQL> select genre, prix from biblio

Image

Quantos livros e qual é o preço médio por livro para livros do mesmo género?

SQL> select upper(genre) GENRE,avg(prix) PRIX_MOYEN,count(*) NOMBRE from biblio group by upper(genre)

Image

A mesma pergunta, mas apenas para os livros que não são romances:

SQL>
select upper(genre) GENRE,avg(prix) PRIX_MOYEN,count(*) NOMBRE
from biblio
group by upper(genre)
having upper(GENRE)!='ROMAN'

Image

A mesma questão, mas apenas para livros com um preço inferior a 150 F:

SQL> 
select upper(genre) GENRE,avg(prix) PRIX_MOYEN,count(*) NOMBRE
from biblio
where prix<150
group by upper(genre)
having upper(GENRE)!='ROMAN'

Image

A mesma questão, mas apenas se mantêm os grupos com um preço médio por livro >100 F

SQL> 
select upper(genre) GENRE, avg(prix) PRIX_MOYEN,count(*) NOMBRE
from biblio
group by upper(genre)
having avg(prix)>100

Image

3.14. Criar o script SQL « » a partir de uma tabela

A linguagem SQL é uma linguagem padrão que pode ser utilizada com vários SGBD. Para poder passar de um SGBD para outro, é aconselhável exportar uma base de dados ou apenas alguns dos seus elementos sob a forma de um script SQL que, quando executado noutro SGBD, será capaz de recriar os elementos exportados no script.

Vamos agora exportar a tabela [BIBLIO]. Escolhamos a opção [Extract Metadata]:

Image

Repare-se que, como se vê acima, é necessário estar na base da qual se pretende exportar os elementos. A opção inicia um assistente:

1
onde gerar o script SQL:
  • num ficheiro (File)
  • na Área de Trabalho (Clipboard)
  • na ferramenta Script Executive
2
nome do ficheiro se for selecionada a opção [File]
3
O que exportar
4
botões para selecionar (->) ou desmarcar (<-) os objetos a exportar

Se quiséssemos exportar toda a base de dados, marcaríamos a opção [Extract All] acima. Queremos simplesmente exportar a tabela BIBLIO. Para tal, com [4], selecionamos a tabela [BIBLIO] e, com [2], indicamos um ficheiro:

Image

Se pararmos por aqui, apenas a estrutura da tabela [BIBLIO] será exportada. Para exportar o seu conteúdo, temos de utilizar o separador [Data Tables]:

Utilizemos [1] para selecionar a tabela [BIBLIO]:

Utilizemos [2] para gerar o script SQL:

Image

Aceitemos a proposta. Isto permite-nos ver o script que foi gerado no ficheiro [biblio.sql]:

/******************************************************************************/
/****          Gerado por IBExpert 17/06/2004 22/01/2006 15:        06:13 ****/
/******************************************************************************/

SET SQL DIALECT 3;

SET NAMES ISO8859_1;

CREATE DATABASE 'D:\data\serge\travail\2005-2006\polys\sql\DBBIBLIO.GDB'
USER 'SYSDBA' PASSWORD 'masterkey'
PAGE_SIZE 16384
DEFAULT CHARACTER SET ISO8859_1;



/******************************************************************************/
/****                                                                 Tabelas ****/
/******************************************************************************/



CREATE TABLE BIBLIO (
ID          INTEGER NOT NULL,
TITRE       VARCHAR(30) NOT NULL,
AUTEUR      VARCHAR(20) NOT NULL,
GENRE       VARCHAR(30) NOT NULL,
ACHAT       DATE NOT NULL,
PRIX        NUMERIC(6,2) DEFAULT 10 NOT NULL,
DISPONIBLE  CHAR(1) NOT NULL
);

INSERT INTO BIBLIO (ID, TITRE, AUTEUR, GENRE, ACHAT, PRIX, DISPONIBLE) VALUES (2, 'Les fleurs du mal', 'Baudelaire', 'POèME', '1978-01-01', 120, 'n');
INSERT INTO BIBLIO (ID, TITRE, AUTEUR, GENRE, ACHAT, PRIX, DISPONIBLE) VALUES (3, 'Tintin au Tibet', 'Hergé', 'BD', '1990-11-10', 70, 'o');
INSERT INTO BIBLIO (ID, TITRE, AUTEUR, GENRE, ACHAT, PRIX, DISPONIBLE) VALUES (4, 'Du côté de chez Swann', 'Proust', 'ROMAN', '1978-12-08', 220.5, 'o');
INSERT INTO BIBLIO (ID, TITRE, AUTEUR, GENRE, ACHAT, PRIX, DISPONIBLE) VALUES (5, 'La terre', 'Zola', 'ROMAN', '1990-06-12', 55.13, 'n');
INSERT INTO BIBLIO (ID, TITRE, AUTEUR, GENRE, ACHAT, PRIX, DISPONIBLE) VALUES (6, 'Madame Bovary', 'Flaubert', 'ROMAN', '1988-03-12', 143.33, 'o');
INSERT INTO BIBLIO (ID, TITRE, AUTEUR, GENRE, ACHAT, PRIX, DISPONIBLE) VALUES (7, 'Manhattan transfer', 'Dos Passos', 'ROMAN', '1987-08-30', 352.8, 'o');
INSERT INTO BIBLIO (ID, TITRE, AUTEUR, GENRE, ACHAT, PRIX, DISPONIBLE) VALUES (8, 'Tintin en Amérique', 'Hergé', 'BD', '1991-05-15', 70, 'o');
INSERT INTO BIBLIO (ID, TITRE, AUTEUR, GENRE, ACHAT, PRIX, DISPONIBLE) VALUES (10, 'Le père Goriot', 'Balzac', 'Roman', '1991-09-01', 210, 'o');
INSERT INTO BIBLIO (ID, TITRE, AUTEUR, GENRE, ACHAT, PRIX, DISPONIBLE) VALUES (11, 'Poèmes saturniens', 'Verlaine', 'Poème', '1992-09-02', 200, 'o');

COMMIT WORK;



/******************************************************************************/
/****                                                     Restrições únicas ****/
/******************************************************************************/

ALTER TABLE BIBLIO ADD CONSTRAINT UNQ1_BIBLIO UNIQUE (TITRE);


/******************************************************************************/
/****                                                           Chaves primárias ****/
/******************************************************************************/

ALTER TABLE BIBLIO ADD CONSTRAINT PK_BIBLIO PRIMARY KEY (ID);
  • as linhas 1 a 3 são comentários
  • as linhas 5 a 12 são do SQL, propriedade do Firebird
  • as restantes linhas pertencem ao SQL padrão, que deverão poder ser executadas num SGBD que tenha os tipos de dados declarados na tabela BIBLIO.

Vamos executar novamente este script no Firebird para criar uma tabela BIBLIO2, que será um clone da tabela BIBLIO. Para tal, vamos utilizar o [Script Executive] (Ctrl-F12):

Image

Vamos carregar o script [biblio.sql] que acabámos de gerar:

Image

Alteremo-lo para manter apenas a parte relativa à criação da tabela e à inserção de linhas. A tabela passa a chamar-se [BIBLIO2]:

CREATE TABLE BIBLIO2 (
    ID          INTEGER NOT NULL,
    TITRE       VARCHAR(30) NOT NULL,
    AUTEUR      VARCHAR(20) NOT NULL,
    GENRE       VARCHAR(30) NOT NULL,
    ACHAT       DATE NOT NULL,
    PRIX        NUMERIC(6,2) DEFAULT 10 NOT NULL,
    DISPONIBLE  CHAR(1) NOT NULL
);

INSERT INTO BIBLIO2 (ID, TITRE, AUTEUR, GENRE, ACHAT, PRIX, DISPONIBLE) VALUES (2, 'Les fleurs du mal', 'Baudelaire', 'POèME', '1978-01-01', 120, 'n');
...

COMMIT WORK;

Vamos executar este script:

Podemos verificar no explorador de bases de dados que a tabela [BIBLIO2] foi efetivamente criada e que possui a estrutura e o conteúdo esperados: