sqlpostgresqlfloorrounding

FLOOR no SQL: arredondar para baixo ate o inteiro anterior e agrupar em buckets

Como o FLOOR arredonda um numero para baixo ate o inteiro anterior, por que negativos se afastam do zero e como difere de TRUNC.

2 min de leituraReferencesql · postgresql · floor · rounding · bucketing · clickhouse

FLOOR arredonda um numero para baixo ate o inteiro mais proximo que nao seja maior que o valor original. E o "piso" matematico: na reta numerica voce sempre se desloca para a esquerda, em direcao ao inteiro menor.

O que o FLOOR faz

A funcao recebe qualquer numero e devolve o maior inteiro que seja menor ou igual ao argumento. A parte decimal simplesmente e descartada, mas apenas para numeros nao negativos.

SELECT
  FLOOR(4.9)  AS a,   -- 4
  FLOOR(4.1)  AS b,   -- 4
  FLOOR(4.0)  AS c,   -- 4
  FLOOR(-4.1) AS d;   -- -5

Propriedades principais:

  • O arredondamento e sempre para baixo, nunca para o mais proximo: 4.9 vira 4, nao 5.
  • Um argumento inteiro nao muda: FLOOR(4.0) e 4.
  • No PostgreSQL o tipo do resultado acompanha o do argumento: numeric continua numeric, double precision continua double precision. Adicione ::int quando quiser um integer de verdade.

Negativos se afastam do zero

Essa e a principal armadilha. Para numeros positivos o FLOOR parece apenas "cortar" a parte decimal, mas para negativos ele arredonda para mais longe do zero, porque o inteiro menor fica abaixo.

SELECT
  FLOOR(2.7)  AS pos,   -- 2
  FLOOR(-2.7) AS neg;   -- -3

Compare com TRUNC, que sempre descarta os decimais e se move em direcao ao zero:

SELECT
  TRUNC(-2.7) AS truncated,   -- -2
  FLOOR(-2.7) AS floored;     -- -3

Atencao: se voce calcula faixas de idade, pontuacoes ou coordenadas onde aparecem valores negativos, FLOOR e TRUNC dao resultados diferentes. Use TRUNC para "remover os decimais"; use FLOOR para "arredondar para baixo no eixo".

Buckets: FLOOR(x/n)*n

O truque mais pratico e distribuir valores em intervalos iguais. Para agrupar valores de pedidos em buckets de 100, divida por 100, aplique FLOOR e multiplique de volta.

SELECT
  FLOOR(amount / 100) * 100 AS bucket,
  COUNT(*)                  AS orders
FROM orders
WHERE status = 'paid'
GROUP BY FLOOR(amount / 100) * 100
ORDER BY bucket;

Um pedido de 250 cai no bucket 200 e um de 99 no bucket 0. O mesmo truque distribui os salarios dos funcionarios em faixas de dez mil:

SELECT
  FLOOR(salary / 10000) * 10000 AS salary_band,
  COUNT(*)                      AS headcount
FROM employees
GROUP BY FLOOR(salary / 10000) * 10000
ORDER BY salary_band;

Atencao: cuidado com a divisao inteira. Se amount for do tipo integer, entao amount / 100 ja sera truncado para inteiro antes mesmo de o FLOOR rodar, e os buckets desviam. Converta para um tipo decimal: FLOOR(amount::numeric / 100) * 100.

Par com CEIL e diferencas entre bancos

FLOOR sempre anda junto com CEIL (tambem CEILING), que arredonda para cima. Juntos eles prendem um valor em um intervalo inteiro.

SELECT
  FLOOR(4.2) AS low,   -- 4
  CEIL(4.2)  AS high;  -- 5

Diferencas por dialeto:

  • PostgreSQL: FLOOR mantem o tipo numerico do argumento e os negativos sao tratados com matematica estrita.
  • MySQL: FLOOR sobre DECIMAL devolve um inteiro, mas para DOUBLE o resultado tambem e DOUBLE; tome cuidado ao comparar tipos.
  • ClickHouse: oferece floor(x) mais a extensao floor(x, N) que arredonda para N casas decimais, algo que o SQL padrao nao tem.

Um padrao util muito comum e distribuir linhas de forma uniforme entre N grupos para amostragem ou sharding:

SELECT
  id,
  FLOOR(RANDOM() * 4)::int AS shard   -- 0..3
FROM users;

Lembre de tres coisas: FLOOR arredonda para baixo, negativos se afastam do zero, e para "cortar os decimais em direcao ao zero" voce precisa de TRUNC, nao de FLOOR.

Pratique com exercícios reais

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

Abrir o treinador