Restrições de Integridade
No Modelo Entidade-Relacionamento (MER), as restrições de integridade são regras que garantem que a informação armazenada seja precisa, consistente e confiável. Sem elas, o banco de dados se torna uma “sucata digital” cheia de informações órfãs ou contraditórias.
Integridade de Domínio
A Integridade de Domínio define os valores válidos para um atributo específico. Ela garante que todos os dados em uma coluna pertençam a um conjunto de valores permitido (tipo de dado, formato, intervalo).
No PostgreSQL, aplicamos isso através de:
- Tipos de Dados:
INTEGER,VARCHAR,DATE. - Constraints:
NOT NULL(não aceita vazios) eCHECK(valida condições).
Tabela de produtos:
Imagine uma tabela de Produtos onde o preço não pode ser negativo.
Tabela de Produtos:
| ID | Nome | Preço | Categoria |
|---|---|---|---|
| 1 | Teclado | 150.00 | Eletrônicos |
| 2 | Mouse | -5.00 | ERRO! Violaria o domínio |
Comando SQL (PostgreSQL):
CREATE TABLE IF NOT EXISTS produtos (
id SERIAL PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
preco NUMERIC(10, 2) CHECK (preco > 0), -- Restrição de Domínio
categoria VARCHAR(50) DEFAULT 'Geral'
);
O comando CREATE DOMAIN:
O comando CREATE DOMAIN para padronização e auxliar a integridade de domínio.
CREATE DOMAIN email_valido AS VARCHAR(100) CHECK (VALUE ~* '^[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+[.][A-Za-z]+$');
CREATE DOMAIN sexo AS CHAR(1) DEFAULT 'M' CHECK (VALUE IN ('M', 'F'));
CREATE DOMAIN pos_int AS INTEGER CHECK (VALUE > 0);
CREATE TABLE funcionarios (
id SERIAL PRIMARY KEY,
nome VARCHAR(100),
email email_valido, -- Aplica a regra de e-mail
idade pos_int, -- Aplica a regra de ser > 0
genero sexo -- Aplica DEFAULT 'M' e restrição M/F
);
Integridade Referencial
A Integridade Referencial garante que as relações entre as tabelas permaneçam consistentes. Em termos simples: se a Tabela A aponta para a Tabela B (via Chave Estrangeira), o registro na Tabela B deve existir.
Ela impede que tenhamos “registros órfãos” (ex: um pedido de um cliente que não está cadastrado).
Tabelas de clientes e pedidos:
Temos as tabelas Clientes e Pedidos. Um pedido só pode existir se estiver vinculado a um cliente real.
Tabela Clientes:
| id (PK) | Nome |
|---|---|
| 10 | Ana Silva |
Tabela de Pedidos:
| id | id_cliente (FK) | Valor |
|---|---|---|
| 501 | 10 | 250.00 |
| 502 | 99 | ERRO! Cliente 99 não existe |
Comando SQL (PostgreSQL):
CREATE TABLE IF NOT EXISTS CLIENTES (
id INT PRIMARY KEY,
nome VARCHAR(100) NOT NULL
);
CREATE TABLE IF NOT EXISTS PEDIDOS (
id SERIAL PRIMARY KEY,
valor NUMERIC(10, 2),
id_cliente INT,
-- Restrição de Integridade Referencial
CONSTRAINT fk_cliente
FOREIGN KEY (id_cliente)
REFERENCES CLIENTES (id)
ON DELETE CASCADE
);
O comando ON DELETE CASCADE é uma estratégia de manutenção da integridade. Se o cliente for excluído, todos os pedidos dele também serão removidos automaticamente, evitando dados órfãos.
Exemplos práticos
CREATE TABLE IF NOT EXISTS SEXO (
ID INT PRIMARY KEY,
DESCRICAO VARCHAR(20)
);
INSERT INTO SEXO VALUES
(1, 'Masculino'),
(2, 'Feminino');
CREATE TABLE IF NOT EXISTS PESSOAS (
ID BIGINT PRIMARY KEY,
NOME VARCHAR(80) NOT NULL,
DATA_NASCIMENTO DATE NOT NULL,
ID_SEXO INT,
EMAIL VARCHAR(200) UNIQUE,
CONSTRAINT FK_SEXO FOREIGN KEY (ID_SEXO) REFERENCES SEXO (ID),
CONSTRAINT CHK_IDADE_MINIMA CHECK (EXTRACT(YEAR FROM AGE(CURRENT_DATE, data_nascimento)) >= 16)
);
INSERT INTO PESSOAS (ID, NOME, DATA_NASCIMENTO, ID_SEXO, EMAIL) VALUES
(1, 'Aragorn II Elessar', '1987-03-01', 1, 'aragorn.rei@gondor.com'),
(2, 'Arwen Undómiel', '1990-05-20', 2, 'arwen.estrela@rivendell.com'),
(3, 'Frodo Bolseiro', '2000-09-22', 1, 'frodo.portador@shire.com'),
(4, 'Galadriel', '1950-12-10', 2, 'galadriel.luz@lothlorien.com'),
(5, 'Gandalf, o Cinzento', '1940-01-01', 1, 'gandalf.istari@maiar.com'),
(6, 'Legolas Greenleaf', '1995-04-15', 1, 'legolas.arco@mirkwood.com'),
(7, 'Éowyn de Rohan', '2002-07-07', 2, 'eowyn.escudeira@rohan.com'),
(8, 'Gimli, Filho de Glóin', '1992-10-30', 1, 'gimli.machado@erebor.com'),
(9, 'Samwise Gamgee', '2001-04-06', 1, 'sam.fiel@shire.com'),
(10, 'Boromir de Gondor', '1982-01-25', 1, 'boromir.capitao@denethor.com');
CREATE TABLE IF NOT EXISTS ATENDENTES (
ID BIGINT PRIMARY KEY,
ID_PESSOA BIGINT,
SALARIO NUMERIC(10, 2),
CONSTRAINT FK_PESSOA_ATENDENTE FOREIGN KEY (ID_PESSOA) REFERENCES PESSOAS (ID),
CONSTRAINT CK_SALARIO_ATENDENTE CHECK (SALARIO BETWEEN 2000 AND 40000)
);
INSERT INTO ATENDENTES (ID, ID_PESSOA, SALARIO) VALUES
(1, 1, 15000.00), -- Aragorn II Elessar (ID_PESSOA 1)
(2, 5, 35500.00), -- Gandalf, o Cinzento (ID_PESSOA 5)
(3, 2, 8200.50), -- Arwen Undómiel (ID_PESSOA 2)
(4, 10, 5400.00), -- Boromir de Gondor (ID_PESSOA 10)
(5, 4, 28000.00); -- Galadriel (ID_PESSOA 4);
INSERT INTO PESSOAS (ID, NOME, DATA_NASCIMENTO, ID_SEXO, EMAIL) VALUES
(11, 'Belfast', '2021-03-01', 1, 'belfast.rei@gondor.com');
-- ERROR: new row for relation "pessoas" violates check constraint "chk_idade_minima"
--Failing row contains (11, Belfast, 2021-03-01, 1, belfast.rei@gondor.com).
Resumo das Restrições
| Tipo de Integridade | Foco | Principal Ferramenta SQL |
|---|---|---|
| Vazio (Nullity) | Presença de dados | NOT NULL |
| Domínio | Validade do valor | CHECK, DATA TYPE |
| Chave (Entidade) | Unicidade da linha | PRIMARY KEY, UNIQUE |
| Referencial | Relacionamento | FOREIGN KEY |