1. Tipos de dados no DB2

Escolher o tipo certo impacta diretamente o espaço em disco, a performance de queries e o comportamento de comparações. Abaixo os tipos mais usados em ambientes bancários.

Numéricos

TipoTamanhoFaixaUso típico
SMALLINT2 bytes-32.768 a 32.767Flags, códigos pequenos
INTEGER4 bytes±2,1 bilhõesIDs, contadores
BIGINT8 bytes±9,2 quintilhõesChaves de alto volume
DECIMAL(p,s)⌈(p+1)/2⌉ bytesp até 31 dígitosValores monetários
FLOAT8 bytesponto flutuanteCálculos científicos
DECIMAL para dinheiro: nunca use FLOAT para valores monetários — o arredondamento binário acumula erro. Use DECIMAL(15,2) para valores em reais com centavos.

Caractere

TipoComprimentoPreenchimentoUso
CHAR(n)Fixo — 1 a 254Espaços à direitaCPF, agência, código fixo
VARCHAR(n)Variável — até 32.704NenhumNome, endereço, descrição
CLOB(n)Até 2 GBTextos longos, logs
⚠️ CHAR vs VARCHAR: comparar CHAR(10) com VARCHAR(10) pode dar resultados inesperados porque o CHAR é sempre preenchido com espaços. Use o mesmo tipo nas duas colunas de um JOIN.

Data e hora

TipoFormato internoExemplo
DATE4 bytes'2026-06-15'
TIME3 bytes'14:30:00'
TIMESTAMP10 bytes'2026-06-15-14.30.00.000000'
🦕 Atenção ao formato do TIMESTAMP: no DB2 o separador entre data e hora é hífen, não espaço: '2026-06-15-14.30.00.000000'. Isso pega muita gente que vem de outros bancos.

2. Registros especiais

Registros especiais são variáveis globais de somente leitura mantidas pelo DB2. Você os usa diretamente em qualquer expressão SQL, sem declarar nada.

SQL
-- Data e hora atuais
SELECT CURRENT DATE          -- DATE de hoje
     , CURRENT TIME          -- TIME agora
     , CURRENT TIMESTAMP     -- TIMESTAMP completo
  FROM SYSIBM.SYSDUMMY1;

-- Contexto da sessão
SELECT CURRENT SCHEMA        -- schema padrão ativo
     , CURRENT SERVER        -- nome do subsistema DB2
     , USER                  -- ID do usuário conectado
  FROM SYSIBM.SYSDUMMY1;
SYSIBM.SYSDUMMY1 é a tabela "dual" do DB2 — uma tabela de uma única linha usada quando você precisa de SELECT sem uma tabela real. Equivalente ao DUAL do Oracle.

3. Funções de string

SQLPrincipais funções de caractere
-- SUBSTR(string, início, comprimento)
SELECT SUBSTR('LADYCOBOL', 1, 4)    -- 'LADY'

-- LENGTH — comprimento real (sem espaços extras em VARCHAR)
SELECT LENGTH('COBOL   ')          -- 8 (CHAR conta os espaços)

-- STRIP / LTRIM / RTRIM — remove espaços
SELECT STRIP('  COBOL  ')         -- 'COBOL'
SELECT LTRIM('  COBOL')          -- 'COBOL'
SELECT RTRIM('COBOL  ')          -- 'COBOL'

-- UPPER / LOWER
SELECT UPPER('lady cobol')       -- 'LADY COBOL'
SELECT LOWER('LADY COBOL')       -- 'lady cobol'

-- CONCAT ou operador ||
SELECT 'LADY' || ' ' || 'COBOL'  -- 'LADY COBOL'
SELECT CONCAT('LADY', 'COBOL')  -- 'LADYCOBOL'

-- POSSTR — posição de substring (começa em 1, retorna 0 se não achar)
SELECT POSSTR('LADYCOBOL', 'COBOL') -- 5

-- REPLACE — substitui todas as ocorrências
SELECT REPLACE('01/06/2026', '/', '-') -- '01-06-2026'

-- LEFT / RIGHT
SELECT LEFT('AGENCIA001', 7)      -- 'AGENCIA'
SELECT RIGHT('AGENCIA001', 3)     -- '001'

4. Funções de data e hora

