Início / Trilha 1 / Conteúdo / Tópico 8
8

Data Types Oracle

Tipos de dados, conversões e boas práticas

📖

Tipos de Dados: Caracteres

VARCHAR2 - Tipo Recomendado para Strings

VARCHAR2 é o tipo de dado mais usado para armazenar strings de tamanho variável no Oracle.

Sintaxe e Limites:

-- Tamanho em bytes (padrão)
nome VARCHAR2(100)

-- Tamanho em caracteres (recomendado para Unicode)
nome VARCHAR2(100 CHAR)

-- Limites:
-- Mínimo: 1 byte
-- Máximo: 4000 bytes (ou 32767 em PL/SQL)

VARCHAR2 vs VARCHAR

Use sempre VARCHAR2!

  • VARCHAR2 é o padrão Oracle
  • VARCHAR está reservado para futuro uso
  • Comportamento do VARCHAR pode mudar
  • VARCHAR2 armazena valores NULL corretamente

BYTE vs CHAR

Cuidado com caracteres multibyte!

  • BYTE: tamanho em bytes (padrão)
  • CHAR: tamanho em caracteres
  • 1 caractere pode ocupar até 4 bytes (UTF-8)
  • Use CHAR para evitar problemas
-- Exemplo prático
CREATE TABLE clientes (
    id          NUMBER(10) PRIMARY KEY,
    nome        VARCHAR2(100 CHAR),  -- Recomendado: usa CHAR
    email       VARCHAR2(255),       -- 255 bytes é suficiente para email
    descricao   VARCHAR2(4000 CHAR)  -- Textos maiores
);

-- Testando BYTE vs CHAR
INSERT INTO clientes VALUES (1, 'João', 'joao@email.com', 'Cliente VIP');
INSERT INTO clientes VALUES (2, '日本語テスト', 'teste@email.com', 'Teste Unicode');

CHAR - Tamanho Fixo

CHAR armazena strings de tamanho fixo, completando com espaços se necessário.

-- Sintaxe
codigo_uf CHAR(2)  -- Sempre ocupa 2 bytes

-- Exemplos de uso adequado:
CREATE TABLE enderecos (
    uf           CHAR(2),      -- 'SP', 'RJ' - sempre 2 caracteres
    cep          CHAR(8),      -- '01310100' - sempre 8 dígitos
    sexo         CHAR(1),      -- 'M' ou 'F'
    tipo_pessoa  CHAR(1)       -- 'F' (física) ou 'J' (jurídica)
);

-- CUIDADO: CHAR preenche com espaços!
INSERT INTO enderecos VALUES ('SP', '01310100', 'M', 'F');

-- Comparação com VARCHAR2
SELECT * FROM enderecos WHERE uf = 'SP';      -- Funciona
SELECT * FROM enderecos WHERE uf = 'SP  ';    -- Também funciona (trailing spaces)

Quando Usar CHAR vs VARCHAR2?

  • CHAR: Códigos de tamanho fixo (UF, flags, status com 1 char)
  • VARCHAR2: Todos os outros casos (nomes, descrições, emails)
🔢

Tipos de Dados: Numéricos

NUMBER - Tipo Universal para Números

NUMBER armazena números com precisão fixa ou flutuante.

Sintaxe: NUMBER(p, s)

  • p (precision): Total de dígitos significativos (1 a 38)
  • s (scale): Dígitos após a vírgula (-84 a 127)
-- Diversos formatos de NUMBER
CREATE TABLE exemplos_number (
    -- Inteiros
    id              NUMBER(10),         -- Até 10 dígitos: 9999999999
    quantidade      NUMBER(6),          -- Até 999999

    -- Decimais
    preco           NUMBER(10, 2),      -- 99999999.99 (preço/dinheiro)
    peso            NUMBER(8, 3),       -- 99999.999 (medidas precisas)
    percentual      NUMBER(5, 2),       -- 100.00 (0% a 100%)

    -- Sem especificação (até 38 dígitos)
    valor_generico  NUMBER,             -- Qualquer número

    -- Escala negativa (arredonda)
    populacao       NUMBER(10, -3)      -- Arredonda para milhares: 1234000
);

-- Exemplos de inserção
INSERT INTO exemplos_number VALUES (
    1,                  -- id
    150,                -- quantidade
    1234.56,            -- preco
    75.350,             -- peso
    15.75,              -- percentual
    123456789.123456,   -- valor_generico
    1234567             -- populacao (armazenado como 1235000)
);

-- Testando arredondamento
SELECT
    populacao,                    -- 1235000
    populacao / 1000 AS milhares  -- 1235
FROM exemplos_number;

Boas Práticas com NUMBER

Recomendações

  • Sempre especifique precisão e escala
  • Use NUMBER(10,2) para valores monetários
  • Evite NUMBER sem parâmetros em produção
  • Para IDs, use NUMBER(10) ou NUMBER(19)

