Referência Completa de Tipos de Dados SQL

Manual de Todos os Campos do Banco de Dados

Explore cada tipo de campo (VARCHAR, CHAR, INT, DECIMAL, TIMESTAMP, JSON, ENUM...) agrupado por funcionalidade, como configurar no DrawDB e como validar e gravar com PHP 8 + PDO.

✕

1. Identificadores & Chaves 2 tipos

Campos responsáveis por identificar unicamente cada linha (Primary Keys) e conectar tabelas (Foreign Keys), incluindo auto-incremento e UUIDs.

INT UNSIGNED AUTO_INCREMENT

⭐ Essencial 💾 4 Bytes (32 bits)

Chave primária numérica sequencial padrão (1, 2, 3...) ideal para a maioria das tabelas relacionais.

O tipo INT UNSIGNED AUTO_INCREMENT (ou SERIAL no PostgreSQL) gera automaticamente um número inteiro único e sequencial a cada novo registro inserido. Por ocupar apenas 4 bytes e ser inserido em ordem crescente, o índice B-Tree da chave primária permanece extremamente rápido e sem fragmentação em disco.

Limites de Capacidade: De 1 até 4.294.967.295 (Unsigned) ou até 2.147.483.647 (Signed)

✅ Quando Usar (Casos Ideais)

  • • Chave primária (id) de tabelas com até ~2 bilhões de registros (usuários, produtos, categorias, clientes).
  • • Chaves estrangeiras (usuario_id, categoria_id) que apontam para tabelas com PK do tipo INT.
  • • Sistemas internos onde o ID sequencial rápido melhora a performance de JOINs.

🚫 Quando NÃO Usar (Armadilhas)

  • • Tabelas de altíssimo volume que podem ultrapassar 4 bilhões de linhas (logs, eventos de IoT, transações financeiras globais) — nesses casos, use BIGINT.
  • • URLs públicas sensíveis onde você não quer que concorrentes descubram quantos clientes ou pedidos você tem (ex: /pedido/105 vs /pedido/106) — combine com um UUID público.

📐 Como Configurar no DrawDB Abrir DrawDB ↗

Type no DrawDB: INT (ou INTEGER)
Size / Values: Deixe em branco (não use INT(11), pois no MySQL 8+ o display width foi depreciado)
Default sugerido: Vazio (o banco gera automaticamente via Auto Increment)
Equivalência nos Dialetos do DrawDB:
MySQL / MariaDB INT UNSIGNED AUTO_INCREMENT PRIMARY KEY
PostgreSQL SERIAL PRIMARY KEY (ou INT GENERATED ALWAYS AS IDENTITY)
SQLite INTEGER PRIMARY KEY AUTOINCREMENT

📋 Exemplos Reais de Colunas com INT:

id
INT UNSIGNED AUTO_INCREMENT PRIMARY KEY
Identificador único da tabela
categoria_id
INT UNSIGNED NOT NULL
Chave estrangeira (FK) apontando para categorias.id
🗄️ SQL DDL (Importar no DrawDB: Import > SQL)
CREATE TABLE categorias (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    nome VARCHAR(80) NOT NULL
);

CREATE TABLE produtos (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    categoria_id INT UNSIGNED NOT NULL,
    nome VARCHAR(120) NOT NULL,
    CONSTRAINT fk_produtos_categoria
        FOREIGN KEY (categoria_id) REFERENCES categorias(id)
        ON DELETE RESTRICT ON UPDATE CASCADE
);
🐘 Como Validar e Salvar no PHP 8 + PDO
<?php
declare(strict_types=1);

// 1. Inserindo registro sem informar o ID (o banco gera via AUTO_INCREMENT)
$stmt = $pdo->prepare('INSERT INTO categorias (nome) VALUES (:nome)');
$stmt->bindValue(':nome', 'Eletrônicos', PDO::PARAM_STR);
$stmt->execute();

// 2. Recuperando o ID gerado pelo banco convertendo para int do PHP
$novoId = (int) $pdo->lastInsertId();
echo "Categoria criada com ID: {$novoId}\n";

