Início / Trilha 1 / Conteúdo / Tópico 2
2

Modelagem de Dados (Entidade-Relacionamento)

Diagramas ER, entidades, atributos e relacionamentos

📖

Definição

O que é Modelagem de Dados?

Modelagem de dados é o processo de criar uma representação visual e lógica das estruturas de dados de um sistema. O Diagrama Entidade-Relacionamento (DER ou ERD) é a ferramenta mais utilizada para essa tarefa.

O modelo ER foi proposto por Peter Chen em 1976 e se tornou o padrão da indústria para projetar bancos de dados relacionais. Ele permite visualizar como os dados se organizam antes de criar as tabelas físicas no banco.

Níveis de Abstração:

1
Modelo Conceitual

Visão de alto nível, foco no negócio. Independente de tecnologia.

2
Modelo Lógico

Define tabelas, colunas, tipos de dados e relacionamentos.

3
Modelo Físico

Específico do SGBD (Oracle), inclui índices, partições, tablespaces.

Componentes do Modelo ER

Entidades

Representam objetos do mundo real sobre os quais queremos armazenar informações.

  • CLIENTE, PRODUTO, PEDIDO
  • FUNCIONARIO, DEPARTAMENTO
  • Representadas por retângulos

Atributos

São as características ou propriedades de uma entidade.

  • Cliente: nome, cpf, email
  • Produto: codigo, descricao, preco
  • Representados por elipses

Relacionamentos

Definem como as entidades se conectam entre si.

  • Cliente FAZ Pedido
  • Funcionário TRABALHA_EM Departamento
  • Representados por losangos

Cardinalidade

Define a quantidade de instâncias em um relacionamento.

  • 1:1 - Um para um
  • 1:N - Um para muitos
  • N:N - Muitos para muitos

Tipos de Cardinalidade em Detalhe

1:1 (Um para Um)

Uma instância de A se relaciona com no máximo uma instância de B, e vice-versa.

FUNCIONARIO ────── 1:1 ────── CRACHA

Cada funcionário tem exatamente um crachá, cada crachá pertence a um funcionário.

1:N (Um para Muitos)

Uma instância de A pode se relacionar com várias instâncias de B.

DEPARTAMENTO ────── 1:N ────── FUNCIONARIO

Um departamento tem vários funcionários, cada funcionário pertence a um departamento.

N:N (Muitos para Muitos)

Várias instâncias de A podem se relacionar com várias instâncias de B.

ALUNO ────── N:N ────── DISCIPLINA

Um aluno cursa várias disciplinas, uma disciplina tem vários alunos.

Importante: Relacionamentos N:N requerem uma tabela associativa no modelo físico!

🛠️

Aplicação Prática

Caso Prático: Sistema de E-commerce

Vamos modelar um sistema de e-commerce simples, partindo dos requisitos até o modelo físico no Oracle.

Requisitos de Negócio:

  • Clientes podem fazer vários pedidos
  • Cada pedido pertence a um único cliente
  • Um pedido contém vários produtos
  • Cada produto pode estar em vários pedidos
  • Produtos são organizados em categorias
  • Uma categoria pode ter várias subcategorias

Entidades Identificadas:

CLIENTE PEDIDO PRODUTO CATEGORIA ITEM_PEDIDO (associativa)

Relacionamentos:

  • CLIENTE 1:N PEDIDO (um cliente faz vários pedidos)
  • PEDIDO N:N PRODUTO (via ITEM_PEDIDO)
  • CATEGORIA 1:N PRODUTO (uma categoria tem vários produtos)
  • CATEGORIA 1:N CATEGORIA (autorelacionamento para subcategorias)

Do Modelo ER para o Modelo Físico (Oracle)

-- Tabela de Categorias (com autorelacionamento para hierarquia)
CREATE TABLE categorias (
    id_categoria      NUMBER(10)    PRIMARY KEY,
    nome              VARCHAR2(100) NOT NULL,
    descricao         VARCHAR2(500),
    categoria_pai_id  NUMBER(10)    REFERENCES categorias(id_categoria),
    ativo             CHAR(1)       DEFAULT 'S' CHECK (ativo IN ('S', 'N'))
);

-- Tabela de Clientes
CREATE TABLE clientes (
    id_cliente    NUMBER(10)    PRIMARY KEY,
    nome          VARCHAR2(150) NOT NULL,
    cpf           CHAR(11)      UNIQUE NOT NULL,
    email         VARCHAR2(100) UNIQUE NOT NULL,
    telefone      VARCHAR2(15),
    data_cadastro DATE          DEFAULT SYSDATE,
    status        VARCHAR2(20)  DEFAULT 'ATIVO' CHECK (status IN ('ATIVO', 'INATIVO', 'BLOQUEADO'))
);