SQLExtraindo partes de datas
SELECT YEAR(CURRENT DATE)      -- 2026
     , MONTH(CURRENT DATE)     -- 6
     , DAY(CURRENT DATE)       -- 15
     , HOUR(CURRENT TIMESTAMP) -- hora (0–23)
     , MINUTE(CURRENT TIMESTAMP) -- minuto
     , SECOND(CURRENT TIMESTAMP) -- segundo
  FROM SYSIBM.SYSDUMMY1;
SQLAritmética com datas
-- Somar/subtrair com DURATION (n DAYS / MONTHS / YEARS)
SELECT CURRENT DATE + 30 DAYS     -- daqui 30 dias
     , CURRENT DATE - 1 MONTH    -- mês passado
     , CURRENT DATE + 1 YEAR     -- ano que vem
  FROM SYSIBM.SYSDUMMY1;

-- Diferença entre datas em dias (DAYS retorna inteiro)
SELECT DAYS(CURRENT DATE) - DAYS('2026-01-01')
  FROM SYSIBM.SYSDUMMY1;   -- dias desde 01/01/2026

-- TIMESTAMPDIFF — diferença entre timestamps em unidades variadas
-- Unidade: 16=min, 32=hora, 64=dia, 128=semana, 256=mês, 512=trimestre, 1024=ano
SELECT TIMESTAMPDIFF(64,
         CHAR(CURRENT TIMESTAMP - '2026-01-01-00.00.00.000000'))
  FROM SYSIBM.SYSDUMMY1;   -- diferença em dias
SQLConversão e formatação de datas
-- DATE() e TIME() convertem TIMESTAMP
SELECT DATE(CURRENT TIMESTAMP)   -- parte de data
     , TIME(CURRENT TIMESTAMP)   -- parte de hora
  FROM SYSIBM.SYSDUMMY1;

-- CHAR converte DATE para string com formato ISO, EUR, USA ou LOCAL
SELECT CHAR(CURRENT DATE, ISO)   -- '2026-06-15'
     , CHAR(CURRENT DATE, EUR)   -- '15.06.2026'
     , CHAR(CURRENT DATE, USA)   -- '06/15/2026'
  FROM SYSIBM.SYSDUMMY1;

5. Funções numéricas

SQL
-- ABS — valor absoluto
SELECT ABS(-150.75)            -- 150.75

-- MOD — resto da divisão
SELECT MOD(17, 5)              -- 2

-- INTEGER — trunca para inteiro (não arredonda)
SELECT INTEGER(3.9)            -- 3

-- DECIMAL(valor, precisão, escala) — converte com precisão controlada
SELECT DECIMAL(1234.567, 10, 2) -- 1234.57 (arredonda)

-- ROUND — arredondamento
SELECT ROUND(3.456, 2)         -- 3.46
SELECT ROUND(3.454, 2)         -- 3.45

6. Funções de conversão

Conversão entre tipos é frequente em COBOL+DB2 — variáveis host são declaradas como numérico ou alfanumérico e nem sempre o tipo coincide com o da coluna.

SQL
-- CHAR — converte número ou data para string
SELECT CHAR(12345)             -- '12345'
SELECT CHAR(9.99)              -- '9.99'
SELECT CHAR(CURRENT DATE, ISO) -- '2026-06-15'

-- DIGITS — número para string com zeros à esquerda (sem sinal)
SELECT DIGITS(42)              -- '0000000042' (para DECIMAL(10,0))

-- HEX — representação hexadecimal
SELECT HEX('A')               -- 'C1' (EBCDIC)

-- INTEGER / BIGINT / SMALLINT — string ou decimal para inteiro
SELECT INTEGER('2026')         -- 2026

-- CAST — conversão explícita (mais portável entre bancos)
SELECT CAST('2026-06-15' AS DATE)
SELECT CAST(SALDO AS DECIMAL(15,2))
DIGITS vs CHAR: use DIGITS quando precisar de número com zeros à esquerda sem ponto decimal — muito comum para formatar campos de relatório em COBOL.

7. Tratamento de nulo

NULL no SQL significa ausência de valor — não é zero, não é espaço, não é falso. Qualquer expressão com NULL resulta em NULL.

SQL
-- COALESCE — retorna o primeiro valor não nulo da lista
SELECT COALESCE(EMAIL, TELEFONE, 'SEM CONTATO')
  FROM CLIENTES;

