Tipos de Dados

Tipos de Dados

Como caixas de armazenamento vêm em diferentes tamanhos — compartimentos pequenos para brincos, médios para relógios, grandes para cachecóis — cada coluna em um banco de dados também precisa da "caixa" certa para armazenar dados. Escolha o tipo certo e seus dados ficam seguros e com espaço eficiente; escolha errado e você desperdiça armazenamento ou perde precisão.


1. Conceitos Fundamentais

Conceito Descrição
Tipos numéricos Armazenam inteiros e decimais, incluindo INT, BIGINT, DECIMAL, FLOAT, etc.
Tipos de string Armazenam dados de texto, incluindo CHAR, VARCHAR, TEXT
Tipos de data Armazenam datas e horários, incluindo DATE, DATETIME, TIMESTAMP
Tipos booleanos Armazenam valores verdadeiro/falso; SQLite usa INTEGER (0/1)
NULL Representa "desconhecido" ou "ausente" — não é uma string vazia, não é zero
Princípio de seleção de tipo Escolha o tipo mais apropriado baseado no intervalo de dados, requisitos de precisão e eficiência de armazenamento

2. Sintaxe Básica

Tipos Numéricos

Tipo Descrição Intervalo/Precisão Ideal Para
INTEGER / INT Inteiro ±2,1 bilhões IDs, quantidades, idades
BIGINT Inteiro grande ±9,2×10¹⁸ IDs para dados massivos, tamanhos de arquivo
DECIMAL(p,s) / NUMERIC(p,s) Decimal exato p = total de dígitos, s = casas decimais Dinheiro, preços (sem perda de precisão)
FLOAT / REAL Ponto flutuante ~7 dígitos significativos Cálculos científicos, aproximações
DOUBLE Ponto flutuante de dupla precisão ~15 dígitos significativos Cálculos aproximados de alta precisão
SQL
-- DECIMAL para armazenamento preciso de dinheiro
CREATE TABLE accounts (
    id INTEGER PRIMARY KEY,
    balance DECIMAL(12, 2)  -- Até 12 dígitos, 2 casas decimais
);

-- FLOAT para armazenamento aproximado
CREATE TABLE measurements (
    id INTEGER PRIMARY KEY,
    temperature REAL  -- Valor aproximado, pode ter pequenos erros
);
💡 Dica: Sempre use DECIMAL para dinheiro, nunca FLOAT! FLOAT armazena valores aproximados — 0.1 + 0.2 pode ser igual a 0.30000000000000004, o que é um desastre em cenários financeiros.

Tipos de String

Tipo Descrição Tamanho Máximo Ideal Para
CHAR(n) String de comprimento fixo 255 bytes Dados de comprimento fixo (ex: gênero M/F, códigos de status)
VARCHAR(n) String de comprimento variável 65535 bytes Nomes, e-mails, títulos
TEXT Texto longo Ilimitado Conteúdo de artigos, notas, descrições
SQL
CREATE TABLE articles (
    id INTEGER PRIMARY KEY,
    title VARCHAR(200),    -- Título, máximo 200 caracteres
    status CHAR(1),         -- Status: D=Rascunho, P=Publicado
    content TEXT             -- Corpo, comprimento ilimitado
);
💡 Dica: SQLite é flexível com tipos de string — você pode armazenar strings de qualquer comprimento. Noém, para legibilidade do código e compatibilidade entre bancos de dados, ainda é recomendado declarar tipos corretamente.

Tipos de Data

Tipo Descrição Formato Ideal Para
DATE Data YYYY-MM-DD Aniversários, datas de contratação
DATETIME Data e hora YYYY-MM-DD HH:MM:SS Horários de criação, horários de compromisso
TIMESTAMP Timestamp Gerenciado automaticamente Horários de modificação de registro, cenários com fusos horários
SQL
CREATE TABLE events (
    id INTEGER PRIMARY KEY,
    event_name TEXT,
    event_date DATE,              -- Apenas se importa com a data
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP  -- Registra automaticamente o horário de criação
);
💡 Dica: SQLite não tem tipo de data dedicado. Datas são tipicamente armazenadas como TEXT (formato ISO 8601 como '2024-01-15') ou INTEGER (timestamp Unix). As funções de data internas do SQLite (como DATE(), DATETIME()) podem lidar corretamente com esses formatos.

Tipos Booleanos

Tipo Descrição Método de Armazenamento
BOOLEAN Verdadeiro/Falso Armazenado como INTEGER no SQLite: 0=falso, 1=verdadeiro
BIT Valor de bit Usado no MySQL/SQL Server
SQL
CREATE TABLE users (
    id INTEGER PRIMARY KEY,
    name TEXT,
    is_active BOOLEAN DEFAULT 1  -- 1=habilitado, 0=desabilitado
);

