O que significa “sair do ER” e chegar no esquema lógico
O diagrama ER (conceitual) descreve significado: entidades, atributos e relacionamentos. O esquema lógico descreve implementação relacional: tabelas, colunas, chaves e constraints. O mapeamento é um conjunto de regras de transformação para preservar o sentido do modelo e, ao mesmo tempo, produzir uma estrutura executável em um SGBD relacional.
Ao transformar, você toma decisões que o ER não detalha totalmente, como: nomes físicos, tipos de dados, tamanhos, constraints (NOT NULL, UNIQUE, CHECK), ações de integridade (ON DELETE/UPDATE) e estratégias para casos como 1:1, multivalorados e especialização/generalização.
Regras de transformação (ER → Relacional)
1) Entidade → Tabela
Para cada entidade forte, crie uma tabela. A chave primária do ER vira PRIMARY KEY na tabela. Atributos simples viram colunas.
- Nome físico: prefira singular e sem espaços (ex.:
cliente,pedido). - Chave primária: mantenha a mesma semântica do ER. Se for substituta (ex.:
id), padronize (ex.:cliente_id).
2) Atributo → Coluna
Cada atributo simples vira uma coluna com tipo, obrigatoriedade e, quando aplicável, unicidade e validações. Atributos compostos normalmente são “achatados” em colunas (ex.: endereco → logradouro, numero, cidade).
- Obrigatório (participação total no atributo):
NOT NULL. - Valor único (candidato a chave):
UNIQUE. - Domínio restrito:
CHECK(ex.: status em conjunto fechado).
3) Relacionamento 1:N → Chave estrangeira no lado N
Em um relacionamento 1:N, a tabela do lado N recebe a chave estrangeira apontando para a tabela do lado 1.
- Ouça o áudio com a tela desligada
- Ganhe Certificado após a conclusão
- + de 5000 cursos para você explorar!
Baixar o aplicativo
Passo a passo:
- Identifique o lado 1 (pai) e o lado N (filho).
- Copie a PK do pai para o filho como coluna FK.
- Defina
FOREIGN KEYe escolha ações (ON DELETE/ON UPDATE). - Se a participação do lado N for obrigatória, marque a FK como
NOT NULL.
Exemplo: Cliente (1) — (N) Pedido → pedido.cliente_id referencia cliente.cliente_id.
4) Relacionamento N:N → Tabela associativa
Relacionamentos N:N não são representáveis diretamente com uma única FK. Crie uma tabela associativa (também chamada de tabela de junção) contendo as FKs para as duas entidades.
Passo a passo:
- Crie uma tabela com duas colunas FK (uma para cada lado).
- Defina a PK como composta (
(fk_a, fk_b)) ou use uma PK substituta e imponhaUNIQUE(fk_a, fk_b). - Se o relacionamento tiver atributos próprios (ex.: quantidade, preço negociado), eles ficam na tabela associativa.
Exemplo: Pedido (N) — (N) Produto → item_pedido com pedido_id, produto_id, quantidade, preco_unitario.
5) Relacionamento 1:1 → Estratégias alternativas
Relacionamentos 1:1 exigem escolha de estratégia. As mais comuns:
- FK em uma das tabelas + UNIQUE: coloque a FK em uma das tabelas e aplique
UNIQUEna FK para garantir 1:1. Útil quando uma entidade depende da outra ou quando há opcionalidade em apenas um lado. - Tabela única: mescle as duas entidades em uma tabela só (bom quando o 1:1 é total-total e não há muitos campos opcionais).
- Tabela separada com PK=FK: a tabela dependente usa a mesma chave do “dono” como PK e FK ao mesmo tempo. Excelente para “extensões” (ex.: dados raros/sensíveis).
Como decidir:
- Se uma parte é opcional e a outra é obrigatória, prefira FK no lado opcional.
- Se há muitos campos opcionais e raramente usados, prefira tabela separada (PK=FK).
- Se a separação existe só por organização e sempre existe, tabela única pode simplificar.
6) Atributos multivalorados → Tabelas separadas
Um atributo multivalorado (ex.: cliente tem vários telefones) vira uma tabela própria. Essa tabela contém a FK para a entidade “dona” e a coluna do valor (e possivelmente tipo/ordem).
Passo a passo:
- Crie tabela
cliente_telefone. - Inclua
cliente_idcomo FK. - Inclua
telefone(e opcionalmentetipo). - Defina PK composta (
cliente_id,telefone) ou PK substituta +UNIQUE.
7) Especialização/Generalização (quando aplicável)
Quando há uma superentidade e subentidades (ex.: Pessoa → Pessoa Física / Pessoa Jurídica), existem três estratégias clássicas no relacional:
- Tabela por hierarquia (single table): uma tabela com todas as colunas e um discriminador (ex.:
tipo_pessoa). Simples, mas pode gerar muitos NULLs. - Tabela por tipo (class table inheritance): uma tabela para a superentidade e uma para cada subentidade, onde a PK da subentidade também é FK para a superentidade (PK=FK). Preserva bem o modelo.
- Tabela por classe concreta: uma tabela para cada subentidade contendo também os atributos comuns. Evita joins, mas duplica colunas comuns.
Regras práticas:
- Se a especialização é grande e com muitos atributos específicos, use “tabela por tipo”.
- Se é pequena e o custo de joins é indesejado, “single table” pode ser aceitável com
CHECKbem definido.
Escolha de tipos de dados: critérios práticos
Identificadores (PK/FK)
- Inteiros (
INT/BIGINT): comuns para chaves substitutas. UseBIGINTse o volume pode ser muito alto. - UUID (
UUIDouCHAR(36)): útil para geração distribuída; maior custo de armazenamento/índice.
Textos
VARCHAR(n)para textos curtos com limite (nome, email).TEXTpara descrições longas (quando o SGBD suportar).- Defina tamanho com base em regra de negócio e dados reais; evite “255 por padrão” sem motivo.
Números e dinheiro
DECIMAL(p,s)para valores monetários (ex.:DECIMAL(10,2)).INTpara contagens/quantidades inteiras.
Datas e horários
DATEpara datas sem horário.TIMESTAMP/DATETIMEpara eventos com horário.
Booleanos e enums
BOOLEANquando o SGBD suportar.- Para status com conjunto fechado, prefira
VARCHAR+CHECK(portável) ou tipo enum nativo (dependente do SGBD).
Constraints: como transformar regras em garantias no banco
NOT NULL
Use quando o atributo é obrigatório. Em relacionamentos 1:N, a FK no lado N deve ser NOT NULL se o registro não pode existir sem o pai.
UNIQUE
Use para garantir unicidade de atributos candidatos (ex.: email) e para garantir 1:1 quando uma FK representa o vínculo exclusivo.
CHECK
Use para restringir domínio e validar regras simples no nível de linha.
- Faixas numéricas:
CHECK (quantidade > 0) - Conjunto de valores:
CHECK (status IN ('ABERTO','PAGO','CANCELADO')) - Regras condicionais simples:
CHECK (data_fim IS NULL OR data_fim >= data_inicio)
FOREIGN KEY e ações referenciais
Além de declarar a FK, escolha o comportamento em exclusões/atualizações:
ON DELETE RESTRICT/NO ACTION: impede apagar pai com filhos.ON DELETE CASCADE: apaga filhos junto (bom para entidades dependentes).ON DELETE SET NULL: desassocia (exige FK nullable).
Evite CASCADE quando a exclusão em cadeia pode apagar dados de negócio importantes sem intenção.
Exemplo completo (esquema lógico + dicionário de dados)
Mini-ER (descrição conceitual resumida)
- Entidades: Cliente, Pedido, Produto.
- Relacionamentos: Cliente 1:N Pedido; Pedido N:N Produto (com atributos quantidade e preço_unitário).
- Atributo multivalorado: Cliente possui Telefones (vários).
- Regra de domínio: Pedido.status ∈ {ABERTO, PAGO, CANCELADO}.
Script lógico (estrutura SQL)
-- Exemplo em SQL padrão (ajuste tipos/auto incremento conforme seu SGBD)CREATE TABLE cliente ( cliente_id BIGINT PRIMARY KEY, nome VARCHAR(120) NOT NULL, email VARCHAR(254) NOT NULL, documento VARCHAR(20) NOT NULL, data_cadastro TIMESTAMP NOT NULL, CONSTRAINT uq_cliente_email UNIQUE (email), CONSTRAINT uq_cliente_documento UNIQUE (documento));CREATE TABLE pedido ( pedido_id BIGINT PRIMARY KEY, cliente_id BIGINT NOT NULL, data_pedido TIMESTAMP NOT NULL, status VARCHAR(10) NOT NULL, valor_total DECIMAL(12,2) NOT NULL, CONSTRAINT fk_pedido_cliente FOREIGN KEY (cliente_id) REFERENCES cliente(cliente_id) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT ck_pedido_status CHECK (status IN ('ABERTO','PAGO','CANCELADO')), CONSTRAINT ck_pedido_valor_total CHECK (valor_total >= 0));CREATE TABLE produto ( produto_id BIGINT PRIMARY KEY, nome VARCHAR(150) NOT NULL, preco_atual DECIMAL(12,2) NOT NULL, ativo BOOLEAN NOT NULL, CONSTRAINT ck_produto_preco CHECK (preco_atual >= 0));CREATE TABLE item_pedido ( pedido_id BIGINT NOT NULL, produto_id BIGINT NOT NULL, quantidade INT NOT NULL, preco_unitario DECIMAL(12,2) NOT NULL, CONSTRAINT pk_item_pedido PRIMARY KEY (pedido_id, produto_id), CONSTRAINT fk_item_pedido_pedido FOREIGN KEY (pedido_id) REFERENCES pedido(pedido_id) ON DELETE CASCADE ON UPDATE RESTRICT, CONSTRAINT fk_item_pedido_produto FOREIGN KEY (produto_id) REFERENCES produto(produto_id) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT ck_item_quantidade CHECK (quantidade > 0), CONSTRAINT ck_item_preco_unitario CHECK (preco_unitario >= 0));CREATE TABLE cliente_telefone ( cliente_id BIGINT NOT NULL, telefone VARCHAR(20) NOT NULL, tipo VARCHAR(10) NOT NULL, CONSTRAINT pk_cliente_telefone PRIMARY KEY (cliente_id, telefone), CONSTRAINT fk_cliente_telefone_cliente FOREIGN KEY (cliente_id) REFERENCES cliente(cliente_id) ON DELETE CASCADE ON UPDATE RESTRICT, CONSTRAINT ck_cliente_telefone_tipo CHECK (tipo IN ('CELULAR','FIXO','COMERCIAL')));Dicionário de dados (tabelas e colunas)
| Tabela | Coluna | Tipo | Obrigatório | Constraints/Observações |
|---|---|---|---|---|
| cliente | cliente_id | BIGINT | Sim | PK |
| cliente | nome | VARCHAR(120) | Sim | Nome completo/razão social conforme regra do domínio |
| cliente | VARCHAR(254) | Sim | UNIQUE (uq_cliente_email) | |
| cliente | documento | VARCHAR(20) | Sim | UNIQUE (uq_cliente_documento); pode representar CPF/CNPJ/ID interno |
| cliente | data_cadastro | TIMESTAMP | Sim | Momento de criação do cliente |
| pedido | pedido_id | BIGINT | Sim | PK |
| pedido | cliente_id | BIGINT | Sim | FK → cliente(cliente_id); ON DELETE RESTRICT |
| pedido | data_pedido | TIMESTAMP | Sim | Data/hora do pedido |
| pedido | status | VARCHAR(10) | Sim | CHECK: ABERTO/PAGO/CANCELADO |
| pedido | valor_total | DECIMAL(12,2) | Sim | CHECK: valor_total >= 0 (pode ser calculado pela aplicação) |
| produto | produto_id | BIGINT | Sim | PK |
| produto | nome | VARCHAR(150) | Sim | Nome do produto |
| produto | preco_atual | DECIMAL(12,2) | Sim | CHECK: preco_atual >= 0 |
| produto | ativo | BOOLEAN | Sim | Indica disponibilidade |
| item_pedido | pedido_id | BIGINT | Sim | PK (composta) e FK → pedido; ON DELETE CASCADE |
| item_pedido | produto_id | BIGINT | Sim | PK (composta) e FK → produto |
| item_pedido | quantidade | INT | Sim | CHECK: quantidade > 0 |
| item_pedido | preco_unitario | DECIMAL(12,2) | Sim | CHECK: preco_unitario >= 0; preço no momento do pedido |
| cliente_telefone | cliente_id | BIGINT | Sim | PK (composta) e FK → cliente; ON DELETE CASCADE |
| cliente_telefone | telefone | VARCHAR(20) | Sim | PK (composta); formato pode ser validado na aplicação ou via CHECK avançado |
| cliente_telefone | tipo | VARCHAR(10) | Sim | CHECK: CELULAR/FIXO/COMERCIAL |