A divisao inteira retorna apenas o quociente e descarta a parte fracionaria. Parece trivial, mas e justamente aqui que a analise de dados quebra com mais frequencia: um cast de tipo distraido e 7 / 2 passa de 3 para 3.5.
Dividir dois inteiros no PostgreSQL
No PostgreSQL o operador / olha os tipos dos operandos. Se ambos sao inteiros, o resultado tambem e inteiro e e truncado em direcao ao zero (truncamento, nao floor):
SELECT 7 / 2;
SELECT -7 / 2;
SELECT 100 / 30;
Isso e pratico para agrupar em faixas. Por exemplo, distribuimos os usuarios em faixas de 100 ids:
SELECT
id / 100 AS bucket,
count(*) AS users
FROM users
GROUP BY id / 100
ORDER BY bucket;
Atencao: o truncamento vai em direcao ao zero, nao para baixo. Para numeros positivos nao ha diferenca, mas -7 / 2 da -3, enquanto o floor matematico daria -4. Quando voce realmente precisa do comportamento de floor, chame floor() de forma explicita.
A armadilha do cast
O erro classico e transformar sem querer um operando em numero de ponto flutuante. Basta um unico numeric ou ::float para que a divisao fique fracionaria:
SELECT 7 / 2;
SELECT 7 / 2.0;
SELECT 7::float / 2;
SELECT amount / 2 FROM orders;
Se amount esta declarado como NUMERIC, entao amount / 2 ja e fracionario. Para obter o numero inteiro de "metades completas", trunque o resultado de forma explicita com DIV ou floor().
A funcao DIV(a, b)
O PostgreSQL oferece a funcao div(a, b), que sempre executa a divisao inteira e retorna o quociente truncado em direcao ao zero, independentemente dos tipos dos operandos:
SELECT div(7, 2);
SELECT div(7.9, 2.0);
SELECT div(-7, 2);
E mais segura que / porque nao depende de os operandos serem inteiros. Otima para colunas de dinheiro declaradas como NUMERIC. Vamos contar quantas centenas completas cabem em cada pedido:
SELECT
id,
amount,
div(amount, 100) AS full_hundreds
FROM orders;
O operador DIV do MySQL
No MySQL / sempre retorna um resultado fracionario, mesmo com dois inteiros: SELECT 7 / 2 da 3.5. Para a divisao inteira existe um operador dedicado, DIV:
SELECT 7 DIV 2;
SELECT 100 DIV 30;
SELECT id DIV 100 AS bucket FROM users;
No ClickHouse existem as duas formas: a funcao intDiv(7, 2) e o habitual 7 / 2 para a divisao em ponto flutuante. Ou seja, a mesma consulta se comporta de forma diferente conforme o motor, algo que vale a pena lembrar ao portar codigo.
A divisao inteira quase sempre anda junto com MOD (o resto). Juntos eles dao o quadro completo: quantas vezes inteiras o divisor cabe e o que sobra.
SELECT
amount,
div(amount, 100) AS whole_hundreds,
mod(amount, 100) AS remainder
FROM orders;
Um truque classico e converter segundos em minutos e segundos numa unica consulta:
SELECT
id,
extract(epoch FROM (now() - created_at))::int AS age_seconds,
div(extract(epoch FROM (now() - created_at))::int, 60) AS minutes,
mod(extract(epoch FROM (now() - created_at))::int, 60) AS seconds
FROM orders;
Outro exemplo: distribuir os funcionarios em turnos de forma ciclica (round-robin) usando o resto:
SELECT
name,
dept,
mod(id, 3) AS shift
FROM employees
ORDER BY shift, name;
Atencao: no PostgreSQL o sinal de mod segue o dividendo, entao mod(-7, 3) retorna -1, nao 2. Se voce precisa de um resto sempre nao negativo (por exemplo, para sharding por hash), envolva-o: mod(mod(x, n) + n, n).
Lembre do essencial: no PostgreSQL / trunca apenas quando ambos os operandos sao inteiros, no MySQL voce precisa do operador DIV para isso, e a funcao div(a, b) e a forma mais portavel e previsivel de obter um quociente inteiro em ambos os motores.
A divisao inteira retorna apenas o quociente e descarta a parte fracionaria. Parece trivial, mas e justamente aqui que a analise de dados quebra com mais frequencia: um cast de tipo distraido e
7 / 2passa de3para3.5.Dividir dois inteiros no PostgreSQL
No PostgreSQL o operador
/olha os tipos dos operandos. Se ambos sao inteiros, o resultado tambem e inteiro e e truncado em direcao ao zero (truncamento, nao floor):SELECT 7 / 2; -- 3 SELECT -7 / 2; -- -3, not -4 SELECT 100 / 30; -- 3Isso e pratico para agrupar em faixas. Por exemplo, distribuimos os usuarios em faixas de 100 ids:
SELECT id / 100 AS bucket, count(*) AS users FROM users GROUP BY id / 100 ORDER BY bucket;Atencao: o truncamento vai em direcao ao zero, nao para baixo. Para numeros positivos nao ha diferenca, mas
-7 / 2da-3, enquanto o floor matematico daria-4. Quando voce realmente precisa do comportamento de floor, chamefloor()de forma explicita.A armadilha do cast
O erro classico e transformar sem querer um operando em numero de ponto flutuante. Basta um unico
numericou::floatpara que a divisao fique fracionaria:SELECT 7 / 2; -- 3 (int / int) SELECT 7 / 2.0; -- 3.5 (int / numeric) SELECT 7::float / 2; -- 3.5 SELECT amount / 2 FROM orders; -- amount NUMERIC -> resultado fracionarioSe
amountesta declarado comoNUMERIC, entaoamount / 2ja e fracionario. Para obter o numero inteiro de "metades completas", trunque o resultado de forma explicita comDIVoufloor().A funcao DIV(a, b)
O PostgreSQL oferece a funcao
div(a, b), que sempre executa a divisao inteira e retorna o quociente truncado em direcao ao zero, independentemente dos tipos dos operandos:SELECT div(7, 2); -- 3 SELECT div(7.9, 2.0); -- 3 (works on numeric too) SELECT div(-7, 2); -- -3E mais segura que
/porque nao depende de os operandos serem inteiros. Otima para colunas de dinheiro declaradas comoNUMERIC. Vamos contar quantas centenas completas cabem em cada pedido:SELECT id, amount, div(amount, 100) AS full_hundreds FROM orders;O operador DIV do MySQL
No MySQL
/sempre retorna um resultado fracionario, mesmo com dois inteiros:SELECT 7 / 2da3.5. Para a divisao inteira existe um operador dedicado,DIV:-- MySQL SELECT 7 DIV 2; -- 3 SELECT 100 DIV 30; -- 3 SELECT id DIV 100 AS bucket FROM users;No ClickHouse existem as duas formas: a funcao
intDiv(7, 2)e o habitual7 / 2para a divisao em ponto flutuante. Ou seja, a mesma consulta se comporta de forma diferente conforme o motor, algo que vale a pena lembrar ao portar codigo.DIV junto com MOD: quociente e resto
A divisao inteira quase sempre anda junto com
MOD(o resto). Juntos eles dao o quadro completo: quantas vezes inteiras o divisor cabe e o que sobra.SELECT amount, div(amount, 100) AS whole_hundreds, mod(amount, 100) AS remainder FROM orders;Um truque classico e converter segundos em minutos e segundos numa unica consulta:
SELECT id, extract(epoch FROM (now() - created_at))::int AS age_seconds, div(extract(epoch FROM (now() - created_at))::int, 60) AS minutes, mod(extract(epoch FROM (now() - created_at))::int, 60) AS seconds FROM orders;Outro exemplo: distribuir os funcionarios em turnos de forma ciclica (round-robin) usando o resto:
SELECT name, dept, mod(id, 3) AS shift -- 0, 1, 2 FROM employees ORDER BY shift, name;Atencao: no PostgreSQL o sinal de
modsegue o dividendo, entaomod(-7, 3)retorna-1, nao2. Se voce precisa de um resto sempre nao negativo (por exemplo, para sharding por hash), envolva-o:mod(mod(x, n) + n, n).Lembre do essencial: no PostgreSQL
/trunca apenas quando ambos os operandos sao inteiros, no MySQL voce precisa do operadorDIVpara isso, e a funcaodiv(a, b)e a forma mais portavel e previsivel de obter um quociente inteiro em ambos os motores.