Tipos de dados no PostgreSQL: texto, números, datas e booleanos

1. Introdução aos tipos de dados no PostgreSQL

A escolha correta dos tipos de dados no PostgreSQL é fundamental para garantir integridade, performance e eficiência no armazenamento. Cada tipo de dado determina como o banco armazena, valida e processa as informações, impactando diretamente a velocidade das consultas e o espaço em disco utilizado.

Os tipos de dados no PostgreSQL se dividem em quatro categorias principais:
- Texto: para armazenar caracteres e strings
- Numérico: para valores inteiros e decimais
- Data/Hora: para datas, horas e intervalos
- Lógico: para valores booleanos

Boas práticas ao escolher tipos incluem: usar o tipo mais específico possível, evitar superdimensionamento, considerar a necessidade de precisão em cálculos financeiros e planejar o crescimento futuro dos dados.

2. Tipos de dados de texto

O PostgreSQL oferece três tipos principais para armazenamento de texto:

CHAR(n) armazena strings de comprimento fixo. Se o valor for menor que n, o PostgreSQL preenche com espaços à direita. Ideal para códigos padronizados, como siglas de estados:

CREATE TABLE exemplo_char (
    sigla_estado CHAR(2)
);

INSERT INTO exemplo_char VALUES ('SP');
-- 'SP' será armazenado como 'SP' (2 caracteres)

VARCHAR(n) armazena strings de comprimento variável até o limite n. Diferente do CHAR, não faz padding com espaços:

CREATE TABLE exemplo_varchar (
    nome VARCHAR(50)
);

INSERT INTO exemplo_varchar VALUES ('Maria Silva');
-- Ocupa apenas 11 caracteres, respeitando o limite de 50

TEXT não possui limite de tamanho, podendo armazenar até 1 GB. Recomendado para descrições longas, comentários e textos imprevisíveis:

CREATE TABLE exemplo_text (
    descricao TEXT
);

INSERT INTO exemplo_text VALUES ('Texto longo sem restrição de tamanho...');

Operações comuns com strings:

-- Concatenação
SELECT 'Olá' || ' ' || 'Mundo' AS saudacao;

-- Funções de string
SELECT UPPER('postgresql') AS maiusculo;   -- POSTGRESQL
SELECT LOWER('SQL') AS minusculo;          -- sql
SELECT LENGTH('Banco de Dados') AS tamanho; -- 14

3. Tipos de dados numéricos

Inteiros possuem faixas específicas de valores:

Tipo Faixa Armazenamento
SMALLINT -32.768 a 32.767 2 bytes
INTEGER -2.147.483.648 a 2.147.483.647 4 bytes
BIGINT -9.223.372.036.854.775.808 a 9.223.372.036.854.775.807 8 bytes
CREATE TABLE produtos (
    id INTEGER,
    quantidade_estoque SMALLINT,
    populacao_mundial BIGINT
);

Decimais e ponto flutuante oferecem diferentes níveis de precisão:

NUMERIC(p, s) — precisão exata, ideal para valores financeiros:
- p = número total de dígitos (precisão)
- s = número de dígitos decimais (escala)

CREATE TABLE contas (
    saldo NUMERIC(10,2)  -- 10 dígitos no total, 2 decimais
);

INSERT INTO contas VALUES (12345.67);

REAL e DOUBLE PRECISION — ponto flutuante, maior performance mas menos precisão:
- REAL: 6 dígitos decimais de precisão (4 bytes)
- DOUBLE PRECISION: 15 dígitos decimais de precisão (8 bytes)

CREATE TABLE medicao (
    temperatura REAL,
    distancia DOUBLE PRECISION
);

Exemplo prático de precisão financeira:

-- NUMERIC mantém precisão exata
SELECT 0.1::NUMERIC + 0.2::NUMERIC;  -- 0.3

-- DOUBLE PRECISION pode ter pequenos erros de arredondamento
SELECT 0.1::DOUBLE PRECISION + 0.2::DOUBLE PRECISION;  -- 0.30000000000000004

4. Tipos de dados de data e hora

O PostgreSQL oferece tipos robustos para trabalhar com datas e horas:

Tipo Descrição Exemplo
DATE Data (ano, mês, dia) '2024-01-15'
TIME Hora (sem fuso) '14:30:00'
TIMESTAMP Data e hora (sem fuso) '2024-01-15 14:30:00'
TIMESTAMPTZ Data e hora (com fuso) '2024-01-15 14:30:00-03'
INTERVAL Período de tempo '2 days 3 hours'
CREATE TABLE eventos (
    data_evento DATE,
    horario TIME,
    criado_em TIMESTAMP,
    atualizado_em TIMESTAMPTZ,
    duracao INTERVAL
);

Funções úteis para manipulação de datas:

-- Data e hora atuais
SELECT NOW() AS agora;                    -- 2024-01-15 14:30:00.123456-03
SELECT CURRENT_DATE AS hoje;              -- 2024-01-15
SELECT CURRENT_TIME AS hora_atual;        -- 14:30:00.123456-03

-- Cálculo de idade entre datas
SELECT AGE('2024-01-15', '1990-05-20') AS idade;  -- 33 years 7 mons 26 days

