La division entera devuelve solo el cociente y descarta la parte fraccionaria. Suena trivial, pero es justo aqui donde la analitica se rompe con mas frecuencia: un casting de tipo despistado y 7 / 2 pasa de 3 a 3.5.
Dividir dos enteros en PostgreSQL
En PostgreSQL el operador / mira los tipos de los operandos. Si ambos son enteros, el resultado tambien es entero y se trunca hacia cero (truncamiento, no floor):
SELECT 7 / 2;
SELECT -7 / 2;
SELECT 100 / 30;
Esto es comodo para agrupar en cubos. Por ejemplo, repartimos los usuarios en cubos de 100 ids:
SELECT
id / 100 AS bucket,
count(*) AS users
FROM users
GROUP BY id / 100
ORDER BY bucket;
Cuidado: el truncamiento va hacia cero, no hacia abajo. Para numeros positivos no hay diferencia, pero -7 / 2 da -3, mientras que el floor matematico daria -4. Cuando de verdad necesitas el comportamiento de floor, llama a floor() de forma explicita.
La trampa del casting
El error clasico es convertir sin querer un operando en numero de coma flotante. Basta con un solo numeric o ::float para que la division se vuelva fraccionaria:
SELECT 7 / 2;
SELECT 7 / 2.0;
SELECT 7::float / 2;
SELECT amount / 2 FROM orders;
Si amount esta declarado como NUMERIC, entonces amount / 2 ya es fraccionario. Para obtener el numero entero de "mitades completas", trunca el resultado de forma explicita con DIV o floor().
La funcion DIV(a, b)
PostgreSQL ofrece la funcion div(a, b), que siempre realiza division entera y devuelve el cociente truncado hacia cero, independientemente de los tipos de los operandos:
SELECT div(7, 2);
SELECT div(7.9, 2.0);
SELECT div(-7, 2);
Es mas segura que / porque no depende de que los operandos sean enteros. Ideal para columnas de dinero declaradas como NUMERIC. Contemos cuantas centenas completas caben en cada pedido:
SELECT
id,
amount,
div(amount, 100) AS full_hundreds
FROM orders;
El operador DIV de MySQL
En MySQL / siempre devuelve un resultado fraccionario, incluso con dos enteros: SELECT 7 / 2 da 3.5. Para la division entera existe un operador dedicado, DIV:
SELECT 7 DIV 2;
SELECT 100 DIV 30;
SELECT id DIV 100 AS bucket FROM users;
En ClickHouse existen ambas formas: la funcion intDiv(7, 2) y el habitual 7 / 2 para la division en coma flotante. Asi que la misma consulta se comporta de forma distinta segun el motor, algo que conviene tener presente al portar codigo.
DIV junto con MOD: cociente y resto
La division entera casi siempre va acompanada de MOD (el resto). Juntos dan la imagen completa: cuantas veces enteras cabe el divisor y que sobra.
SELECT
amount,
div(amount, 100) AS whole_hundreds,
mod(amount, 100) AS remainder
FROM orders;
Un truco clasico es convertir segundos en minutos y segundos en una sola 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;
Otro ejemplo: repartir a los empleados en turnos de forma ciclica (round-robin) usando el resto:
SELECT
name,
dept,
mod(id, 3) AS shift
FROM employees
ORDER BY shift, name;
Cuidado: en PostgreSQL el signo de mod sigue al dividendo, asi que mod(-7, 3) devuelve -1, no 2. Si necesitas un resto siempre no negativo (por ejemplo, para sharding por hash), envuelvelo: mod(mod(x, n) + n, n).
Recuerda lo esencial: en PostgreSQL / trunca solo cuando ambos operandos son enteros, en MySQL necesitas el operador DIV para ello, y la funcion div(a, b) es la forma mas portable y predecible de obtener un cociente entero en ambos motores.
La division entera devuelve solo el cociente y descarta la parte fraccionaria. Suena trivial, pero es justo aqui donde la analitica se rompe con mas frecuencia: un casting de tipo despistado y
7 / 2pasa de3a3.5.Dividir dos enteros en PostgreSQL
En PostgreSQL el operador
/mira los tipos de los operandos. Si ambos son enteros, el resultado tambien es entero y se trunca hacia cero (truncamiento, no floor):SELECT 7 / 2; -- 3 SELECT -7 / 2; -- -3, not -4 SELECT 100 / 30; -- 3Esto es comodo para agrupar en cubos. Por ejemplo, repartimos los usuarios en cubos de 100 ids:
SELECT id / 100 AS bucket, count(*) AS users FROM users GROUP BY id / 100 ORDER BY bucket;Cuidado: el truncamiento va hacia cero, no hacia abajo. Para numeros positivos no hay diferencia, pero
-7 / 2da-3, mientras que el floor matematico daria-4. Cuando de verdad necesitas el comportamiento de floor, llama afloor()de forma explicita.La trampa del casting
El error clasico es convertir sin querer un operando en numero de coma flotante. Basta con un solo
numerico::floatpara que la division se vuelva fraccionaria: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 fraccionarioSi
amountesta declarado comoNUMERIC, entoncesamount / 2ya es fraccionario. Para obtener el numero entero de "mitades completas", trunca el resultado de forma explicita conDIVofloor().La funcion DIV(a, b)
PostgreSQL ofrece la funcion
div(a, b), que siempre realiza division entera y devuelve el cociente truncado hacia cero, independientemente de los tipos de los operandos:SELECT div(7, 2); -- 3 SELECT div(7.9, 2.0); -- 3 (works on numeric too) SELECT div(-7, 2); -- -3Es mas segura que
/porque no depende de que los operandos sean enteros. Ideal para columnas de dinero declaradas comoNUMERIC. Contemos cuantas centenas completas caben en cada pedido:SELECT id, amount, div(amount, 100) AS full_hundreds FROM orders;El operador DIV de MySQL
En MySQL
/siempre devuelve un resultado fraccionario, incluso con dos enteros:SELECT 7 / 2da3.5. Para la division entera existe un operador dedicado,DIV:-- MySQL SELECT 7 DIV 2; -- 3 SELECT 100 DIV 30; -- 3 SELECT id DIV 100 AS bucket FROM users;En ClickHouse existen ambas formas: la funcion
intDiv(7, 2)y el habitual7 / 2para la division en coma flotante. Asi que la misma consulta se comporta de forma distinta segun el motor, algo que conviene tener presente al portar codigo.DIV junto con MOD: cociente y resto
La division entera casi siempre va acompanada de
MOD(el resto). Juntos dan la imagen completa: cuantas veces enteras cabe el divisor y que sobra.SELECT amount, div(amount, 100) AS whole_hundreds, mod(amount, 100) AS remainder FROM orders;Un truco clasico es convertir segundos en minutos y segundos en una sola 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;Otro ejemplo: repartir a los empleados en turnos de forma ciclica (round-robin) usando el resto:
SELECT name, dept, mod(id, 3) AS shift -- 0, 1, 2 FROM employees ORDER BY shift, name;Cuidado: en PostgreSQL el signo de
modsigue al dividendo, asi quemod(-7, 3)devuelve-1, no2. Si necesitas un resto siempre no negativo (por ejemplo, para sharding por hash), envuelvelo:mod(mod(x, n) + n, n).Recuerda lo esencial: en PostgreSQL
/trunca solo cuando ambos operandos son enteros, en MySQL necesitas el operadorDIVpara ello, y la funciondiv(a, b)es la forma mas portable y predecible de obtener un cociente entero en ambos motores.