// 3. Buscando por ID com validação e PDO::PARAM_INT
$idBusca = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
if ($idBusca === false || $idBusca === null || $idBusca <= 0) {
    throw new InvalidArgumentException('ID inválido.');
}

$stmt = $pdo->prepare('SELECT id, nome FROM categorias WHERE id = :id');
$stmt->bindValue(':id', $idBusca, PDO::PARAM_INT);
$stmt->execute();
$categoria = $stmt->fetch(PDO::FETCH_ASSOC);

BIGINT UNSIGNED AUTO_INCREMENT

⭐ Essencial 💾 8 Bytes (64 bits)

Chave primária de 64 bits para tabelas massivas (padrão em frameworks modernos como Laravel).

Ocupa o dobro do espaço de um INT (8 bytes em vez de 4), mas permite até 18 quintilhões de registros. Frameworks modernos como Laravel utilizam BIGINT UNSIGNED como padrão (`$table->id()`) para garantir que nenhuma tabela esgote seus IDs, mesmo em sistemas de grande escala.

Limites de Capacidade: De 0 até 18.446.744.073.709.551.615 (Unsigned)

✅ Quando Usar (Casos Ideais)

  • • Tabelas que crescem rapidamente: pedidos, itens_pedido, logs_acesso, mensagens_chat, notificações, movimentações.
  • • Como padrão geral de chave primária caso queira total padronização no banco inteiro.

🚫 Quando NÃO Usar (Armadilhas)

  • • Tabelas auxiliares estáticas minúsculas (ex: estados_brasileiros com 27 linhas), onde `TINYINT` ou `INT` economiza memória em milhões de FKs.
  • • ATENÇÃO NO DRAWDB: Nunca crie uma FK `INT` apontando para uma PK `BIGINT`! O MySQL recusará criar a Foreign Key (Erro 150 / 3780).

📐 Como Configurar no DrawDB Abrir DrawDB ↗

Type no DrawDB: BIGINT
Size / Values: Vazio
Default sugerido: Vazio
Equivalência nos Dialetos do DrawDB:
MySQL / MariaDB BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY
PostgreSQL BIGSERIAL PRIMARY KEY
SQLite INTEGER PRIMARY KEY AUTOINCREMENT

📋 Exemplos Reais de Colunas com BIGINT:

id
BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY
PK de tabela de alto volume
usuario_id
BIGINT UNSIGNED NOT NULL
FK compatível com usuarios.id (BIGINT)
🗄️ SQL DDL (Importar no DrawDB: Import > SQL)
CREATE TABLE usuarios (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    email VARCHAR(150) NOT NULL UNIQUE
);

CREATE TABLE logs_auditoria (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    usuario_id BIGINT UNSIGNED NOT NULL,
    acao VARCHAR(100) NOT NULL,
    criado_em TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT fk_logs_usuario
        FOREIGN KEY (usuario_id) REFERENCES usuarios(id)
        ON DELETE CASCADE
);
🐘 Como Validar e Salvar no PHP 8 + PDO
<?php
declare(strict_types=1);

// Em PHP de 64-bits (padrão atual), o tipo `int` suporta até 9 quintilhões (PHP_INT_MAX).
$usuarioId = 9876543210;