-- Inserir valores booleanos
INSERT INTO users (name, is_active) VALUES ('John', TRUE);   -- Armazenado como 1
INSERT INTO users (name, is_active) VALUES ('Jane', FALSE);  -- Armazenado como 0

-- Consultar usando valores booleanos
SELECT * FROM users WHERE is_active = 1;
💡 Dica: No SQLite, TRUE equivale a 1 e FALSE equivale a 0. Mas para legibilidade do código, é recomendado usar TRUE/FALSE em vez de escrever números diretamente.

O Significado de NULL

NULL representa "desconhecido" ou "ausente" — não é uma string vazia '', não é o número 0 e certamente não é FALSE.

SQL
-- Qualquer operação envolvendo NULL resulta em NULL
SELECT NULL + 1;        -- Resultado: NULL
SELECT NULL || 'hello'; -- Resultado: NULL

-- Para verificar NULL, deve-se usar IS / IS NOT
SELECT * FROM employees WHERE department_id IS NULL;     -- ✅ Correto
SELECT * FROM employees WHERE department_id = NULL;      -- ❌ Sempre retorna vazio
SELECT * FROM employees WHERE department_id IS NOT NULL; -- ✅ Correto
💡 Dica: NULL é o maior obstáculo para iniciantes. Lembre-se de duas regras: ①Use IS para verificar NULL, não =; ②Qualquer operação envolvendo NULL resulta em NULL.

Boas Práticas de Seleção de Tipo

Cenário Tipo Recomendado Razão
ID de chave primária INTEGER PRIMARY KEY AUTOINCREMENT Inteiros são mais rápidos que strings; auto-incremento é conveniente
Dinheiro/Preços DECIMAL(10,2) Armazenamento preciso, sem erros de arredondamento
Nomes de usuário/Títulos VARCHAR(100) Comprimento variável economiza espaço; limite de comprimento previne abuso
Corpo de artigo TEXT Comprimento ilimitado, adequado para grandes textos
Datas DATE / DATETIME Semântica clara, suporte interno a funções de data
Sinalizadores Sim/Não BOOLEAN Semântica clara, armazenamento compacto
Status de enumeração CHAR(1) ou INTEGER Mais flexível que o tipo ENUM

3. Exemplos de Código

Exemplo: Criar uma Tabela de Produtos e Verificar Restrições de Tipo (Dificuldade ⭐)

Crie uma tabela de produtos para experimentar o comportamento de diferentes tipos de dados.

SQL
-- Criar tabela products_demo com tipos de colunas especificados
CREATE TABLE products_demo (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name VARCHAR(100) NOT NULL,
    price DECIMAL(10, 2) NOT NULL,
    stock INTEGER DEFAULT 0,
    description TEXT,
    is_active BOOLEAN DEFAULT 1,
    created_at DATE
);

-- Inserir dados de vários tipos
INSERT INTO products_demo (name, price, stock, description, is_active, created_at)
VALUES ('Mechanical Keyboard', 299.50, 100, 'Teclado mecânico blue switch 87 teclas, ótimo para digitação', TRUE, '2024-01-15');

INSERT INTO products_demo (name, price, stock, description, is_active, created_at)
VALUES ('Wireless Mouse', 89.00, 200, NULL, TRUE, '2024-02-20');

-- Visualizar dados e comportamento dos tipos
SELECT name, price, stock, description, is_active, created_at
FROM products_demo;
▶ Experimente

Saída:

TEXT
name              price    stock  description                                   is_active  created_at
----------------  -------  -----  ---------------------------------------------  ---------  ----------
Mechanical Keyboard 299.50 100    Teclado mecânico blue switch 87 teclas...      1          2024-01-15
Wireless Mouse    89.00    200    (NULL)                                         1          2024-02-20

Exemplo: Verificar Propriedades Aritméticas do NULL (Dificuldade ⭐⭐)

Entenda o comportamento especial do NULL através de consultas reais.

SQL
-- Criar tabela de teste
CREATE TABLE null_test (
    id INTEGER PRIMARY KEY,
    value INTEGER
);

INSERT INTO null_test VALUES (1, 10);
INSERT INTO null_test VALUES (2, NULL);
INSERT INTO null_test VALUES (3, 20);

-- NULL em operações aritméticas
SELECT id, value, value + 100 AS add_result
FROM null_test;
▶ Experimente

Saída:

