sqlpostgresqltruncfloor

TRUNC no SQL: descartar a parte fracionaria em direcao a zero sem arredondar

Como o TRUNC corta a parte fracionaria em direcao a zero, como TRUNC(x, n) recorta casas decimais e por que difere do FLOOR em negativos.

2 min de leituraReferencesql · postgresql · trunc · floor · rounding · mysql

TRUNC descarta a parte fracionaria de um numero sem arredonda-lo: tudo o que vem depois do ponto e simplesmente cortado. Ao contrario de ROUND, a direcao e sempre a mesma — em direcao a zero — entao o resultado e previsivel tanto para valores positivos quanto negativos.

O que o TRUNC faz

Na sua forma mais simples, TRUNC(x) retorna a parte inteira de um numero, descartando a fracao. Nao ha arredondamento para o mais proximo: 3.99 vira 3, e nao 4.

SELECT
  TRUNC(3.99)   AS a,   -- 3
  TRUNC(3.01)   AS b,   -- 3
  TRUNC(-3.99)  AS c,   -- -3
  TRUNC(2.5)    AS d;   -- 2

Propriedades principais:

  • O truncamento vai sempre em direcao a zero, e nao para baixo: -3.99 da -3, porque -3 esta mais perto de zero que -4.
  • ROUND(2.5) daria 3, mas TRUNC(2.5) da 2: o TRUNC nunca olha para os digitos que descarta.
  • O tipo do resultado e numeric, entao a precisao e preservada.

TRUNC(x, n): cortar por casas decimais

O segundo argumento define quantos digitos depois do ponto manter. O resto e cortado sem arredondar.

SELECT
  TRUNC(123.4567, 2)  AS two_dp,    -- 123.45
  TRUNC(123.4567, 0)  AS zero_dp,   -- 123
  TRUNC(123.4567, -1) AS neg_one;   -- 120

Um n negativo trunca a esquerda do ponto: -1 zera as unidades, -2 as dezenas. Aplique isso na tabela employees para agrupar salarios em centenas grosseiras sem arredondar para cima:

SELECT
  name,
  salary,
  TRUNC(salary, -2) AS salary_bucket
FROM employees
ORDER BY salary DESC;

Um funcionario que ganha 4999 cai no grupo 4900, e nao 5000 — o truncamento nunca empurra um valor para a proxima casa.

TRUNC contra FLOOR em numeros negativos

Para numeros positivos, TRUNC e FLOOR parecem identicos. A divergencia comeca nos negativos: FLOOR arredonda para baixo (em direcao a menos infinito), enquanto TRUNC arredonda em direcao a zero.

SELECT
  FLOOR(-3.2) AS floor_neg,  -- -4
  TRUNC(-3.2) AS trunc_neg,  -- -3
  FLOOR(3.2)  AS floor_pos,  --  3
  TRUNC(3.2)  AS trunc_pos;  --  3

Isso e facil de transformar em bug. Digamos que orders guarde reembolsos com amount negativo e voce queira os "dolares inteiros":

SELECT
  id,
  amount,
  FLOOR(amount) AS whole_floor,  -- -16 para -15.30
  TRUNC(amount) AS whole_trunc   -- -15 para -15.30
FROM orders
WHERE amount < 0;

Pegadinha: se voce quer um "descartar a fracao" simetrico, use TRUNC. O FLOOR sobre reembolsos infla o valor debitado em um dolar inteiro.

Truncar dinheiro contra arredondar

Dinheiro e um campo minado a parte. A contabilidade costuma querer arredondamento (ROUND), mas alguns calculos — taxas, acumulo de juros, dividir um preco — sao obrigados por lei ou contrato a truncar, para nunca "presentear" o cliente com um centavo a mais.

SELECT
  u.id,
  SUM(o.amount)                         AS gross,
  ROUND(SUM(o.amount) * 0.029, 2)       AS fee_rounded,   -- arredondamento
  TRUNC(SUM(o.amount) * 0.029, 2)       AS fee_truncated  -- truncamento
FROM users u
JOIN orders o ON o.user_id = u.id
WHERE o.status = 'paid'
GROUP BY u.id;

Lembre-se:

  • ROUND(2.575, 2) pode dar 2.58, enquanto TRUNC(2.575, 2) da sempre 2.57.
  • O truncamento subestima o resultado de forma sistematica; o arredondamento nao. Escolha de forma deliberada.
  • Calcule sobre numeric, e nao sobre float: TRUNC de um float binario pode te surpreender por causa do erro de representacao.

MySQL: a funcao se chama TRUNCATE

O MySQL nao tem a funcao TRUNC — seu papel e cumprido por TRUNCATE, e ali o segundo argumento e obrigatorio.

-- MySQL
SELECT
  TRUNCATE(123.4567, 2) AS two_dp,   -- 123.45
  TRUNCATE(123.4567, 0) AS zero_dp;  -- 123

Nao confunda com o comando TRUNCATE TABLE, que esvazia uma tabela instantaneamente — essa e uma operacao completamente diferente. O ClickHouse oferece tanto trunc(x) quanto truncate(x, n) como sinonimos. Lembre-se de uma coisa: TRUNC significa "cortar em direcao a zero sem arredondar", e o nome da funcao e se o segundo argumento e obrigatorio dependem do motor.

Pratique com exercícios reais

Resolva exercícios no treinador de SQL com correção instantânea e dicas.

Abrir o treinador