-- Tabela de Produtos
CREATE TABLE produtos (
    id_produto    NUMBER(10)    PRIMARY KEY,
    codigo_sku    VARCHAR2(50)  UNIQUE NOT NULL,
    nome          VARCHAR2(200) NOT NULL,
    descricao     CLOB,
    preco         NUMBER(10,2)  NOT NULL CHECK (preco > 0),
    estoque       NUMBER(10)    DEFAULT 0,
    categoria_id  NUMBER(10)    NOT NULL REFERENCES categorias(id_categoria),
    data_cadastro DATE          DEFAULT SYSDATE,
    ativo         CHAR(1)       DEFAULT 'S' CHECK (ativo IN ('S', 'N'))
);

-- Tabela de Pedidos
CREATE TABLE pedidos (
    id_pedido       NUMBER(10)    PRIMARY KEY,
    cliente_id      NUMBER(10)    NOT NULL REFERENCES clientes(id_cliente),
    data_pedido     TIMESTAMP     DEFAULT SYSTIMESTAMP,
    status          VARCHAR2(20)  DEFAULT 'PENDENTE'
                    CHECK (status IN ('PENDENTE', 'CONFIRMADO', 'ENVIADO', 'ENTREGUE', 'CANCELADO')),
    valor_total     NUMBER(12,2),
    endereco_entrega VARCHAR2(500)
);

-- Tabela Associativa: Itens do Pedido (resolve relacionamento N:N)
CREATE TABLE itens_pedido (
    id_pedido     NUMBER(10)   REFERENCES pedidos(id_pedido),
    id_produto    NUMBER(10)   REFERENCES produtos(id_produto),
    quantidade    NUMBER(10)   NOT NULL CHECK (quantidade > 0),
    preco_unitario NUMBER(10,2) NOT NULL,
    desconto      NUMBER(5,2)  DEFAULT 0,
    PRIMARY KEY (id_pedido, id_produto)
);

-- Índices para melhorar performance
CREATE INDEX idx_pedidos_cliente ON pedidos(cliente_id);
CREATE INDEX idx_pedidos_data ON pedidos(data_pedido);
CREATE INDEX idx_produtos_categoria ON produtos(categoria_id);
CREATE INDEX idx_itens_produto ON itens_pedido(id_produto);

-- Comentários nas tabelas (documentação)
COMMENT ON TABLE clientes IS 'Cadastro de clientes do e-commerce';
COMMENT ON COLUMN clientes.cpf IS 'CPF do cliente sem formatação';
COMMENT ON TABLE itens_pedido IS 'Tabela associativa entre pedidos e produtos';

Normalização: As 3 Formas Normais

1ª Forma Normal (1FN)

Eliminar grupos repetitivos - cada célula deve conter apenas um valor atômico.

❌ Errado: telefone = "11999999999, 11888888888"
✓ Correto: Criar tabela TELEFONES_CLIENTE separada

2ª Forma Normal (2FN)

Eliminar dependências parciais - atributos devem depender de toda a chave primária.

❌ Errado: ITEM_PEDIDO com nome_produto (depende só de id_produto)
✓ Correto: nome_produto fica na tabela PRODUTOS

3ª Forma Normal (3FN)

Eliminar dependências transitivas - atributos não-chave não devem depender de outros atributos não-chave.

❌ Errado: FUNCIONARIO com cidade e estado (estado depende de cidade)
✓ Correto: Criar tabela CIDADES com cidade_id, nome, estado

Resultado Esperado

O que você deve dominar após este tópico:

Ler diagramas ER

Interpretar modelos existentes de qualquer sistema

Identificar entidades e atributos

Extrair requisitos de negócio para modelo de dados

Definir cardinalidades

Escolher 1:1, 1:N ou N:N corretamente

Converter ER para SQL

Transformar modelo lógico em CREATE TABLE

Aplicar normalização

Eliminar redundâncias até 3FN

Usar ferramentas

Conhecer Oracle SQL Developer Data Modeler

📝

Exercícios Práticos

Exercício 1: Identificar Cardinalidades

Determine a cardinalidade correta para os seguintes relacionamentos:

  1. AUTOR e LIVRO (um autor pode escrever vários livros, um livro pode ter vários autores)
  2. PAIS e ESTADO (um país tem vários estados, um estado pertence a um país)
  3. PESSOA e RG (cada pessoa tem um RG único)
  4. MEDICO e PACIENTE (um médico atende vários pacientes, um paciente consulta vários médicos)
Ver Solução
  1. N:N - Requer tabela associativa AUTOR_LIVRO
  2. 1:N - FK país_id na tabela ESTADO
  3. 1:1 - Pode ser FK em PESSOA ou tabela separada RG
  4. N:N - Requer tabela associativa CONSULTAS

Exercício 2: Modelar Sistema de Biblioteca