TEXT
id  value  add_result
--  -----  ----------
1   10     110
2   (NULL) (NULL)
3   20     120
SQL
-- Verificando NULL: IS vs =
SELECT id, value,
    CASE WHEN value IS NULL THEN 'É NULL' ELSE 'Não é NULL' END AS check_result
FROM null_test;

Saída:

TEXT
id  value  check_result
--  -----  ------------
1   10     Não é NULL
2   (NULL) É NULL
3   20     Não é NULL
SQL
-- NULL e funções de agregação: COUNT exclui NULL, SUM/AVG ignoram NULL
SELECT COUNT(value) AS count_val,      -- 2 (não conta NULL)
       COUNT(*) AS count_all,          -- 3 (conta todas as linhas)
       SUM(value) AS sum_val,          -- 30 (ignora NULL)
       AVG(value) AS avg_val           -- 15 (30/2, não 30/3)
FROM null_test;

Saída:

TEXT
count_val  count_all  sum_val  avg_val
---------  ---------  -------  -------
2          3          30       15.0

4. Cenários Comuns de Aplicação

Cenário 1: Projetar uma Tabela de Registro de Usuários

Escolha tipos apropriados baseados nos requisitos de negócio:

SQL
CREATE TABLE users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    username VARCHAR(50) NOT NULL UNIQUE,     -- Nome de usuário, único e não nulo
    email VARCHAR(100) NOT NULL UNIQUE,       -- E-mail
    password_hash CHAR(64) NOT NULL,          -- Hash SHA256, fixo em 64 caracteres
    age INTEGER CHECK (age >= 0 AND age <= 150),  -- Idade, verificação de intervalo razoável
    balance DECIMAL(12, 2) DEFAULT 0.00,      -- Saldo da conta, preciso ao centavo
    bio TEXT,                                  -- Bio, comprimento ilimitado
    is_verified BOOLEAN DEFAULT 0,            -- Se o e-mail foi verificado
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

Cenário 2: Lidando com NULL e Valores Padrão

Use a função COALESCE para fornecer valores padrão para NULL:

SQL
-- Consultar informações do funcionário, mostrar "Não atribuído" quando o departamento é NULL
SELECT e.name,
       COALESCE(d.name, 'Não atribuído') AS department,
       COALESCE(e.salary, 0) AS salary
FROM employees e
LEFT JOIN departments d ON e.department_id = d.id;

❓ Perguntas Frequentes

P: DECIMAL(10,2) e FLOAT podem armazenar decimais. Qual a diferença? R: DECIMAL armazena valores exatos, adequado para dinheiro e outros cenários onde a precisão é crítica. FLOAT armazena valores aproximados, com computação mais rápida mas pequenos erros. Regra simples: Dinheiro usa DECIMAL, cálculos científicos usam FLOAT.

P: Como escolher entre CHAR e VARCHAR? R: Se o comprimento dos dados é fixo (ex: gênero M/F, hash MD5), CHAR é mais eficiente. Se o comprimento varia (ex: nomes, títulos), VARCHAR economiza mais espaço. Na prática, VARCHAR é usado mais frequentemente.

P: Qual a diferença entre NULL e uma string vazia ''? R: NULL significa "desconhecido/sem valor", enquanto uma string vazia significa "o valor é conhecido e está vazio". Por exemplo, uma coluna "nome do meio": um estrangeiro pode não ter nome do meio (NULL), enquanto um brasileiro pode ter mas é uma string vazia (''). Em funções de agregação, COUNT(coluna) não conta NULL mas conta strings vazias.

P: Como o sistema de tipos do SQLite difere de outros bancos de dados? R: SQLite usa um sistema de tipos dinâmico — declarações de tipo de coluna são mais como "sugestões" do que restrições estritas. Você pode inserir uma string em uma coluna INTEGER (embora não recomendado). MySQL, PostgreSQL e outros usam sistemas de tipos estritos onde incompatibilidades de tipo causam erros. Para portabilidade do código, use tipos corretamente.


📖 Resumo


📝 Exercícios

Exercício 1 (⭐)

Projete uma tabela de "empréstimo de biblioteca" com os seguintes campos, escolhendo tipos de dados apropriados:

Exercício 2 (⭐⭐)

Crie a tabela do Exercício 1, insira 5 registros e depois escreva consultas:

  1. Consulte todos os registros de empréstimo não devolvidos
  2. Consulte registros onde as notas são NULL
  3. Conte todos os registros não devolvidos (cuidado com o tratamento de NULL)

Próxima Lição

👉 06-practice-basics - Prática: Consultas Básicas Abrangentes

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%