Evite

  • INTEGER (use NUMBER com precisão)
  • FLOAT, REAL (use NUMBER para precisão)
  • NUMBER sem especificação em tabelas
  • Escala maior que precisão
📅

Tipos de Dados: Data e Hora

DATE - Data e Hora

DATE armazena data e hora com precisão de segundos.

-- Criando tabela com DATE
CREATE TABLE eventos (
    id               NUMBER(10) PRIMARY KEY,
    nome             VARCHAR2(200 CHAR),
    data_criacao     DATE DEFAULT SYSDATE,
    data_evento      DATE,
    data_atualizacao DATE
);

-- Inserindo datas de diversas formas
INSERT INTO eventos VALUES (
    1,
    'Reunião',
    SYSDATE,                    -- Data/hora atual
    DATE '2025-01-15',          -- Formato ISO (apenas data)
    TO_DATE('15/01/2025 14:30', 'DD/MM/YYYY HH24:MI')  -- Com hora
);

-- Operações com DATE
SELECT
    nome,
    data_evento,
    data_evento + 7 AS uma_semana_depois,    -- Adiciona 7 dias
    data_evento - 1 AS ontem,                -- Subtrai 1 dia
    SYSDATE - data_criacao AS dias_desde_criacao,
    TRUNC(data_evento) AS data_sem_hora,     -- Remove hora
    TO_CHAR(data_evento, 'DD/MM/YYYY HH24:MI:SS') AS formatado
FROM eventos;

TIMESTAMP - Precisão de Frações de Segundo

TIMESTAMP estende DATE com precisão de até 9 casas decimais (nanossegundos).

-- Tipos de TIMESTAMP
CREATE TABLE logs_sistema (
    id                NUMBER(19) PRIMARY KEY,
    mensagem          VARCHAR2(4000 CHAR),
    timestamp_local   TIMESTAMP(6),              -- Precisão de 6 casas decimais
    timestamp_tz      TIMESTAMP WITH TIME ZONE,  -- Com fuso horário
    timestamp_ltz     TIMESTAMP WITH LOCAL TIME ZONE  -- Convertido para fuso local
);

-- Inserindo timestamps
INSERT INTO logs_sistema VALUES (
    1,
    'Sistema iniciado',
    SYSTIMESTAMP,                                      -- Timestamp atual
    CURRENT_TIMESTAMP,                                 -- Com fuso horário
    TO_TIMESTAMP('2025-01-15 10:30:45.123456', 'YYYY-MM-DD HH24:MI:SS.FF6')
);

-- Comparando DATE e TIMESTAMP
SELECT
    SYSDATE AS data_atual,             -- 15/01/2025 10:30:45
    SYSTIMESTAMP AS timestamp_atual    -- 15/01/2025 10:30:45.123456000 -03:00
FROM dual;

Quando usar DATE?

  • Datas de nascimento, eventos
  • Precisão de segundos é suficiente
  • Economiza espaço (7 bytes)

Quando usar TIMESTAMP?

  • Logs de sistema e auditoria
  • Precisa de milissegundos/nanossegundos
  • Sistemas distribuídos (time zones)
📦

Large Objects (LOBs)

CLOB e BLOB - Objetos Grandes

CLOB (Character LOB)

Armazena textos muito grandes (até 4 GB).

  • Documentos HTML/XML
  • Descrições longas
  • JSON grandes
  • Logs de texto extensos

BLOB (Binary LOB)

Armazena dados binários grandes (até 4 GB).

  • Imagens, fotos
  • PDFs, documentos
  • Vídeos, áudios
  • Arquivos compactados
-- Criando tabela com LOBs
CREATE TABLE documentos (
    id            NUMBER(10) PRIMARY KEY,
    titulo        VARCHAR2(200 CHAR),
    conteudo_xml  CLOB,           -- Texto grande
    arquivo_pdf   BLOB,           -- Binário grande
    data_upload   TIMESTAMP DEFAULT SYSTIMESTAMP
);

-- Inserindo texto grande (CLOB)
INSERT INTO documentos (id, titulo, conteudo_xml) VALUES (
    1,
    'Contrato de Serviço',
    '
        ...
        ... (muitas linhas) ...
    '
);

-- Consultar tamanho dos LOBs
SELECT
    titulo,
    DBMS_LOB.GETLENGTH(conteudo_xml) AS tamanho_xml_bytes,
    DBMS_LOB.GETLENGTH(arquivo_pdf) AS tamanho_pdf_bytes
FROM documentos;

Importante sobre LOBs:

  • LOBs são armazenados fora da linha (out-of-line) por padrão
  • Use DBMS_LOB package para manipular LOBs grandes
  • VARCHAR2(4000) é mais eficiente que CLOB para textos pequenos
  • Considere armazenar arquivos no filesystem e apenas referências no BD
🔄

Conversões de Tipos

Conversões Implícitas vs Explícitas

Conversão Implícita

