SQL DDL Criando Tabelas e Restrições Fernanda Baião UNIRIO Material parcialmente extraído a partir das notas de aula de Maria Luiza M. Campos, Arnaldo Rocha e Maria Cláudia Cavalcanti Comandos de Definição de Dados Create Drop Alter schema domain table view index assertion database Create Schema Coleção de tabelas, visões, domínios, funções e permissões CREATE SCHEMA [schema_name] [AUTHORIZATION owner_name] [ANSI CREATE statements [ ]] [ANSI GRANT statements [ ]] Ex. CREATE SCHEMA empresa AUTHORIZATION a01 CREATE TABLE empregado ( ) CREATE TABLE departamento ( ) 1
Create Table EMPREGADO Nome SNome Matrícula DataNasc Endereço Sexo Salário SuperMat Depto DEPARTAMENTO DeptoNome DeptoSigla MatrículaGerente DEPTO_LOCAL Depto Localização PROJETO PNome PCódigo PLocalização Depto TRABALHA_EM MatrículaEmp PCódigo Horas DEPENDENTE MatrículaEmp DependenteNome Sexo DataNasc Parentesco Create Table Para criar as tabelas CREATE [{LOCAL TEMPORARY GLOBAL TEMPORARY}] TABLE table_name (column_name datatype attributes [, ]) [CONSTRAINT constraint_type [constraint_name] [, ]] Attributes podem ser NOT NULL DEFAULT CONSTRAINT Tipos de dados char(n) varchar(n) ou char varying(n) int ou integer shortint float ou real double precision decimal(n,d) ou numeric(n,d) date time SQL:2003 BIGINT, MULTISET, XML 2
Create Table create table Empregado ( Nome varchar(15) not null, SNome varchar(15) not null, Matrícula char(9) not null, DataNasc date, Endereço varchar(30), Sexo char, Salário decimal(10,2), SuperMat char(9), Depto char(5) not null, primary key (Matrícula), foreign key (SuperMat) references Empregado(Matrícula), foreign key (Depto) references Departamento (DeptoSigla)); Create Table create table Departamento ( DeptoNome varchar(15) not null, DeptoSigla char(5) not null, MatrículaGerente char(9) not null, primary key (DeptoSigla), unique (DeptoNome), foreign key (MatrículaGerente) references Empregado (Matrícula)); create table Depto_Local ( Depto char(9) not null, Localização varchar(15) not null, primary key (Depto, Localização), foreign key (Depto) references Departamento (DeptoSigla)); Create Table create table Projeto ( PNome varchar(15) not null, Pcódigo int not null, PLocalização varchar(15), Depto char(5) not null, primary key (Pcódigo), unique (PNome), foreign key (Depto) references Departamento (DeptoSigla)); create table Trabalha_Em ( MatrículaEmp char(9) not null, Pcódigo int not null, Horas decimal(3,1) not null, primary key (MatrículaEmp, Pcódigo), foreign key (MatrículaEmp) references Empregado (Matrícula), foreign key (Pcódigo ) references Projeto (Pcódigo)); 3
Create Table create table Dependente ( MatrículaEmp char(9) not null, DependenteNome varchar(15) not null, Sexo char, DataNasc date, Parentesco varchar(8) not null, AuxilioCreche numeric(6,2), primary key (MatrículaEmp, DependenteNome), foreign key (MatrículaEmp) references Empregado (Matrícula)); Alter Table Acrescentar e remover atributos Ex. ALTER TABLE Dependente ADD Parentesco VARCHAR(8) DEFAULT `filho`; ALTER TABLE Dependente DROP AuxilioCreche; Alguns SGBDs oferecem MODIFY Ex. ALTER TABLE Dependente MODIFY Parentesco VARCHAR(8) DEFAULT `filho`; Geradores de Sequência Padronizado no SQL 2003 Para preencher valores de chaves Controle fica centralizado em um objeto O uso de chaves como cpf ou e-mail traz problemas CREATE SEQUENCE PARTSEQ AS INTEGER START WITH 1 INCREMENT BY 1 MINVALUE 1 MAXVALUE 10000 NO CYCLE 4
Usando/Modificando Geradores de Sequência Função built-in: NEXT VALUE FOR chamada no momento da inclusão INSERT INTO SHIPMENT ( PARTNUM, DECRIPTION, QUANTITY ) VALUES ( NEXT VALUE FOR PARTSEQ, 'Display', 20); IDENTITY Declarar tipos sequenciais na própria estrutura da tabela Função next value for fica implícita na inserção. GENERATED ALWAYS ou BY DEFAULT.. CREATE TABLE PARTS ( PARTNUM INTEGER GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1 MINVALUE 1 MAXVALUE 10000 NO CYCLE), DESCRIPTION VARCHAR (100), QUANTITY INTEGER INSERT INTO PARTS (DESCRIPTION, QUANTITY) VALUES ('WIDGET', 30) Restrições Domínio Chaves primárias e secundárias Chaves estrangeiras Check Assertion 5
Domínios apenas permite que um tipo de dados seja compartilhado por vários atributos. create domain Cor char (6) default??? constraint CoresValidas check ( value in ( azul, amarelo, verde,??? )) ;... create table T (..., cort Cor,... ) ; Restrições create table Empregado (... Depto char(5) not null default DESC, constraint Emppk primary key (Matrícula), constraint Superfk foreign key (SuperMat) references Empregado(Matrícula) on delete set null on update cascade, constraint EmpDept foreign key (Depto) references Departamento (DeptoSigla) on delete set null on update cascade ); Restrições create table Departamento (... MatrículaGerente char(9) not null default 888665555, constraint Deptopk primary key (DeptoSigla), constraint Deptosk unique (DeptoNome), constraint DeptoGerfk foreign key (MatriculaGerente) references Empregado (Matrícula) on delete set default on update cascade ); create table Depto_Local (... primary key (Depto, Localização), foreign key (Depto) references Departamento (DeptoSigla) on delete cascade on update cascade ); 6
Restrições check (expressão) create table SP ( S# char(5) not null, P# char(5) not null, Qtde integer not null, primary key (S#, P#), foreign key (S#) references S (S#) on delete cascade on update cascade, foreign key (P#) references P (P#) on delete cascade on update cascade, check (Qtde > 0 and Qtde < 5001) ); Restrições check pode ser usado ao invés de create domain create table P ( P# char(5) not null, CorP char(10) not null, primary key (P#), check (CorP in (`azul`, `verde`, `branco`)) ); not null pode ser declarado como um check check (CorP is not null) Restrições Cuidado com checks que envolvem mais de uma tabela! create table EMPREGADO ( matricula char(9) not null, nome varchar(20) not null, depto char(5) check (depto in (select deptosigla from DEPARTAMENTO)),... Inclusões e atualizações em EMPREGADO são verificadas, mas remoções em DEPARTAMENTO não o serão 7
Assertions General constraints Quando a restrição envolve mais de uma relação e precisa ser verificada sempre que qq das relações envolvidas mudar Ex. CREATE ASSERTION marajá CHECK (NOT EXISTS ( SELECT * FROM empregado e, trabalha_em t WHERE e.matricula = t.matriculaemp AND e.salario > 100000)) Modificando Restrições Atribuir nomes às restrições Add/drop restrições Exemplos: ALTER TABLE empregado DROP CONSTRAINT Deptosk ALTER TABLE empregado ADD CONSTRAINT nova CHECK sexo IN ( F, M ) ALTER DOMAIN Cor DROP CONSTRAINT CoresValidas ALTER DOMAIN Cor ADD CONSTRAINT CoresModa CHECK (values IN ( rosa,...)) DROP ASSERTION marajá Triggers Regras event-condition-action (ECA) Controle sobre os eventos Propósito mais amplo que restrições Ações podem ocorrer antes, depois ou ao invés do evento Referência aos valores antigos e novos 8
Triggers No PL/pgSQL um trigger pode ser criado através do comando CREATE FUNCTION Sem parâmetros RETURNS trigger Qdo a função é chamada como um trigger, variáveis especiais são criadas OLD, NEW, TG_NAME, TG_WHEN, TG_LEVEL, TG_OP, TG_RELID, TG_RELNAME, TG_NARGS, TG_ARGS[] Triggers CREATE TABLE emp ( empname text, salary integer, last_date timestamp, last_user text ); CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$ BEGIN IF NEW.empname IS NULL OR NEW.salary IS NULL THEN RAISE EXCEPTION 'empname or salary cannot be null'; END IF; IF NEW.salary < 0 THEN RAISE EXCEPTION 'cannot have a negative salary'; END IF; -- Remember who changed the payroll when NEW.last_date := 'now'; NEW.last_user := current_user; RETURN NEW; END; $emp_stamp$ LANGUAGE plpgsql; CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp FOR EACH ROW EXECUTE PROCEDURE emp_stamp(); Triggers exemplos Irredutibilidade de salários CREATE OR REPLACE FUNCTION empresa.vsalario() RETURNS trigger AS $$ BEGIN IF NEW.salario < OLD.salario THEN RAISE EXCEPTION ' NAO SE PODE DIMINUIR SALARIO'; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; DROP TRIGGER atuemp ON empresa.empregado; CREATE TRIGGER atuemp BEFORE UPDATE ON empresa.empregado FOR EACH ROW EXECUTE PROCEDURE empresa.vsalario(); 9
Triggers exemplos o salário de um empregado tem de ser menor ou igual ao salário de seu supervisor. CREATE OR REPLACE FUNCTION empresa.vsalariosup() RETURNS trigger AS $$ BEGIN IF NEW.salario > (SELECT salario FROM empresa.empregado e WHERE e.matricula = NEW.supervisor) THEN RAISE EXCEPTION ' emp % nao pode ter salario superior ao do chefe', NEW.nomeemp; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER atuemp2 BEFORE INSERT OR UPDATE ON empresa.empregado FOR EACH ROW EXECUTE PROCEDURE empresa.vsalariosup(); Triggers exemplos o número de horas semanais que um empregado pode trabalhar em projetos tem de ser menor ou igual a 56 CREATE OR REPLACE FUNCTION empresa.vtothoras() RETURNS trigger AS $$ BEGIN IF 56 < NEW.tothoras + (SELECT sum(t.tothoras) FROM empresa.trabalhaem t WHERE t.empmat = NEW.empmat) THEN RAISE EXCEPTION ' emp % nao pode trabalhar mais de 56 horas', NEW.empmat; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; DROP TRIGGER vtothoras ON empresa.trabalhaem; CREATE TRIGGER vtothoras BEFORE INSERT OR UPDATE ON empresa.trabalhaem FOR EACH ROW EXECUTE PROCEDURE empresa.vtothoras(); Visões Definidas como uma consulta; Não existem fisicamente; Podem ser consultadas como uma tabela comum; Ex. CREATE VIEW Empregado_v AS SELECT nome, snome, matricula, depto FROM Empregado; Renomeando atributos CREATE VIEW Empregado_v (nomefunc, snomefunc, mat, dpt) AS... 10
Visões - atualizações Ao incluir tuplas, os atributos não usados na visão podem ser preenchidos com NULL ou com DEFAULT caso possível. Uma visão, para ser atualizável: não pode referenciar mais de uma tabela, seja através de comandos UNION ou na cláusula FROM não pode usar cláusulas DISTINCT, GROUP BY ou HAVING precisa incluir todos os campos not null que não apresentam valor default [WITH CHECK OPTION] Força que os comandos de modificação executados estejam de acordo com o critério do comando select CREATE VIEW Empregado_v AS SELECT nome, snome, matricula, depto FROM Empregado WHERE depto = SE9 WHITH CHECK OPTION 11