flowchart LR
A[Modelo Conceitual - DER] --> B[Modelo Logico - Relacional]
B --> C[Modelo Fisico - SGBD especifico]
A -. independente de tecnologia .-> A
B -. independente de SGBD .-> B
C -. dependente do SGBD .-> C
Modelagem Lógica: mapeamento do modelo ER para o relacional
Quero começar este módulo te situando exatamente onde estamos na jornada do projeto de um banco de dados, porque é justamente esse “lugar no mapa” que costuma render questão de prova. Nos módulos anteriores você desenhou o modelo conceitual: aquele Diagrama Entidade-Relacionamento (DER) cheio de retângulos, losangos e linhas, que conversa com o usuário de negócio e ignora deliberadamente qualquer detalhe de implementação. Agora vamos descer um degrau de abstração. A modelagem lógica é a etapa em que pego aquele desenho conceitual e o traduzo para o modelo de dados de um paradigma específico — no nosso caso, o modelo relacional, feito de tabelas, colunas, chaves primárias e chaves estrangeiras. Repare comigo: ainda não escolhemos o SGBD (PostgreSQL, Oracle, SQL Server), ainda não pensamos em índices, tablespaces ou tipos físicos de armazenamento. Isso fica para a modelagem física. A lógica é a ponte intermediária, e dominá-la é o que separa quem “sabe desenhar DER” de quem realmente sabe construir bancos de dados.
Vou te mostrar o panorama das três camadas para fixar a posição.
Definição. A modelagem lógica é o processo de mapear um modelo conceitual (DER) para as estruturas de um modelo de dados específico — aqui, o relacional — produzindo um esquema composto de tabelas, colunas, chaves e restrições, ainda sem comprometer-se com detalhes físicos de um SGBD particular.
Por que essa etapa cai em prova
Antes de entrar nas regras mecânicas, deixa eu te convencer de que essa etapa não é burocracia. A modelagem lógica refina o conceitual, transformando conceitos abstratos em estruturas concretas e, nesse caminho, expõe ambiguidades que ficavam escondidas no DER. Ela garante independência de SGBD: o mesmo modelo lógico pode ser implementado em PostgreSQL ou em Oracle com poucos ajustes. Ela é o ponto onde aplico normalização para reduzir redundância — assunto que aprofundaremos no módulo de Normalização — e onde defino as restrições de integridade que manterão os dados consistentes. E, não menos importante, ela serve como documentação e como linguagem comum entre analistas, projetistas e desenvolvedores. Quando a prova pergunta “qual o papel do modelo lógico”, é esse conjunto de funções que ela espera ver: refinamento, independência tecnológica, otimização estrutural, integridade e documentação.
Vou abrir um pouco mais cada uma dessas funções, porque elas costumam aparecer fragmentadas em alternativas de prova. O refinamento do conceitual significa que, ao traduzir, sou obrigado a tomar decisões que o DER permitia adiar: que atributo será chave primária, como um atributo composto se decompõe, se um relacionamento opcional aceita nulo. Cada uma dessas decisões fecha uma lacuna. A independência de SGBD é o que dá portabilidade ao projeto: como ainda não escolhi tipos físicos nem recursos proprietários, o mesmo esquema lógico sobrevive a uma troca de fornecedor. A otimização estrutural, via normalização, ataca a redundância na origem, evitando que o mesmo dado apareça repetido em vários lugares e gere anomalias de inserção, atualização e exclusão. A integridade, por sua vez, transforma regras de negócio em restrições verificáveis pelo próprio banco, e não em promessas que dependem da disciplina do programador. E a documentação consolida tudo isso num artefato que sobrevive à rotatividade da equipe. Quando você enxerga essas cinco funções como um conjunto, fica fácil reconhecê-las isoladas numa questão.
O processo, na prática, segue um roteiro que vou destrinchar ao longo do módulo. Olhe o fluxo geral:
flowchart TD
A[Analisar modelo conceitual] --> B[Mapear entidades para tabelas]
B --> C[Mapear atributos para colunas]
C --> D[Definir chaves primarias]
D --> E[Mapear relacionamentos]
E --> F[Tratar entidades fracas]
F --> G[Tratar generalizacao especializacao]
G --> H[Definir restricoes]
H --> I[Normalizar e refinar]
I --> J[Validar e documentar]
Regra 1 — Entidades viram tabelas, atributos viram colunas
A regra mais elementar do mapeamento é direta: cada entidade do DER se transforma em uma tabela, cada atributo da entidade vira uma coluna dessa tabela, e o identificador da entidade vira a chave primária. Vou usar como fio condutor um sistema de biblioteca, que carregaremos pelo módulo inteiro. Suponha a entidade Livro com os atributos ISBN (identificador), título, ano de publicação e número de páginas. O mapeamento produz:
Note que já apareceu uma decisão de projeto: escolhi o ISBN como chave primária porque ele identifica unicamente cada livro. Quando uma entidade não tem um identificador natural confiável, é comum introduzir uma chave substituta (uma surrogate key), tipicamente uma coluna numérica autoincrementada. Veja a entidade Usuario, que poderia até ter CPF, mas onde prefiro uma chave artificial por simplicidade e estabilidade:
Repare que mantive o CPF na tabela, mas como chave candidata marcada com UNIQUE, não como chave primária. Essa distinção entre chave primária e chave candidata é exatamente o tipo de detalhe que a modelagem lógica formaliza.
Atributos que não mapeiam direto
Nem todo atributo do DER vira uma coluna simples. Há três casos especiais que você precisa reconhecer de imediato. O atributo composto — como um endereço formado por rua, número, cidade e CEP — normalmente é decomposto em várias colunas atômicas, porque o modelo relacional, na Primeira Forma Normal, exige valores atômicos. O atributo multivalorado — como vários telefones de um mesmo usuário — não cabe em uma única coluna; ele exige uma tabela própria, ligada por chave estrangeira à entidade original. E o atributo derivado — como a idade, calculável a partir da data de nascimento — geralmente não é armazenado, sendo computado quando necessário. Veja o tratamento do multivalorado:
Atenção. Um atributo multivalorado nunca deve virar uma coluna do tipo “telefone1, telefone2, telefone3”. Isso viola a Primeira Forma Normal e engessa o modelo. A solução correta é sempre uma tabela separada com chave estrangeira de volta à entidade dona.
Regra 2 — Relacionamentos um-para-um
Agora entramos no coração da modelagem lógica: a tradução de relacionamentos. O modelo relacional não tem “losangos”; ele expressa associações por meio de chaves estrangeiras e, quando necessário, de tabelas próprias. A estratégia muda conforme a cardinalidade.
Comecemos pelo um-para-um (1:1). Imagine que cada usuário possui no máximo um cartão de matrícula, e cada cartão pertence a um único usuário. Há três abordagens possíveis, e a escolha depende da obrigatoriedade da participação. A mais comum, quando um dos lados é opcional, é colocar a chave estrangeira do lado obrigatório dentro da tabela do lado opcional, marcando-a como UNIQUE para garantir a cardinalidade máxima de um:
O UNIQUE sobre id_usuario é o detalhe decisivo: sem ele, eu teria um relacionamento um-para-muitos disfarçado, pois nada impediria dois cartões apontarem para o mesmo usuário. É esse pequeno detalhe que faz a cardinalidade máxima de um ser respeitada pelo banco. Quando os dois lados são obrigatórios e fortemente acoplados — quando um nunca existe sem o outro — uma alternativa elegante é fundir as duas entidades em uma única tabela, evitando uma junção permanente e um relacionamento que nunca traria nulos. Já se a participação for opcional dos dois lados, a chave estrangeira pode ir para qualquer um dos lados; nesse caso, escolho o lado que torna as consultas mais frequentes mais simples, ou, em situações de baixo acoplamento, crio uma terceira tabela só com o par de chaves. Perceba que, ao contrário do 1:N, no 1:1 a posição da chave estrangeira é uma decisão de projeto com mais de uma resposta correta, guiada pela obrigatoriedade e pelo padrão de acesso. Vamos visualizar:
erDiagram
USUARIO ||--o| CARTAO : possui
USUARIO {
int id_usuario PK
string nome
}
CARTAO {
int id_cartao PK
int id_usuario FK
string codigo
}
Regra 3 — Relacionamentos um-para-muitos
O relacionamento um-para-muitos (1:N) é o mais frequente e o mais simples de mapear, então preste bastante atenção porque ele é a base de tudo. A regra é uma só: a chave primária do lado “um” é replicada como chave estrangeira na tabela do lado “muitos”. Pense em editoras e livros — uma editora publica muitos livros, e cada livro pertence a uma única editora. O “um” é a editora; o “muitos” é o livro. Logo, a chave da editora desce para a tabela livro:
Quero que você internalize a lógica por trás disso, não apenas a mecânica. A chave estrangeira vai sempre para o lado “muitos” porque cada linha desse lado se associa a no máximo um registro do outro. Se eu tentasse o contrário — guardar uma lista de livros dentro da editora — cairia de novo no problema do multivalorado. Colocar a chave no lado “muitos” mantém cada coluna atômica e o relacionamento limpo.
Há ainda uma decisão fina que distingue o bom modelador: a obrigatoriedade da participação. Se todo livro precisa obrigatoriamente ter uma editora, então a coluna id_editora deve ser NOT NULL, e o banco passa a recusar qualquer livro órfão. Se, ao contrário, um livro pode existir temporariamente sem editora cadastrada, a coluna aceita nulo e a participação é opcional. Essa diferença entre cardinalidade mínima zero e um, que no DER aparecia como uma bolinha ou um traço na linha do relacionamento, agora vira uma cláusula concreta no CREATE TABLE. É exatamente esse tipo de tradução fiel — do símbolo conceitual para a restrição executável — que dá valor à etapa lógica.
erDiagram
EDITORA ||--o{ LIVRO : publica
EDITORA {
int id_editora PK
string nome
}
LIVRO {
string isbn PK
int id_editora FK
string titulo
}
Síntese da regra 1:N. A chave primária do lado “um” entra como chave estrangeira na tabela do lado “muitos”. Se a participação do lado “muitos” for obrigatória, marque a chave estrangeira como NOT NULL; se for opcional, permita nulo.
Regra 4 — Relacionamentos muitos-para-muitos e a tabela associativa
Chegamos ao caso que mais derruba estudante desatento. No relacionamento muitos-para-muitos (N:M), nenhuma das duas tabelas pode hospedar a chave estrangeira da outra, porque cada lado se associa a vários do outro. Pense em empréstimos: um usuário pega muitos livros ao longo do tempo, e um mesmo livro é emprestado a muitos usuários. Não dá para guardar a chave do livro na tabela de usuário nem o contrário. A solução é criar uma tabela associativa (também chamada de tabela de junção, de ligação ou bridge table), que decompõe o N:M em dois relacionamentos 1:N.
Essa tabela nova recebe as chaves primárias das duas entidades como chaves estrangeiras, e a combinação delas costuma formar a chave primária composta. O ponto que muita gente ignora: a tabela associativa é o lugar natural dos atributos do próprio relacionamento. A data do empréstimo e a data de devolução não pertencem ao usuário nem ao livro — pertencem ao ato de emprestar. Veja:
Observe que incluí data_emprestimo na chave primária. Sem ela, o mesmo usuário jamais poderia pegar o mesmo livro duas vezes em datas diferentes — o que seria um erro de modelagem. Esse refinamento da chave da tabela associativa, conforme as regras de negócio, é típico da etapa lógica. Quando o relacionamento tem identidade própria forte, é comum até introduzir uma chave substituta id_emprestimo SERIAL e tratar o par como UNIQUE.
erDiagram
USUARIO ||--o{ EMPRESTIMO : realiza
LIVRO ||--o{ EMPRESTIMO : consta_em
EMPRESTIMO {
int id_usuario PK
string isbn PK
date data_emprestimo PK
date data_devolucao
}
Para você não esquecer o critério de decisão, montei uma tabela-resumo dos três tipos de mapeamento de cardinalidade.
| Cardinalidade | Estratégia de mapeamento | Onde vai a chave estrangeira |
|---|---|---|
| 1:1 | FK com UNIQUE (ou fusão de tabelas) |
No lado opcional, ou em qualquer lado |
| 1:N | FK simples | Sempre no lado “muitos” |
| N:M | Tabela associativa | Nas duas FKs, compondo a PK |
Regra 5 — Entidades fracas
Uma entidade fraca é aquela que não tem existência própria nem identificador suficiente sozinha: ela depende de uma entidade forte para ser identificada. O exemplo clássico é a dependência de um item de pedido em relação ao pedido, ou, no nosso domínio, os exemplares físicos de um livro. Um exemplar não faz sentido sem o livro a que pertence, e seu número de tombo só é único dentro daquele livro. No mapeamento lógico, a tabela da entidade fraca recebe a chave primária da entidade forte como parte de sua própria chave primária — uma chave composta pela chave da forte mais o discriminador parcial da fraca:
A diferença em relação a um 1:N comum é sutil mas importante para a prova: na entidade fraca, a chave estrangeira participa da chave primária, refletindo a dependência de identificação. Em um 1:N comum, a chave estrangeira é apenas um atributo a mais, fora da chave primária. Vou tornar isso visível com um contraste: se eu modelasse exemplar com uma chave artificial própria id_exemplar SERIAL PRIMARY KEY e apenas uma FK simples para o livro, eu teria tratado o exemplar como entidade forte, e o número do exemplar deixaria de depender do livro. A modelagem como fraca é uma escolha que preserva a semântica original do DER: o exemplar 3 do livro A é coisa distinta do exemplar 3 do livro B, e só a chave composta captura isso. Na prática, muitos projetistas optam pela chave artificial por conveniência de implementação, mas você precisa saber que, no plano lógico estrito, a entidade fraca pede chave composta herdada.
Atenção à diferença. Em um relacionamento 1:N normal, a FK fica fora da PK. Numa entidade fraca, a FK da entidade forte entra dentro da PK composta. Confundir os dois é erro comum em questões discursivas.
Regra 6 — Generalização e especialização
Quando o DER traz hierarquias de herança — uma entidade genérica Pessoa especializada em Aluno e Professor, por exemplo — o modelo relacional, que não conhece herança nativa, oferece três estratégias de mapeamento. Vou te apresentar as três, porque a escolha entre elas é matéria recorrente de prova e cada uma tem um trade-off claro.
A primeira estratégia é a tabela única (single table): uma só tabela reúne a superclasse e todas as subclasses, com uma coluna discriminadora indicando o tipo e colunas específicas que ficam nulas quando não se aplicam.
A segunda é a tabela por classe concreta: cada subclasse vira sua própria tabela, repetindo os atributos da superclasse, e a superclasse não tem tabela.
A terceira, e mais normalizada, é a tabela por tipo (class table inheritance): a superclasse vira uma tabela, cada subclasse vira outra tabela cuja chave primária é também chave estrangeira para a superclasse, num relacionamento 1:1.
CREATE TABLE pessoa (
id_pessoa SERIAL PRIMARY KEY,
nome VARCHAR(120) NOT NULL
);
CREATE TABLE aluno (
id_pessoa INTEGER PRIMARY KEY REFERENCES pessoa (id_pessoa),
matricula VARCHAR(20) NOT NULL
);
CREATE TABLE professor (
id_pessoa INTEGER PRIMARY KEY REFERENCES pessoa (id_pessoa),
titulacao VARCHAR(40)
);A escolha entre as três não é arbitrária; ela depende de quanto as subclasses divergem e de como você vai consultar os dados. Se as subclasses têm poucos atributos próprios e você consulta frequentemente todas as pessoas juntas, a tabela única vence pela simplicidade, ainda que ao custo de colunas nulas e de uma integridade mais frouxa — afinal, nada na estrutura impede que um aluno tenha titulação preenchida por engano, restando apenas a cláusula CHECK para mitigar. Se as subclasses são muito distintas e raramente consultadas em conjunto, a tabela por classe concreta isola bem cada tipo, mas duplica os atributos comuns e dificulta perguntas globais do tipo “todas as pessoas da instituição”. Se a prioridade é fidelidade ao modelo e ausência de redundância, a tabela por tipo é a mais correta teoricamente, pagando o preço de junções para reconstituir uma entidade completa. Não existe vencedora absoluta; existe a adequada ao caso. Compare comigo os trade-offs antes de decidir:
| Estratégia | Vantagem | Desvantagem |
|---|---|---|
| Tabela única | Consultas simples, sem junções | Muitas colunas nulas, integridade fraca |
| Tabela por classe concreta | Sem nulos, cada tipo isolado | Atributos comuns duplicados, consultas globais difíceis |
| Tabela por tipo | Normalizada, sem redundância | Exige junções para reconstituir o objeto |
flowchart TD
P[Pessoa - superclasse] --> A[Aluno]
P --> Pr[Professor]
A -. herda atributos .-> P
Pr -. herda atributos .-> P
Regra 7 — Definição de restrições
Mapear estruturas é metade do trabalho; a outra metade é blindar o esquema com restrições que garantam a integridade. Na modelagem lógica eu defino formalmente a integridade de entidade (toda tabela tem chave primária, e nenhuma parte dela pode ser nula), a integridade referencial (toda chave estrangeira aponta para uma chave primária existente ou é nula) e as restrições de domínio (cada coluna só aceita valores válidos). É aqui que decido também o comportamento das chaves estrangeiras em cascata. Veja um exemplo consolidando várias restrições:
CREATE TABLE reserva (
id_reserva SERIAL PRIMARY KEY,
id_usuario INTEGER NOT NULL,
isbn VARCHAR(13) NOT NULL,
data_reserva DATE NOT NULL DEFAULT CURRENT_DATE,
status VARCHAR(15) NOT NULL DEFAULT 'ativa'
CHECK (status IN ('ativa','atendida','cancelada')),
CONSTRAINT fk_reserva_usuario
FOREIGN KEY (id_usuario) REFERENCES usuario (id_usuario)
ON DELETE CASCADE,
CONSTRAINT fk_reserva_livro
FOREIGN KEY (isbn) REFERENCES livro (isbn)
ON DELETE RESTRICT,
CONSTRAINT uq_reserva UNIQUE (id_usuario, isbn, data_reserva)
);Repare nas decisões: o ON DELETE CASCADE na FK do usuário significa que apagar um usuário apaga suas reservas; já o ON DELETE RESTRICT na FK do livro impede apagar um livro que ainda tenha reservas. Essas escolhas de propagação são parte legítima do modelo lógico, pois expressam regras de negócio sobre a vida dos dados. A integridade referencial pode ser visualizada como um grafo de dependências entre tabelas:
flowchart LR
RESERVA --> USUARIO
RESERVA --> LIVRO
EMPRESTIMO --> USUARIO
EMPRESTIMO --> LIVRO
EXEMPLAR --> LIVRO
LIVRO --> EDITORA
TELEFONE_USUARIO --> USUARIO
Definição. A integridade referencial é a propriedade que garante que todo valor de chave estrangeira corresponda a um valor existente da chave primária referenciada, ou seja nulo. Formalmente, para uma FK F sobre a relação R referenciando a chave K de S, exige-se que \pi_F(R) \subseteq \pi_K(S) \cup \{\text{nulo}\}.
Refinamento, normalização e validação
Com o esquema rascunhado, entra a fase iterativa. A normalização, que trataremos em profundidade no módulo próprio, decompõe tabelas para eliminar redundância e anomalias de atualização, levando o modelo às formas normais. No refinamento, reviso se cada tabela atende aos requisitos, ajusto tipos, reconsidero chaves e às vezes faço uma desnormalização controlada por desempenho — sempre uma decisão consciente, não um descuido. A validação confronta o modelo com os stakeholders e com os casos de uso reais: consigo, com este esquema, responder a todas as consultas que o negócio precisa? Toda regra de negócio está garantida por alguma restrição? Por fim, a documentação registra o dicionário de dados — tabelas, colunas, tipos, restrições — e as justificativas de cada decisão de projeto, transformando o modelo em conhecimento transmissível.
Vale insistir num ponto que a fonte enfatiza: o processo é iterativo. Você raramente acerta o modelo lógico de primeira. Cada validação revela um requisito esquecido, cada normalização sugere uma nova decomposição, e o ciclo recomeça até a estabilidade.
Síntese para a prova. Guarde antes de tudo o roteiro de mapeamento: entidade vira tabela, atributo vira coluna, identificador vira chave primária. Para relacionamentos, fixe o critério por cardinalidade — 1:1 resolve-se com chave estrangeira marcada UNIQUE ou fusão de tabelas; 1:N coloca a chave do lado “um” como chave estrangeira no lado “muitos”; N:M sempre exige tabela associativa que recebe as duas chaves e hospeda os atributos do relacionamento. Lembre que entidade fraca herda a chave da entidade forte dentro de sua chave primária composta, o que a distingue de um 1:N comum. Para generalização e especialização, saiba descrever as três estratégias — tabela única, tabela por classe concreta e tabela por tipo — com seus trade-offs entre junções e nulos. Não esqueça as três integridades — de entidade, referencial e de domínio — nem o papel das ações ON DELETE. E tenha sempre na ponta da língua o lugar da modelagem lógica: a ponte entre o conceitual independente de tecnologia e o físico dependente do SGBD, com refinamento, normalização, validação e documentação fechando o ciclo iterativo.