sqlpostgresqlmathnumeric

ABS en SQL: valor absoluto, diferencias y comprobaciones con tolerancia

Como ABS calcula la magnitud, mide la diferencia entre dos valores, sirve en WHERE con tolerancia y se combina con SIGN.

3 min de lecturaReferencesql · postgresql · math · numeric · mysql · clickhouse

ABS devuelve el valor absoluto de un numero: su magnitud sin el signo. Suena trivial, pero es la funcion que responde "que tan lejos" cuando la direccion no importa: la diferencia entre el total esperado y el real, una brecha salarial, una desviacion respecto a un objetivo.

Magnitud y valor absoluto

ABS(x) elimina el signo: un negativo se vuelve positivo, mientras que el cero y los positivos quedan igual.

SELECT ABS(-7),     -- 7
       ABS(7),      -- 7
       ABS(0);      -- 0

El tipo del resultado coincide con el del argumento: un integer sigue siendo integer, un numeric sigue siendo numeric y un double precision sigue siendo float. Eso ayuda cuando quieres evitar conversiones implicitas y perdida de precision en columnas monetarias.

-- magnitude of a signed balance adjustment
SELECT id, amount, ABS(amount) AS magnitude
FROM orders
WHERE status = 'refund';

Aqui las filas de reembolso guardan amount como negativo, pero el informe quiere el tamano del reembolso, no la direccion del flujo de caja.

Diferencia y distancia entre valores

El uso mas comun es la distancia entre dos numeros: ABS(a - b). El orden de los argumentos deja de importar, porque el valor absoluto es simetrico.

-- how far each order amount sits from the user's average
SELECT o.id,
       o.amount,
       ABS(o.amount - avg_amount) AS delta
FROM orders o
JOIN (
    SELECT user_id, AVG(amount) AS avg_amount
    FROM orders
    GROUP BY user_id
) a ON a.user_id = o.user_id;

La misma idea sirve para los salarios: a que distancia esta el sueldo de un empleado del promedio de su departamento, sin importar si es mayor o menor.

SELECT name, dept, salary,
       ABS(salary - AVG(salary) OVER (PARTITION BY dept)) AS gap
FROM employees
ORDER BY gap DESC;

ABS(a - b) es una distancia euclidiana de una dimension. Sostiene informes de discrepancias, conciliaciones y busquedas del "registro mas cercano" sobre un campo numerico.

Comprobaciones con tolerancia en WHERE

Comparar valores float por igualdad exacta es arriesgado: el error de redondeo acumulado casi siempre hara que a = b sea falso. Lo correcto es comprobar que la diferencia cae dentro de una tolerancia pequena (epsilon).

-- find orders whose amount is within 0.01 of a target
SELECT id, amount
FROM orders
WHERE ABS(amount - 100.00) <= 0.01;

El mismo patron concilia dos totales que en teoria deberian coincidir, pero que en la practica se desvian por un centimo a causa del redondeo.

SELECT o.id
FROM orders o
JOIN ledger l ON l.order_id = o.id
WHERE ABS(o.amount - l.posted_amount) > 0.005;   -- flag real mismatches
  • Trampa: el predicado ABS(amount - 100) <= 0.01 no puede usar un indice normal sobre amount, porque la columna esta envuelta en una funcion. Para un rango, amount BETWEEN 99.99 AND 100.01 es mas rapido: es un predicado sargable que se apoya en un indice B-tree.
  • Con enteros ABS no pierde precision, pero cuidado con el desbordamiento: ABS del valor minimo de int4 cae fuera del rango del tipo y lanza un error.

Combinacion con SIGN

ABS responde "cuanto" y SIGN responde "hacia donde". Juntos describen por completo una desviacion: magnitud mas direccion.

-- magnitude and direction of deviation from a target salary
SELECT name,
       salary,
       ABS(salary - 50000)  AS gap,
       SIGN(salary - 50000) AS direction   -- -1 below, 0 equal, 1 above
FROM employees;

SIGN devuelve -1, 0 o 1, asi que el valor original siempre se puede reconstruir: value = SIGN(value) * ABS(value). Eso es comodo cuando ordenas primero por el tamano de la desviacion y luego por su signo.

Las diferencias entre motores son pequenas, pero conviene conocer algunas:

  • En PostgreSQL y MySQL el nombre es simplemente ABS. En ClickHouse la funcion se escribe abs (en minusculas, como todas), y el resultado sobre tipos con signo sigue teniendo signo.
  • En ClickHouse, abs de un entero sin signo devuelve el mismo valor sin signo: alli no hay negativos que invertir.
  • ABS(NULL) siempre da NULL. Si la tolerancia se calcula sobre una columna que puede contener NULL, envuelvela en COALESCE, o la fila desaparece en silencio de la comprobacion.

En resumen: ABS es "distancia sin direccion". Usalo para diferencias y conciliaciones, anade SIGN cuando necesites la direccion y reescribe los predicados como BETWEEN cuando importen la velocidad y el indice.

Practica con ejercicios reales

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

Abrir el entrenador