sqlpostgresqlmysqlmath

Division entera en SQL: DIV, MOD y la trampa del casting

Como funciona la division entera en PostgreSQL y MySQL, cuando usar DIV y como combinarla con MOD para obtener cociente y resto a la vez.

2 min de lecturaReferencesql · postgresql · mysql · math · division

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;     -- 3
SELECT -7 / 2;    -- -3, not -4
SELECT 100 / 30;  -- 3

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;            -- 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 fraccionario

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);        -- 3
SELECT div(7.9, 2.0);    -- 3   (works on numeric too)
SELECT div(-7, 2);       -- -3

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:

-- 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 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   -- 0, 1, 2
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.

Practica con ejercicios reales

Resuelve ejercicios en el entrenador de SQL con corrección instantánea y pistas.

Abrir el entrenador