$stmt = $pdo->prepare('
    INSERT INTO logs_auditoria (usuario_id, acao)
    VALUES (:usuario_id, :acao)
');
$stmt->bindValue(':usuario_id', $usuarioId, PDO::PARAM_INT);
$stmt->bindValue(':acao', 'LOGIN_SUCESSO', PDO::PARAM_STR);
$stmt->execute();

$logId = (int) $pdo->lastInsertId();

2. Numéricos Inteiros 3 tipos

Números sem casas decimais para contagens, quantidades em estoque, idades, ordenação e códigos numéricos.

TINYINT / TINYINT UNSIGNED

⭐ Essencial 💾 1 Byte (8 bits)

Inteiro super compacto de 1 Byte (0 a 255 sem sinal, ou -128 a 127 com sinal).

É o menor tipo numérico inteiro do banco de dados, consumindo apenas 1 byte por linha. Excelente para armazenar números pequenos cujos limites são bem conhecidos, como idade de uma pessoa, dia do mês (1 a 31), nota de avaliação (1 a 5 estrelas), número de parcelas de cartão (1 a 24) ou códigos de status.

Limites de Capacidade: Unsigned: 0 a 255 | Signed: -128 a 127

✅ Quando Usar (Casos Ideais)

  • • Idade de usuários (0 a 150 anos cabe com folga em `TINYINT UNSIGNED`).
  • • Avaliações/Ratings de produtos (1 a 5 estrelas ou 0 a 10).
  • • Mês do ano (1 a 12), dia da semana (1 a 7), número de parcelas (1 a 48).
  • • Prioridade ou nível de permissão numérico simples.

🚫 Quando NÃO Usar (Armadilhas)

  • • Quantidades de estoque ou contadores de visualizações que podem facilmente passar de 255.
  • • No PostgreSQL não existe `TINYINT` nativo (use `SMALLINT` no Postgres).

📐 Como Configurar no DrawDB Abrir DrawDB ↗

Type no DrawDB: TINYINT (MySQL/MariaDB) ou SMALLINT (PostgreSQL)
Size / Values: Vazio
Default sugerido: Ex: 0 ou 1
Equivalência nos Dialetos do DrawDB:
MySQL / MariaDB TINYINT UNSIGNED
PostgreSQL SMALLINT (2 bytes)
SQLite INTEGER

📋 Exemplos Reais de Colunas com TINYINT:

idade
TINYINT UNSIGNED NULL
Idade do cliente (0 a 255)
estrelas
TINYINT UNSIGNED NOT NULL
Nota da avaliação de 1 a 5
parcelas
TINYINT UNSIGNED NOT NULL DEFAULT 1
Quantidade de parcelas do pagamento
🗄️ SQL DDL (Importar no DrawDB: Import > SQL)
CREATE TABLE avaliacoes_produto (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    produto_id INT UNSIGNED NOT NULL,
    estrelas TINYINT UNSIGNED NOT NULL COMMENT 'Nota de 1 a 5',
    comentario VARCHAR(500) NULL,
    CONSTRAINT chk_estrelas CHECK (estrelas BETWEEN 1 AND 5)
);
🐘 Como Validar e Salvar no PHP 8 + PDO
<?php
declare(strict_types=1);

$estrelas = filter_input(INPUT_POST, 'estrelas', FILTER_VALIDATE_INT, [
    'options' => ['min_range' => 1, 'max_range' => 5]
]);

if ($estrelas === false || $estrelas === null) {
    throw new DomainException('A nota deve ser um número inteiro entre 1 e 5.');
}

$stmt = $pdo->prepare('
    INSERT INTO avaliacoes_produto (produto_id, estrelas, comentario)
    VALUES (:produto_id, :estrelas, :comentario)
');
$stmt->bindValue(':produto_id', 42, PDO::PARAM_INT);
$stmt->bindValue(':estrelas', $estrelas, PDO::PARAM_INT);
$stmt->bindValue(':comentario', 'Excelente produto!', PDO::PARAM_STR);
$stmt->execute();

SMALLINT / SMALLINT UNSIGNED

💾 2 Bytes (16 bits)

Inteiro de 2 Bytes para faixas intermediárias (0 a 65.535 sem sinal).

Ocupa metade do espaço de um INT comum (2 bytes). É ideal para quantidades moderadas que passam de 255 mas nunca chegarão a 65 mil, como ano de fabricação de veículos, número de páginas de um livro, portas de rede TCP/IP (1 a 65535) ou ordem de exibição de itens em menus e galerias.

Limites de Capacidade: Unsigned: 0 a 65.535 | Signed: -32.768 a 32.767

✅ Quando Usar (Casos Ideais)

  • • Número de páginas de um livro, duração de um filme em minutos.
  • • Ano histórico ou ano modelo de veículo (ex: 1850 a 2150).
  • • Porta de servidor de rede (0 a 65535).
  • • Quantidade de itens por pedido no carrinho de compras.

🚫 Quando NÃO Usar (Armadilhas)

  • • Estoque de produtos em atacado ou visualizações de página que possam ultrapassar 65.535.

📐 Como Configurar no DrawDB Abrir DrawDB ↗

Type no DrawDB: SMALLINT
Size / Values: Vazio
Default sugerido: Ex: 0 ou 1
Equivalência nos Dialetos do DrawDB:
MySQL / MariaDB SMALLINT UNSIGNED
PostgreSQL SMALLINT
SQLite INTEGER

📋 Exemplos Reais de Colunas com SMALLINT:

ano_fabricacao
SMALLINT UNSIGNED NOT NULL
Ano do veículo (ex: 2026)
numero_paginas
SMALLINT UNSIGNED NULL
Total de páginas de um livro
ordem_exibicao
SMALLINT UNSIGNED NOT NULL DEFAULT 0
Ordenação de banners/menus
🗄️ SQL DDL (Importar no DrawDB: Import > SQL)
CREATE TABLE livros (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    titulo VARCHAR(180) NOT NULL,
    ano_publicacao SMALLINT UNSIGNED NOT NULL,
    numero_paginas SMALLINT UNSIGNED NOT NULL
);
🐘 Como Validar e Salvar no PHP 8 + PDO
<?php
declare(strict_types=1);

$paginas = 384;
$ano = 2026;

if ($paginas < 1 || $paginas > 65535) {
    throw new RangeException('Número de páginas fora do limite de SMALLINT.');
}

$stmt = $pdo->prepare('
    INSERT INTO livros (titulo, ano_publicacao, numero_paginas)
    VALUES (:titulo, :ano, :paginas)
');
$stmt->bindValue(':titulo', 'Arquitetura de Bancos de Dados em PHP', PDO::PARAM_STR);
$stmt->bindValue(':ano', $ano, PDO::PARAM_INT);
$stmt->bindValue(':paginas', $paginas, PDO::PARAM_INT);
$stmt->execute();

INT / INTEGER (Com e Sem Sinal)

⭐ Essencial 💾 4 Bytes (32 bits)

O tipo inteiro padrão de 4 Bytes para quantidades de estoque, contadores, pontos e durações em segundos.

Quando não usado como chave primária, o INT (ou INTEGER) é o cavalo de batalha para números inteiros do dia a dia. Se o valor nunca puder ser negativo (como visualizações de vídeo, tempo em segundos), marque como UNSIGNED no MySQL ou adicione uma restrição CHECK (valor >= 0). Se puder ficar negativo (como saldo de pontos de fidelidade ou ajuste de estoque), mantenha SIGNED.

Limites de Capacidade: Signed: -2.147.483.648 a +2.147.483.647 | Unsigned: 0 a 4.294.967.295

✅ Quando Usar (Casos Ideais)

  • • Quantidade de produtos em estoque (`estoque_atual INT NOT NULL DEFAULT 0`).
  • • Contador de acessos, curtidas, downloads ou duração de vídeo em segundos.
  • • Armazenar valores monetários em centavos caso a equipe adote o padrão Money Pattern (ex: R$ 19,90 = 1990 centavos).

🚫 Quando NÃO Usar (Armadilhas)

  • • NUNCA use INT para armazenar CPF, CNPJ, CEP ou Telefone! Números de documentos e telefones começam com zero (`01234567890`) e o INT apaga os zeros à esquerda, além de estourar o limite de 32 bits em CNPJs e telefones com DDI.

📐 Como Configurar no DrawDB Abrir DrawDB ↗

Type no DrawDB: INT ou INTEGER
Size / Values: Vazio
Default sugerido: 0
Equivalência nos Dialetos do DrawDB:
MySQL / MariaDB INT (ou INT UNSIGNED)
PostgreSQL INTEGER
SQLite INTEGER

📋 Exemplos Reais de Colunas com INT:

quantidade_estoque
INT NOT NULL DEFAULT 0
Saldo atual de unidades no estoque
duracao_segundos
INT UNSIGNED NOT NULL
Tempo de duração de uma aula em vídeo
🗄️ SQL DDL (Importar no DrawDB: Import > SQL)
CREATE TABLE estoque_produtos (
    produto_id INT UNSIGNED PRIMARY KEY,
    quantidade_disponivel INT NOT NULL DEFAULT 0,
    quantidade_reservada INT UNSIGNED NOT NULL DEFAULT 0,
    atualizado_em TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
🐘 Como Validar e Salvar no PHP 8 + PDO
<?php
declare(strict_types=1);

// Atualização atômica de estoque no banco via PDO
$produtoId = 10;
$qtdComprada = 3;

$stmt = $pdo->prepare('
    UPDATE estoque_produtos
    SET quantidade_disponivel = quantidade_disponivel - :qtd
    WHERE produto_id = :id AND quantidade_disponivel >= :qtd
');
$stmt->bindValue(':qtd', $qtdComprada, PDO::PARAM_INT);
$stmt->bindValue(':id', $produtoId, PDO::PARAM_INT);
$stmt->execute();

if ($stmt->rowCount() === 0) {
    throw new RuntimeException('Estoque insuficiente para concluir a reserva.');
}

7. Estruturas Flexíveis & JSON 1 tipo

Armazenamento de objetos, arrays e metadados dinâmicos validados diretamente pelo banco de dados com suporte a buscas internas.

JSON / JSONB (Documentos Estruturados)

⭐ Essencial 💾 Aproximadamente o tamanho de um LONGBLOB/LONGTEXT (até 1 GB no Postgres / 4 GB no MySQL)

Armazena objetos e arrays JSON validados automaticamente e consultáveis via SQL.

O tipo nativo `JSON` (MySQL 5.7.8+ / MariaDB) e `JSONB` (PostgreSQL) valida automaticamente se a string enviada é um JSON válido e a armazena em um formato binário otimizado que permite buscar chaves específicas (`JSON_EXTRACT` ou operador `->`) sem precisar ler e fazer parse do texto inteiro.

Limites de Capacidade: Documentos JSON válidos (objetos `{}` ou arrays `[]`)

✅ Quando Usar (Casos Ideais)

  • • Atributos dinâmicos de produtos de categorias muito diferentes (ex: ficha técnica de uma Camiseta vs Placa de Vídeo).
  • • Preferências e configurações de interface do usuário (tema escuro, notificações, idioma).
  • • Payloads brutos de Webhooks (Stripe, Mercado Pago, Asaas) e snapshots de auditoria (antes/depois da edição).

🚫 Quando NÃO Usar (Armadilhas)

  • • NÃO use JSON como muleta para evitar criar tabelas e relacionamentos normais! Nunca guarde chaves estrangeiras dentro de um array JSON (`"produtos_ids": [1, 5, 9]`) — crie uma tabela associativa!

📐 Como Configurar no DrawDB Abrir DrawDB ↗

Type no DrawDB: JSON (ou JSONB no PostgreSQL)
Size / Values: Vazio
Default sugerido: Deixe vazio ou NULL
Equivalência nos Dialetos do DrawDB:
MySQL / MariaDB JSON
PostgreSQL JSONB (Binário indexável recomendado) ou JSON
SQLite TEXT (com funções da extensão JSON1 nativas)

📋 Exemplos Reais de Colunas com JSON:

especificacoes_tecnicas
JSON NULL
Atributos variáveis do produto (voltagem, memória, cor)
configuracoes
JSON NOT NULL
Preferências customizadas do usuário
🗄️ SQL DDL (Importar no DrawDB: Import > SQL)
CREATE TABLE produtos_catalogo (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    nome VARCHAR(150) NOT NULL,
    preco DECIMAL(10, 2) NOT NULL,
    atributos_extras JSON NULL COMMENT 'Ex: {"voltagem": "220v", "garantia_meses": 12}'
);
🐘 Como Validar e Salvar no PHP 8 + PDO
<?php
declare(strict_types=1);

// 1. Codificando array associativo do PHP para JSON com tratamento de erro nativo (JSON_THROW_ON_ERROR)
$atributos = [
    'processador' => 'Ryzen 7',
    'memoria_ram_gb' => 32,
    'conexoes' => ['HDMI 2.1', 'USB-C', 'Wi-Fi 6E'],
];

$jsonString = json_encode($atributos, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);

$stmt = $pdo->prepare('
    INSERT INTO produtos_catalogo (nome, preco, atributos_extras)
    VALUES (:nome, :preco, :atributos)
');
$stmt->bindValue(':nome', 'Notebook Pro 16', PDO::PARAM_STR);
$stmt->bindValue(':preco', '7499.90', PDO::PARAM_STR);
$stmt->bindValue(':atributos', $jsonString, PDO::PARAM_STR);
$stmt->execute();

// 2. Lendo do banco e decodificando de volta para Array PHP
$dadosAtributos = json_decode($jsonString, true, 512, JSON_THROW_ON_ERROR);
echo $dadosAtributos['processador']; // "Ryzen 7"

8. Opções & Conjuntos (Listas) 1 tipo

Restrição de valores a uma lista fechada pré-definida de opções (como status de pedido ou nível de acesso).

ENUM (Lista Fechada de Opções)

⭐ Essencial 💾 1 Byte (até 255 opções) ou 2 Bytes (até 65.535 opções)

Permite que a coluna assuma apenas UM valor dentre uma lista pré-definida de opções.

Internamente no MySQL, o ENUM armazena o texto das opções no metadado da tabela e grava apenas um índice numérico compacto de 1 byte na linha (para até 255 opções), mas exibe e filtra como string. No PHP 8.1+, combina perfeitamente com `BackedEnum`. Alternativamente, em sistemas onde a lista de opções muda com frequência, muitos arquitetos preferem `VARCHAR(30)` validado por um `enum` do PHP ou uma tabela de domínio auxiliar.

Limites de Capacidade: 1 valor escolhido por registro dentre a lista declarada

✅ Quando Usar (Casos Ideais)

  • • Status de máquina de estados estável: `ENUM('pendente', 'pago', 'enviado', 'cancelado')`.
  • • Tipo de pessoa: `ENUM('PF', 'PJ')`.
  • • Nível de severidade de um log: `ENUM('info', 'warning', 'error', 'critical')`.

🚫 Quando NÃO Usar (Armadilhas)

  • • Listas que o administrador do sistema pode cadastrar ou editar pelo painel (ex: categorias de produtos, cargos da empresa) — para isso, crie uma tabela separada com Foreign Key!

📐 Como Configurar no DrawDB Abrir DrawDB ↗

Type no DrawDB: ENUM
Size / Values: 'pendente', 'pago', 'enviado', 'cancelado'
Default sugerido: 'pendente'
Equivalência nos Dialetos do DrawDB:
MySQL / MariaDB ENUM('pendente', 'pago', 'cancelado') NOT NULL DEFAULT 'pendente'
PostgreSQL CREATE TYPE status_pedido AS ENUM (...) ou VARCHAR(20) CHECK (...)
SQLite TEXT CHECK(status IN ('pendente', 'pago', 'cancelado'))

📋 Exemplos Reais de Colunas com ENUM:

status
ENUM('pendente', 'pago', 'cancelado') NOT NULL DEFAULT 'pendente'
Ciclo de vida de um pedido
tipo_pessoa
ENUM('PF', 'PJ') NOT NULL
Pessoa Física ou Jurídica
🗄️ SQL DDL (Importar no DrawDB: Import > SQL)
CREATE TABLE pagamentos (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    pedido_id BIGINT UNSIGNED NOT NULL,
    metodo ENUM('pix', 'cartao_credito', 'boleto') NOT NULL,
    status ENUM('aguardando', 'aprovado', 'recusado', 'estornado') NOT NULL DEFAULT 'aguardando'
);
🐘 Como Validar e Salvar no PHP 8 + PDO
<?php
declare(strict_types=1);

// Usando Backed Enum nativo do PHP 8.1+ sincronizado com o banco!
enum StatusPagamento: string {
    case Aguardando = 'aguardando';
    case Aprovado   = 'aprovado';
    case Recusado   = 'recusado';
    case Estornado  = 'estornado';
}

// Validando uma string recebida via requisição com tryFrom()
$statusRecebido = StatusPagamento::tryFrom($_POST['status'] ?? 'aguardando');
if ($statusRecebido === null) {
    throw new ValueError('Status de pagamento inválido.');
}

$stmt = $pdo->prepare('
    INSERT INTO pagamentos (pedido_id, metodo, status)
    VALUES (:pedido_id, :metodo, :status)
');
$stmt->bindValue(':pedido_id', 1020, PDO::PARAM_INT);
$stmt->bindValue(':metodo', 'pix', PDO::PARAM_STR);
$stmt->bindValue(':status', $statusRecebido->value, PDO::PARAM_STR);
$stmt->execute();

9. Booleanos & Flags 1 tipo

Estados binários de verdadeiro/falso (ativo/inativo, pago/pendente, verificado/não verificado).

BOOLEAN / TINYINT(1) (Verdadeiro ou Falso)

⭐ Essencial 💾 1 Byte

Armazena estados binários Verdadeiro (1 / true) ou Falso (0 / false) como ativo, pago ou verificado.

No MySQL e MariaDB, a palavra-chave `BOOLEAN` (ou `BOOL`) é um apelido (alias) para `TINYINT(1)`, onde `0` representa `false` e `1` representa `true`. No PostgreSQL, `BOOLEAN` é um tipo dedicado que aceita `TRUE` e `FALSE`. Dica de modelagem: se você precisa saber QUANDO a flag virou verdadeira (ex: quando o e-mail foi verificado), em vez de `email_verificado BOOLEAN`, crie `email_verificado_em TIMESTAMP NULL`!

Limites de Capacidade: 0 (False) ou 1 (True) — mais NULL se a coluna for nullable

✅ Quando Usar (Casos Ideais)

  • • Flags de controle simples: `ativo`, `destaque_home`, `aceitou_termos`, `frete_gratis`.
  • • Configurações de liga/desliga.

🚫 Quando NÃO Usar (Armadilhas)

  • • Nunca use `VARCHAR(3)` escrevendo `"SIM"` e `"NAO"` ou `CHAR(1)` com `"S"` e `"N"`! Use sempre `BOOLEAN` / `TINYINT(1)` com `0` e `1`.

📐 Como Configurar no DrawDB Abrir DrawDB ↗

Type no DrawDB: BOOLEAN (ou TINYINT no MySQL)
Size / Values: 1 (se selecionar TINYINT) ou vazio (se selecionar BOOLEAN)
Default sugerido: 1 (true) ou 0 (false)
Equivalência nos Dialetos do DrawDB:
MySQL / MariaDB BOOLEAN NOT NULL DEFAULT 1 (ou TINYINT(1))
PostgreSQL BOOLEAN NOT NULL DEFAULT TRUE
SQLite INTEGER NOT NULL DEFAULT 1 (0 ou 1)

📋 Exemplos Reais de Colunas com BOOLEAN:

ativo
BOOLEAN NOT NULL DEFAULT 1
Indica se o cadastro está ativo no sistema
em_destaque
BOOLEAN NOT NULL DEFAULT 0
Exibir produto na vitrine principal
🗄️ SQL DDL (Importar no DrawDB: Import > SQL)
CREATE TABLE cupons_desconto (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    codigo VARCHAR(30) NOT NULL UNIQUE,
    ativo BOOLEAN NOT NULL DEFAULT 1,
    uso_unico BOOLEAN NOT NULL DEFAULT 0
);
🐘 Como Validar e Salvar no PHP 8 + PDO
<?php
declare(strict_types=1);

$ativo    = true;
$usoUnico = false;

// Nota importante no PDO + MySQL: converter bool para int (1 ou 0) com PDO::PARAM_INT
// evita incompatibilidades de driver em modo estrito do MySQL.
$stmt = $pdo->prepare('
    INSERT INTO cupons_desconto (codigo, ativo, uso_unico)
    VALUES (:codigo, :ativo, :uso_unico)
');
$stmt->bindValue(':codigo', 'BEMVINDO10', PDO::PARAM_STR);
$stmt->bindValue(':ativo', $ativo ? 1 : 0, PDO::PARAM_INT);
$stmt->bindValue(':uso_unico', $usoUnico ? 1 : 0, PDO::PARAM_INT);
$stmt->execute();

// Ao ler do banco no PHP, faça o cast explícito para (bool):
$cupomAtivo = (bool) 1; // true

11. Espaciais & Geográficos 1 tipo

Coordenadas de GPS (latitude/longitude), pontos no mapa, rotas e polígonos de áreas de entrega.

POINT / DECIMAL(10,8) (Coordenadas GPS)

💾 DECIMAL(10,8) + DECIMAL(11,8): 11 Bytes | POINT: 25 Bytes

Armazenamento de coordenadas geográficas (Latitude e Longitude) para mapas e cálculo de distância.

Você tem duas abordagens excelentes para guardar localização GPS: 1) Duas colunas separadas `latitude DECIMAL(10, 8)` e `longitude DECIMAL(11, 8)`, que é simples, universal e funciona em 100% dos bancos e ORMs; ou 2) O tipo espacial `POINT` com `SPATIAL INDEX`, ideal quando você precisa calcular raio de distância em tempo real (`ST_Distance_Sphere`) para apps de entrega.

Limites de Capacidade: Latitude: -90.00000000 a +90.00000000 | Longitude: -180.00000000 a +180.00000000

✅ Quando Usar (Casos Ideais)

  • • Endereços de lojas, restaurantes ou clientes para exibir pino no Google Maps / Leaflet (`DECIMAL(10,8)` e `DECIMAL(11,8)`).
  • • Busca geoespacial "encontrar lojas num raio de 5 km" usando `POINT` e `ST_Distance_Sphere`.

🚫 Quando NÃO Usar (Armadilhas)

  • • Não use `FLOAT` para coordenadas GPS precisas, pois perde precisão nas últimas casas decimais.

📐 Como Configurar no DrawDB Abrir DrawDB ↗

Type no DrawDB: DECIMAL (10,8 e 11,8) ou POINT
Size / Values: 10,8 (para latitude) e 11,8 (para longitude)
Default sugerido: NULL
Equivalência nos Dialetos do DrawDB:
MySQL / MariaDB DECIMAL(10, 8) / POINT SRID 4326
PostgreSQL NUMERIC(10, 8) / PostGIS GEOGRAPHY(POINT, 4326)
SQLite REAL / NUMERIC

📋 Exemplos Reais de Colunas com POINT:

latitude
DECIMAL(10, 8) NULL
Latitude GPS (ex: -23.56141400)
longitude
DECIMAL(11, 8) NULL
Longitude GPS (ex: -46.65588190)
🗄️ SQL DDL (Importar no DrawDB: Import > SQL)
CREATE TABLE filiais (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    nome VARCHAR(100) NOT NULL,
    latitude DECIMAL(10, 8) NOT NULL COMMENT 'De -90 a +90',
    longitude DECIMAL(11, 8) NOT NULL COMMENT 'De -180 a +180'
);
🐘 Como Validar e Salvar no PHP 8 + PDO
<?php
declare(strict_types=1);

$lat = -23.561414;
$lng = -46.655881;

if ($lat < -90 || $lat > 90 || $lng < -180 || $lng > 180) {
    throw new RangeException('Coordenadas GPS fora dos limites terrestres.');
}

$stmt = $pdo->prepare('
    INSERT INTO filiais (nome, latitude, longitude)
    VALUES (:nome, :lat, :lng)
');
$stmt->bindValue(':nome', 'Filial Avenida Paulista', PDO::PARAM_STR);
$stmt->bindValue(':lat', number_format($lat, 8, '.', ''), PDO::PARAM_STR);
$stmt->bindValue(':lng', number_format($lng, 8, '.', ''), PDO::PARAM_STR);
$stmt->execute();