Oracle converte automaticamente. Pode causar problemas!

-- Oracle converte automaticamente
SELECT * FROM funcionarios
WHERE id = '123';  -- String → Number

SELECT * FROM eventos
WHERE data_evento = '15/01/2025';  -- String → Date

Conversão Explícita

Use funções TO_*. Recomendado!

-- Conversão explícita e segura
SELECT * FROM funcionarios
WHERE id = TO_NUMBER('123');

SELECT * FROM eventos
WHERE data_evento = TO_DATE('15/01/2025', 'DD/MM/YYYY');

TO_CHAR - Convertendo para String

-- Convertendo números para string
SELECT
    TO_CHAR(12345) AS simples,                -- '12345'
    TO_CHAR(12345, '99999') AS com_formato,   -- ' 12345' (com espaços)
    TO_CHAR(12345, '00000') AS com_zeros,     -- '012345'
    TO_CHAR(1234.56, '9999.99') AS decimal,   -- '1234.56'
    TO_CHAR(1234.56, 'L9,999.99') AS moeda,   -- 'R$1,234.56'
    TO_CHAR(0.15, '99.99%') AS percentual     -- '15.00%'
FROM dual;

-- Convertendo datas para string
SELECT
    TO_CHAR(SYSDATE, 'DD/MM/YYYY') AS data_br,           -- '15/01/2025'
    TO_CHAR(SYSDATE, 'DD/MM/YYYY HH24:MI:SS') AS completo,  -- '15/01/2025 14:30:45'
    TO_CHAR(SYSDATE, 'DAY, DD "de" MONTH "de" YYYY') AS extenso,  -- 'MONDAY, 15 de JANUARY de 2025'
    TO_CHAR(SYSDATE, 'DY') AS dia_semana,               -- 'MON'
    TO_CHAR(SYSDATE, 'Q') AS trimestre,                 -- '1'
    TO_CHAR(SYSDATE, 'YYYY-MM-DD"T"HH24:MI:SS') AS iso  -- '2025-01-15T14:30:45'
FROM dual;

TO_NUMBER - Convertendo para Número

-- Convertendo strings para números
SELECT
    TO_NUMBER('12345') AS simples,                    -- 12345
    TO_NUMBER('1,234.56', '9,999.99') AS formatado,   -- 1234.56
    TO_NUMBER('R$1.234,56', 'L9G999D99') AS moeda_br, -- 1234.56
    TO_NUMBER('15%', '99%') AS percentual             -- 15
FROM dual;

-- CUIDADO com erros!
SELECT TO_NUMBER('ABC') FROM dual;  -- ORA-01722: invalid number

-- Use validação com REGEXP_LIKE
SELECT
    CASE
        WHEN REGEXP_LIKE('12345', '^\d+$')
        THEN TO_NUMBER('12345')
        ELSE NULL
    END AS numero_valido
FROM dual;

TO_DATE e TO_TIMESTAMP - Convertendo para Data

-- TO_DATE: String → Date
SELECT
    TO_DATE('15/01/2025', 'DD/MM/YYYY') AS data_br,
    TO_DATE('2025-01-15', 'YYYY-MM-DD') AS data_iso,
    TO_DATE('15-JAN-2025', 'DD-MON-YYYY') AS data_mon,
    TO_DATE('15/01/2025 14:30:45', 'DD/MM/YYYY HH24:MI:SS') AS com_hora
FROM dual;

-- TO_TIMESTAMP: String → Timestamp (com frações de segundo)
SELECT
    TO_TIMESTAMP('15/01/2025 14:30:45.123456', 'DD/MM/YYYY HH24:MI:SS.FF6') AS ts,
    TO_TIMESTAMP_TZ('2025-01-15 10:30:45 -03:00', 'YYYY-MM-DD HH24:MI:SS TZH:TZM') AS ts_tz
FROM dual;

-- Formatos comuns
-- DD = dia (01-31)
-- MM = mês (01-12)
-- YYYY = ano (4 dígitos)
-- HH24 = hora 24h (00-23)
-- MI = minuto (00-59)
-- SS = segundo (00-59)
-- FF = fração de segundo

Nunca Confie em Conversão Implícita de Datas!

Formatos de data variam por configuração (NLS_DATE_FORMAT). Sempre use TO_DATE explicitamente!

Resultado Esperado

O que você deve dominar após este tópico:

Escolher tipos corretos

VARCHAR2, NUMBER, DATE, TIMESTAMP, LOBs

Especificar precisão

VARCHAR2(100 CHAR), NUMBER(10,2)

Diferenças importantes

CHAR vs VARCHAR2, DATE vs TIMESTAMP

Conversões explícitas

TO_CHAR, TO_NUMBER, TO_DATE

Formatar dados

Usar máscaras de formato corretamente

LOBs quando necessário

CLOB e BLOB para dados grandes

Anterior: SGBD Próximo: Operadores SQL