-- VALUE — sinônimo de COALESCE no DB2 (função proprietária IBM)
SELECT VALUE(LIMITE_CREDITO, 0)
  FROM CONTAS;

-- NULLIF — retorna NULL se os dois valores forem iguais
SELECT NULLIF(DIVISOR, 0)      -- evita divisão por zero

-- Verificação correta de nulo (nunca use = NULL)
SELECT * FROM CONTAS WHERE LIMITE_CREDITO IS NULL
SELECT * FROM CONTAS WHERE LIMITE_CREDITO IS NOT NULL
⚠️ Armadilha clássica: WHERE COLUNA = NULL nunca retorna linhas no DB2. NULL não é igual a nada — nem a outro NULL. Use sempre IS NULL ou IS NOT NULL.

8. Funções de agregação

SQLFunções de coluna
SELECT COUNT(*)              -- total de linhas (inclui NULLs)
     , COUNT(EMAIL)          -- linhas onde EMAIL não é NULL
     , COUNT(DISTINCT AGENCIA) -- agências únicas
     , SUM(SALDO)            -- soma (ignora NULL)
     , AVG(SALDO)            -- média (ignora NULL)
     , MIN(DT_ABERTURA)      -- data mais antiga
     , MAX(SALDO)            -- maior saldo
  FROM CONTAS;
SQLGROUP BY e HAVING
-- Saldo total por agência, só para agências com mais de 100 contas
SELECT COD_AGENCIA
     , COUNT(*)           AS QTD_CONTAS
     , SUM(SALDO)         AS SALDO_TOTAL
     , AVG(SALDO)         AS SALDO_MEDIO
  FROM CONTAS
 GROUP BY COD_AGENCIA
HAVING COUNT(*) > 100
 ORDER BY SALDO_TOTAL DESC;
🦕 Analogia: WHERE filtra linhas antes de agrupar. HAVING filtra grupos depois de agrupar. Se você quer filtrar por valor calculado (SUM, COUNT...) use HAVING — WHERE não tem acesso a esses valores.

9. Diferenças do SQL padrão

Quem vem de MySQL, PostgreSQL ou SQL Server vai encontrar algumas surpresas no DB2 para z/OS.

FETCH FIRST em vez de LIMIT

SQL
-- DB2 — limita linhas retornadas
SELECT * FROM TRANSACOES
 ORDER BY DT_TRANSACAO DESC
FETCH FIRST 10 ROWS ONLY;

-- NÃO EXISTE no DB2 z/OS:
-- SELECT * FROM TRANSACOES LIMIT 10       ← MySQL/PostgreSQL
-- SELECT TOP 10 * FROM TRANSACOES         ← SQL Server

Sem tipo BOOLEAN

O DB2 para z/OS não tem tipo BOOLEAN. Condições lógicas são representadas com SMALLINT (0/1) ou CHAR(1) ('S'/'N'). Flags no banco geralmente são colunas CHAR(1) NOT NULL DEFAULT 'N'.

Concatenação com ||

SQL
-- DB2 usa || para concatenar strings
SELECT NOME || ' ' || SOBRENOME AS NOME_COMPLETO
  FROM CLIENTES;

-- Cuidado: NULL || 'algo' = NULL
SELECT COALESCE(NOME, '') || ' ' || COALESCE(SOBRENOME, '')
  FROM CLIENTES;

Aritmética de datas com DURATION

SQL
-- DB2 — sintaxe própria para aritmética de datas
SELECT DT_VENCIMENTO + 5 DAYS   -- adiciona 5 dias
     , DT_VENCIMENTO - 1 MONTH  -- subtrai 1 mês
  FROM TITULOS;

-- Subtração entre duas datas resulta em DURATION (não em INTEGER)
-- Para obter inteiro use a função DAYS()
SELECT DAYS(DT_VENCIMENTO) - DAYS(CURRENT DATE) AS DIAS_RESTANTES
  FROM TITULOS;

WITH (Common Table Expression)

SQLCTE no DB2 — disponível desde a versão 8
WITH CONTAS_ATIVAS AS (
    SELECT COD_CLIENTE, SALDO
      FROM CONTAS
     WHERE STATUS = 'A'
)
SELECT C.NOME, CA.SALDO
  FROM CLIENTES C
  JOIN CONTAS_ATIVAS CA ON C.COD_CLIENTE = CA.COD_CLIENTE
 WHERE CA.SALDO > 1000;

