Construtor Interativo de Tabela (DrawDB + PHP PDO)
Escolha o nome da tabela e marque os campos que você precisa. O PHP gerará automaticamente o script SQL DDL (pronto para colar em Import > SQL no DrawDB) e o código PHP 8 + PDO com os tipos de bind corretos!
CREATE TABLE clientes_loja (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
uuid CHAR(36) NOT NULL UNIQUE,
nome VARCHAR(120) NOT NULL,
email VARCHAR(150) NOT NULL UNIQUE,
cpf CHAR(11) NOT NULL UNIQUE,
preco DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
ativo BOOLEAN NOT NULL DEFAULT 1,
criado_em TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
<?php
declare(strict_types=1);
// Inserindo na tabela `clientes_loja` com Prepared Statement PDO
$stmt = $pdo->prepare('
INSERT INTO clientes_loja (uuid, nome, email, cpf, preco, ativo)
VALUES (:uuid, :nome, :email, :cpf, :preco, :ativo)
');
$stmt->bindValue(':uuid', '550e8400-e29b-41d4-a716-446655440000', PDO::PARAM_STR);
$stmt->bindValue(':nome', 'Marcos Silva', PDO::PARAM_STR);
$stmt->bindValue(':email', 'contato@exemplo.com.br', PDO::PARAM_STR);
$stmt->bindValue(':cpf', '01234567890', PDO::PARAM_STR);
$stmt->bindValue(':preco', '199.90', PDO::PARAM_STR);
$stmt->bindValue(':ativo', 1, PDO::PARAM_INT);
$stmt->execute();
$novoId = (int) $pdo->lastInsertId();
🧭 Guia Rápido: "O que você quer guardar no banco?"
Consulte os casos reais mais comuns em sistemas brasileiros (CPF, CNPJ, CEP, Dinheiro, Senhas, Fotos) e evite erros graves de modelagem.
Coluna: cpf
CPF (Cadastro de Pessoa Física)
INT ou BIGINT
Números inteiros apagam o zero à esquerda! O CPF "01234567890" viraria "1234567890", corrompendo o documento.
// Remove tudo que não for dígito antes de salvar no CHAR(11)
$cpfLimpo = preg_replace('/\D/', '', $_POST['cpf'] ?? '');
if (strlen($cpfLimpo) !== 11) {
throw new InvalidArgumentException('CPF deve conter 11 dígitos.');
}
$stmt->bindValue(':cpf', $cpfLimpo, PDO::PARAM_STR);
Coluna: cnpj
CNPJ (Pessoa Jurídica)
BIGINT
Além de perder zeros à esquerda, o CNPJ agora suporta letras e números (CNPJ Alfanumérico), exigindo `CHAR(14)`.
// Remove pontuação mantendo letras maiúsculas e números (14 posições)
$cnpjLimpo = preg_replace('/[^A-Z0-9]/', '', strtoupper($_POST['cnpj'] ?? ''));
if (strlen($cnpjLimpo) !== 14) {
throw new InvalidArgumentException('CNPJ deve conter 14 caracteres.');
}
$stmt->bindValue(':cnpj', $cnpjLimpo, PDO::PARAM_STR);
Coluna: senha_hash
Senha de Usuário (Password Hash)
VARCHAR(20) ou MD5 CHAR(32)
Jamais salve senhas em texto puro ou MD5! A função nativa `password_hash()` do PHP gera hashes de 60 caracteres (Bcrypt) a ~97 caracteres (Argon2id) e recomenda oficialmente `VARCHAR(255)` para suportar algoritmos futuros.
// Ao cadastrar:
$hash = password_hash($senhaPura, PASSWORD_DEFAULT);
$stmt->bindValue(':senha_hash', $hash, PDO::PARAM_STR);
// Ao fazer login:
if (password_verify($senhaDigitada, $usuarioDoBanco['senha_hash'])) {
// Login aprovado!
}
Coluna: preco_unitario / valor_total
Preços, Salários e Valores em Dinheiro (R$)
FLOAT ou DOUBLE
FLOAT usa ponto flutuante binário aproximado (`0.1 + 0.2 = 0.30000000000000004`), gerando diferenças de centavos em somas de pedidos e auditorias fiscais.
// Sempre trafegue DECIMAL como string no PDO para evitar imprecisão de float:
$preco = '1499.90';
$stmt->bindValue(':preco', $preco, PDO::PARAM_STR);
Coluna: email
Endereço de E-mail
TEXT ou CHAR(150)
CHAR(150) desperdiçaria espaço fixo em todos os registros, e TEXT dificulta a criação direta de índice UNIQUE sem prefixo no MySQL.
$email = mb_strtolower(trim($_POST['email'] ?? ''), 'UTF-8');
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('E-mail inválido.');
}
$stmt->bindValue(':email', $email, PDO::PARAM_STR);
Coluna: telefone
Telefone / Celular / WhatsApp
INT
Um celular com DDD (ex: 11999998888) passa de 11 bilhões e ESTOURA o limite máximo do tipo INT (2,14 bilhões)! Além disso, telefones não sofrem cálculos matemáticos.
// Mantém apenas dígitos (e opcionalmente o sinal + do DDI padrão E.164)
$telefone = preg_replace('/[^\d+]/', '', $_POST['telefone'] ?? '');
$stmt->bindValue(':telefone', $telefone, PDO::PARAM_STR);
Coluna: cep / uf
CEP e Sigla do Estado (UF)
INT para CEP / VARCHAR(255) para UF
CEPs de São Paulo e Grande SP começam com zero (`01310-100`). Se salvar em INT, o zero some e vira `1310100`.
$cep = preg_replace('/\D/', '', $_POST['cep'] ?? ''); // "01310100"
$uf = strtoupper(trim($_POST['uf'] ?? '')); // "SP"
$stmt->bindValue(':cep', $cep, PDO::PARAM_STR);
$stmt->bindValue(':uf', $uf, PDO::PARAM_STR);
Coluna: foto_url / caminho_arquivo
Foto de Perfil, Imagens de Produtos e PDFs
LONGBLOB (guardando a imagem inteira dentro da tabela)
Salvar imagens e PDFs dentro do banco deixa as consultas lentas, multiplica o tamanho do backup em gigabytes e consome toda a RAM do servidor SQL. Salve o arquivo em uma pasta `/uploads` ou no S3 e grave apenas o caminho/URL no banco!
// Salva o arquivo no disco/storage com nome único e grava apenas o caminho no banco:
$nomeArquivo = bin2hex(random_bytes(16)) . '.webp';
$caminhoRelativo = 'uploads/produtos/' . $nomeArquivo;
// move_uploaded_file($_FILES['foto']['tmp_name'], __DIR__ . '/public/' . $caminhoRelativo);
$stmt->bindValue(':foto_url', $caminhoRelativo, PDO::PARAM_STR);
Coluna: status
Status de Pedido / Situação de Cadastro
TEXT livre sem validação
Sem restrição de domínio (ENUM ou validação por BackedEnum no PHP), erros de digitação como `"Pago"`, `"pago "` ou `"aprovado"` quebram os relatórios financeiros.
enum StatusPedido: string {
case Pendente = 'pendente';
case Pago = 'pago';
case Enviado = 'enviado';
case Cancelado = 'cancelado';
}
$stmt->bindValue(':status', StatusPedido::Pago->value, PDO::PARAM_STR);
Coluna: criado_em, atualizado_em, deletado_em
Datas de Criação, Atualização e Exclusão Lógica (Soft Delete)
VARCHAR(20)
Campos `TIMESTAMP` com `DEFAULT CURRENT_TIMESTAMP` são preenchidos sozinhos pelo próprio banco de dados e permitem filtrar vendas por mês, dia e hora instantaneamente.
// Para Soft Delete (desativar sem apagar do banco com DELETE):
$stmt = $pdo->prepare('UPDATE produtos SET deletado_em = CURRENT_TIMESTAMP WHERE id = :id');
$stmt->bindValue(':id', $produtoId, PDO::PARAM_INT);
$stmt->execute();