Modelo 1: E-Commerce Completo (Lojas Virtuais)
Modelagem clássica com Clientes, Endereços, Categorias, Produtos, Pedidos e Itens do Pedido. Demonstra o uso correto de VARCHAR, CHAR, DECIMAL(10,2), INT, ENUM e TIMESTAMP.
🔍 O que observar ao abrir este diagrama no DrawDB:
- ▸Observe por que `preco_unitario` existe tanto em `produtos` quanto em `itens_pedido` (histórico imutável: se o produto subir de preço amanhã, os pedidos antigos não podem mudar de valor!).
- ▸Repare no uso de `CHAR(11)` para CPF, `CHAR(8)` para CEP e `CHAR(2)` para UF.
- ▸Todas as chaves primárias e estrangeiras usam exatamente o mesmo tipo (`BIGINT UNSIGNED` ou `INT UNSIGNED`).
CREATE TABLE categorias (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
nome VARCHAR(80) NOT NULL,
slug VARCHAR(100) NOT NULL UNIQUE,
ativa BOOLEAN NOT NULL DEFAULT 1
);
CREATE TABLE produtos (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
categoria_id INT UNSIGNED NOT NULL,
nome VARCHAR(150) NOT NULL,
sku VARCHAR(40) NOT NULL UNIQUE,
descricao TEXT NULL,
preco_atual DECIMAL(10, 2) NOT NULL,
estoque_atual INT NOT NULL DEFAULT 0,
peso_kg DECIMAL(8, 3) NOT NULL DEFAULT 0.000,
ativo BOOLEAN NOT NULL DEFAULT 1,
criado_em TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_produtos_categoria FOREIGN KEY (categoria_id) REFERENCES categorias(id) ON DELETE RESTRICT
);
CREATE TABLE clientes (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
nome_completo VARCHAR(120) NOT NULL,
email VARCHAR(150) NOT NULL UNIQUE,
senha_hash VARCHAR(255) NOT NULL,
cpf CHAR(11) NOT NULL UNIQUE,
telefone VARCHAR(20) NULL,
data_nascimento DATE NULL,
criado_em TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE enderecos_cliente (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
cliente_id BIGINT UNSIGNED NOT NULL,
rotulo VARCHAR(40) NOT NULL COMMENT 'Ex: Casa, Trabalho',
cep CHAR(8) NOT NULL,
logradouro VARCHAR(150) NOT NULL,
numero VARCHAR(20) NOT NULL,
complemento VARCHAR(80) NULL,
bairro VARCHAR(80) NOT NULL,
cidade VARCHAR(80) NOT NULL,
uf CHAR(2) NOT NULL,
CONSTRAINT fk_enderecos_cliente FOREIGN KEY (cliente_id) REFERENCES clientes(id) ON DELETE CASCADE
);
CREATE TABLE pedidos (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
codigo_publico CHAR(36) NOT NULL UNIQUE,
cliente_id BIGINT UNSIGNED NOT NULL,
endereco_entrega_id BIGINT UNSIGNED NOT NULL,
status ENUM('aguardando_pagamento', 'pago', 'em_separacao', 'enviado', 'entregue', 'cancelado') NOT NULL DEFAULT 'aguardando_pagamento',
valor_produtos DECIMAL(10, 2) NOT NULL,
valor_frete DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
valor_desconto DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
valor_total DECIMAL(10, 2) NOT NULL,
criado_em TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_pedidos_cliente FOREIGN KEY (cliente_id) REFERENCES clientes(id) ON DELETE RESTRICT,
CONSTRAINT fk_pedidos_endereco FOREIGN KEY (endereco_entrega_id) REFERENCES enderecos_cliente(id) ON DELETE RESTRICT
);
CREATE TABLE itens_pedido (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
pedido_id BIGINT UNSIGNED NOT NULL,
produto_id INT UNSIGNED NOT NULL,
quantidade SMALLINT UNSIGNED NOT NULL DEFAULT 1,
preco_unitario_congelado DECIMAL(10, 2) NOT NULL,
subtotal DECIMAL(10, 2) NOT NULL,
CONSTRAINT fk_itens_pedido FOREIGN KEY (pedido_id) REFERENCES pedidos(id) ON DELETE CASCADE,
CONSTRAINT fk_itens_produto FOREIGN KEY (produto_id) REFERENCES produtos(id) ON DELETE RESTRICT
);
<?php
declare(strict_types=1);
// Exemplo Real: Criando um Pedido + Itens usando Transação Atômica (ACID) no PHP PDO
$pdo->beginTransaction();
try {
$stmtPedido = $pdo->prepare('
INSERT INTO pedidos (codigo_publico, cliente_id, endereco_entrega_id, valor_produtos, valor_frete, valor_total)
VALUES (:uuid, :cliente, :endereco, :v_prod, :v_frete, :v_total)
');
$stmtPedido->execute([
':uuid' => '550e8400-e29b-41d4-a716-446655440000',
':cliente' => 1,
':endereco' => 1,
':v_prod' => '299.80',
':v_frete' => '20.00',
':v_total' => '319.80',
]);
$pedidoId = (int) $pdo->lastInsertId();
$stmtItem = $pdo->prepare('
INSERT INTO itens_pedido (pedido_id, produto_id, quantidade, preco_unitario_congelado, subtotal)
VALUES (:pedido_id, :produto_id, :qtd, :preco, :subtotal)
');
$stmtItem->execute([
':pedido_id' => $pedidoId,
':produto_id' => 10,
':qtd' => 2,
':preco' => '149.90',
':subtotal' => '299.80',
]);
$pdo->commit();
} catch (Throwable $e) {
$pdo->rollBack();
throw $e;
}