Crie o modelo físico (CREATE TABLE) para uma biblioteca com:

  • Livros (podem ter múltiplos exemplares)
  • Autores (um livro pode ter vários autores)
  • Usuários (leitores)
  • Empréstimos (controle de quem pegou qual exemplar)
Ver Solução
-- Autores
CREATE TABLE autores (
    id_autor  NUMBER PRIMARY KEY,
    nome      VARCHAR2(150) NOT NULL,
    pais      VARCHAR2(50)
);

-- Livros
CREATE TABLE livros (
    id_livro  NUMBER PRIMARY KEY,
    isbn      VARCHAR2(20) UNIQUE NOT NULL,
    titulo    VARCHAR2(300) NOT NULL,
    editora   VARCHAR2(100),
    ano_pub   NUMBER(4)
);

-- Relacionamento N:N entre Livros e Autores
CREATE TABLE livros_autores (
    id_livro  NUMBER REFERENCES livros(id_livro),
    id_autor  NUMBER REFERENCES autores(id_autor),
    PRIMARY KEY (id_livro, id_autor)
);

-- Exemplares (cada livro pode ter vários exemplares)
CREATE TABLE exemplares (
    id_exemplar NUMBER PRIMARY KEY,
    id_livro    NUMBER NOT NULL REFERENCES livros(id_livro),
    codigo      VARCHAR2(20) UNIQUE NOT NULL,
    status      VARCHAR2(20) DEFAULT 'DISPONIVEL'
                CHECK (status IN ('DISPONIVEL', 'EMPRESTADO', 'MANUTENCAO'))
);

-- Usuários
CREATE TABLE usuarios (
    id_usuario  NUMBER PRIMARY KEY,
    nome        VARCHAR2(150) NOT NULL,
    email       VARCHAR2(100) UNIQUE NOT NULL,
    telefone    VARCHAR2(15)
);

-- Empréstimos
CREATE TABLE emprestimos (
    id_emprestimo   NUMBER PRIMARY KEY,
    id_exemplar     NUMBER NOT NULL REFERENCES exemplares(id_exemplar),
    id_usuario      NUMBER NOT NULL REFERENCES usuarios(id_usuario),
    data_emprestimo DATE DEFAULT SYSDATE,
    data_prevista   DATE NOT NULL,
    data_devolucao  DATE
);

Exercício 3: Normalização

A tabela abaixo está desnormalizada. Normalize-a até a 3ª Forma Normal:

CREATE TABLE vendas (
    id_venda          NUMBER,
    data_venda        DATE,
    vendedor_nome     VARCHAR2(100),
    vendedor_cpf      VARCHAR2(14),
    vendedor_depto    VARCHAR2(50),
    depto_gerente     VARCHAR2(100),
    produto_codigo    VARCHAR2(20),
    produto_nome      VARCHAR2(100),
    produto_categoria VARCHAR2(50),
    quantidade        NUMBER,
    preco_unitario    NUMBER
);
Ver Solução
-- Departamentos (3FN: gerente não depende da venda)
CREATE TABLE departamentos (
    id_depto   NUMBER PRIMARY KEY,
    nome       VARCHAR2(50) NOT NULL,
    gerente    VARCHAR2(100)
);

-- Vendedores (2FN: dados do vendedor em tabela própria)
CREATE TABLE vendedores (
    id_vendedor NUMBER PRIMARY KEY,
    nome        VARCHAR2(100) NOT NULL,
    cpf         VARCHAR2(14) UNIQUE NOT NULL,
    id_depto    NUMBER REFERENCES departamentos(id_depto)
);

-- Categorias (3FN: categoria independente)
CREATE TABLE categorias (
    id_categoria NUMBER PRIMARY KEY,
    nome         VARCHAR2(50) NOT NULL
);

-- Produtos (2FN: dados do produto separados)
CREATE TABLE produtos (
    id_produto   NUMBER PRIMARY KEY,
    codigo       VARCHAR2(20) UNIQUE NOT NULL,
    nome         VARCHAR2(100) NOT NULL,
    id_categoria NUMBER REFERENCES categorias(id_categoria)
);

-- Vendas (tabela principal limpa)
CREATE TABLE vendas (
    id_venda     NUMBER PRIMARY KEY,
    data_venda   DATE DEFAULT SYSDATE,
    id_vendedor  NUMBER REFERENCES vendedores(id_vendedor)
);

-- Itens da Venda (resolve N:N e armazena preço histórico)
CREATE TABLE itens_venda (
    id_venda       NUMBER REFERENCES vendas(id_venda),
    id_produto     NUMBER REFERENCES produtos(id_produto),
    quantidade     NUMBER NOT NULL,
    preco_unitario NUMBER NOT NULL,
    PRIMARY KEY (id_venda, id_produto)
);
Anterior: BD Relacional Próximo: SQL Developer e SQL*Plus