-- Extração de partes da data
SELECT EXTRACT(YEAR FROM NOW()) AS ano;
SELECT EXTRACT(MONTH FROM NOW()) AS mes;
SELECT EXTRACT(DAY FROM NOW()) AS dia;

-- Operações aritméticas com INTERVAL
SELECT CURRENT_DATE + INTERVAL '30 days' AS data_futura;
SELECT CURRENT_DATE - INTERVAL '1 year' AS ano_passado;

5. Tipo booleano

O tipo BOOLEAN no PostgreSQL aceita três valores: TRUE, FALSE e NULL.

CREATE TABLE usuarios (
    id INTEGER,
    nome TEXT,
    ativo BOOLEAN
);

INSERT INTO usuarios VALUES 
    (1, 'João', TRUE),
    (2, 'Maria', FALSE),
    (3, 'Pedro', NULL);

Uso em condições e operadores lógicos:

-- WHERE com booleano
SELECT * FROM usuarios WHERE ativo = TRUE;
SELECT * FROM usuarios WHERE ativo;  -- Sintaxe simplificada

-- Operadores lógicos
SELECT * FROM usuarios WHERE ativo IS NOT NULL;
SELECT * FROM usuarios WHERE NOT ativo;  -- Retorna FALSE e NULL? Não! Apenas FALSE

-- CHECK constraint com booleano
CREATE TABLE produtos_ativos (
    id INTEGER PRIMARY KEY,
    disponivel BOOLEAN NOT NULL DEFAULT TRUE,
    CONSTRAINT check_disponivel CHECK (disponivel IS NOT NULL)
);

Conversão implícita e explícita:

-- Conversão implícita em condições
SELECT * FROM usuarios WHERE ativo = 'true';  -- Funciona

-- Conversão explícita
SELECT 't'::BOOLEAN;   -- true
SELECT 'yes'::BOOLEAN; -- true
SELECT '1'::BOOLEAN;   -- true
SELECT 'f'::BOOLEAN;   -- false
SELECT 'no'::BOOLEAN;  -- false
SELECT '0'::BOOLEAN;   -- false

6. Considerações de armazenamento e performance

O tipo de dado escolhido impacta diretamente no espaço em disco e na performance das consultas:

-- Comparação de tamanhos
SELECT pg_column_size('abc'::CHAR(10)) AS char_size;     -- 10 bytes
SELECT pg_column_size('abc'::VARCHAR(10)) AS varchar_size; -- 4 bytes
SELECT pg_column_size('abc'::TEXT) AS text_size;          -- 4 bytes

Dicas importantes:
- Evite superdimensionamento: VARCHAR(1000) ocupa mais espaço em índices que VARCHAR(100)
- Prefira tipos específicos: use DATE em vez de TIMESTAMP quando não precisar de hora
- Indexação: índices em tipos numéricos são mais rápidos que em tipos texto
- Overflow: verifique faixas de valores para inteiros e precisão para NUMERIC
- Truncamento: VARCHAR(n) trunca silenciosamente strings maiores que n

-- Exemplo de overflow
CREATE TABLE teste_overflow (
    valor SMALLINT
);
INSERT INTO teste_overflow VALUES (40000);  -- ERRO: smallint out of range

-- Exemplo de truncamento
CREATE TABLE teste_trunc (
    nome VARCHAR(5)
);
INSERT INTO teste_trunc VALUES ('abcdefgh');  -- ERRO: value too long

7. Exemplo prático: criando uma tabela com tipos variados

-- Criação da tabela com tipos variados
CREATE TABLE funcionarios (
    id SERIAL PRIMARY KEY,
    nome TEXT NOT NULL,
    idade INTEGER CHECK (idade >= 18 AND idade <= 120),
    salario NUMERIC(12,2) DEFAULT 0.00,
    data_cadastro DATE DEFAULT CURRENT_DATE,
    ativo BOOLEAN DEFAULT TRUE
);

-- Inserção de dados
INSERT INTO funcionarios (nome, idade, salario, data_cadastro, ativo) VALUES
    ('Ana Beatriz', 28, 5500.00, '2024-01-15', TRUE),
    ('Carlos Eduardo', 35, 8200.50, '2024-01-10', TRUE),
    ('Daniela Santos', 42, 12500.75, '2023-11-20', FALSE);

-- Verificação dos tipos com pg_typeof
SELECT 
    pg_typeof(nome) AS tipo_nome,
    pg_typeof(idade) AS tipo_idade,
    pg_typeof(salario) AS tipo_salario,
    pg_typeof(data_cadastro) AS tipo_data,
    pg_typeof(ativo) AS tipo_ativo
FROM funcionarios LIMIT 1;

-- Consulta demonstrando os tipos em ação
SELECT 
    nome,
    idade,
    salario,
    data_cadastro,
    ativo,
    CASE 
        WHEN ativo THEN 'Sim'
        ELSE 'Não'
    END AS ativo_texto,
    AGE(data_cadastro) AS tempo_cadastro
FROM funcionarios
WHERE ativo = TRUE
ORDER BY salario DESC;

Este exemplo prático demonstra como combinar diferentes tipos de dados em uma única tabela, respeitando constraints e utilizando funções específicas para cada tipo. A escolha adequada dos tipos garante integridade dos dados, performance nas consultas e economia de espaço em disco.

Referências