10. JOINs e subqueries

SQLTipos de JOIN
-- INNER JOIN — só linhas com correspondência nos dois lados
SELECT C.NOME, T.VL_TRANSACAO, T.DT_TRANSACAO
  FROM CLIENTES C
 INNER JOIN TRANSACOES T ON C.COD_CLIENTE = T.COD_CLIENTE;

-- LEFT OUTER JOIN — todos os clientes, mesmo sem transações
SELECT C.NOME, T.VL_TRANSACAO
  FROM CLIENTES C
  LEFT OUTER JOIN TRANSACOES T ON C.COD_CLIENTE = T.COD_CLIENTE;

-- FULL OUTER JOIN — todos de ambos os lados
SELECT C.NOME, T.VL_TRANSACAO
  FROM CLIENTES C
  FULL OUTER JOIN TRANSACOES T ON C.COD_CLIENTE = T.COD_CLIENTE;
SQLSubqueries comuns
-- IN com subquery
SELECT * FROM CLIENTES
 WHERE COD_CLIENTE IN
       (SELECT COD_CLIENTE FROM CONTAS WHERE SALDO > 50000);

-- EXISTS — eficiente para checar existência (para quando acha a 1ª linha)
SELECT * FROM CLIENTES C
 WHERE EXISTS (
       SELECT 1 FROM CONTAS A
        WHERE A.COD_CLIENTE = C.COD_CLIENTE
          AND A.STATUS = 'INADIMPLENTE');

-- NOT EXISTS — clientes sem conta inadimplente
SELECT * FROM CLIENTES C
 WHERE NOT EXISTS (
       SELECT 1 FROM CONTAS A
        WHERE A.COD_CLIENTE = C.COD_CLIENTE
          AND A.STATUS = 'INADIMPLENTE');
SQLUNION e UNION ALL
-- UNION ALL — une dois resultados sem remover duplicatas (mais rápido)
SELECT COD_CLIENTE, 'ATIVO' AS ORIGEM FROM CONTAS_ATIVAS
UNION ALL
SELECT COD_CLIENTE, 'INATIVO' AS ORIGEM FROM CONTAS_INATIVAS;

-- UNION — remove duplicatas (faz sort interno — mais caro)
SELECT COD_CLIENTE FROM CONTAS_ATIVAS
UNION
SELECT COD_CLIENTE FROM CONTAS_INATIVAS;

11. Exemplos práticos

SQLRelatório de contas por faixa de saldo
SELECT
    CASE
        WHEN SALDO < 0              THEN 'NEGATIVO'
        WHEN SALDO = 0              THEN 'ZERADO'
        WHEN SALDO BETWEEN 1 AND 999  THEN 'BAIXO'
        WHEN SALDO BETWEEN 1000 AND 9999 THEN 'MEDIO'
        ELSE                         'ALTO'
    END                       AS FAIXA
  , COUNT(*)                  AS QTD
  , SUM(SALDO)                AS TOTAL
  FROM CONTAS
 GROUP BY
    CASE
        WHEN SALDO < 0              THEN 'NEGATIVO'
        WHEN SALDO = 0              THEN 'ZERADO'
        WHEN SALDO BETWEEN 1 AND 999  THEN 'BAIXO'
        WHEN SALDO BETWEEN 1000 AND 9999 THEN 'MEDIO'
        ELSE                         'ALTO'
    END
 ORDER BY TOTAL DESC;
SQLTop 5 clientes com maior saldo total — usando FETCH FIRST
SELECT C.NOME
     , COUNT(A.COD_CONTA)   AS QTD_CONTAS
     , SUM(A.SALDO)         AS SALDO_TOTAL
     , CHAR(CURRENT DATE, ISO) AS DT_CONSULTA
  FROM CLIENTES C
  JOIN CONTAS A ON C.COD_CLIENTE = A.COD_CLIENTE
 WHERE A.STATUS = 'A'
 GROUP BY C.NOME
HAVING SUM(A.SALDO) > 0
 ORDER BY SALDO_TOTAL DESC
FETCH FIRST 5 ROWS ONLY;
🟣 Diferença importante entre DB2 e outros bancos: No DB2 z/OS, o GROUP BY precisa repetir a expressão CASE completa — não é possível referenciar o alias da coluna no GROUP BY (ao contrário do PostgreSQL). Para evitar repetição use uma subquery ou CTE.