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,
FLOOR(4.1) AS b,
FLOOR(4.0) AS c,
FLOOR(-4.1) AS d;
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,
FLOOR(-2.7) AS neg;
Compare com TRUNC, que sempre descarta os decimais e se move em direcao ao zero:
SELECT
TRUNC(-2.7) AS truncated,
FLOOR(-2.7) AS floored;
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.
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,
CEIL(4.2) AS high;
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
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.
FLOORarredonda 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; -- -5Propriedades principais:
4.9vira4, nao5.FLOOR(4.0)e4.numericcontinuanumeric,double precisioncontinuadouble precision. Adicione::intquando quiser umintegerde verdade.Negativos se afastam do zero
Essa e a principal armadilha. Para numeros positivos o
FLOORparece 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; -- -3Compare 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; -- -3Buckets: 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
FLOORe 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
250cai no bucket200e um de99no bucket0. 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;Par com CEIL e diferencas entre bancos
FLOORsempre anda junto comCEIL(tambemCEILING), 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; -- 5Diferencas por dialeto:
FLOORmantem o tipo numerico do argumento e os negativos sao tratados com matematica estrita.FLOORsobreDECIMALdevolve um inteiro, mas paraDOUBLEo resultado tambem eDOUBLE; tome cuidado ao comparar tipos.floor(x)mais a extensaofloor(x, N)que arredonda paraNcasas 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:
FLOORarredonda para baixo, negativos se afastam do zero, e para "cortar os decimais em direcao ao zero" voce precisa deTRUNC, nao deFLOOR.