sqlpostgresqllogmath

LOG en SQL: logaritmo en base 10 y base arbitraria, y la trampa de MySQL

Como funcionan LOG(x) en base 10 y LOG(b, x) en base arbitraria en PostgreSQL, por que LOG en MySQL es una trampa y donde sirven en la practica.

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

LOG devuelve el logaritmo de un numero: la potencia a la que hay que elevar la base para obtener el argumento. En PostgreSQL la funcion tiene dos formas: LOG(x) en base 10 y LOG(b, x) en una base arbitraria.

Dos formas de LOG en PostgreSQL

Sin un segundo argumento, LOG calcula el logaritmo en base 10. Si pasas dos argumentos, el primero se convierte en la base.

SELECT
  LOG(100)    AS a,   -- 2   (10^2 = 100)
  LOG(1000)   AS b,   -- 3   (10^3 = 1000)
  LOG(2, 8)   AS c,   -- 3   (2^3 = 8)
  LOG(2, 1024) AS d;  -- 10  (2^10 = 1024)

Propiedades clave:

  • LOG(x) es el logaritmo en base 10, no el natural.
  • LOG(b, x) se lee como "logaritmo de x en base b".
  • El tipo del resultado es numeric, asi que la precision es alta pero es mas lento que double precision.
  • El argumento debe ser estrictamente positivo: LOG(0) y LOG(-5) lanzan un error en lugar de devolver NULL.

La trampa principal: LOG en MySQL es el logaritmo natural

Este es el punto mas peligroso al portar consultas. En MySQL LOG(x) con un solo argumento es el logaritmo natural (base e), no el de base 10. La misma llamada devuelve numeros distintos en motores distintos.

-- PostgreSQL: LOG(100) = 2     (base 10)
-- MySQL:      LOG(100) = 4.605  (base e, natural log)
SELECT LOG(100) AS surprise;

Para que el codigo no dependa del dialecto, se explicito:

  • Logaritmo base 10: PostgreSQL LOG(x), MySQL LOG10(x). La funcion LOG10 existe en ambos y es inequivoca.
  • Logaritmo natural: usa LN(x); significa base e tanto en PostgreSQL como en MySQL.
  • Base arbitraria: PostgreSQL LOG(b, x), MySQL tiene la misma sintaxis LOG(b, x) con el mismo orden de argumentos, asi que se porta sin problemas.

Cuidado: nunca confies en LOG(x) de un solo argumento en codigo multimotor. Escribe LOG10(x) para base 10 y LN(x) para base e, y el significado sera el mismo en todas partes.

Escalas logaritmicas y conteo de digitos

Los logaritmos comprimen valores que crecen por ordenes de magnitud: importes de pedidos, conteos de eventos, tamanos de archivos. En una escala log "10 y 100" estan tan separados como "100 y 1000".

SELECT
  FLOOR(LOG(amount))::int AS magnitude,   -- 0, 1, 2, 3 ...
  COUNT(*)                AS orders
FROM orders
WHERE status = 'paid' AND amount > 0
GROUP BY FLOOR(LOG(amount))::int
ORDER BY magnitude;

Aqui los pedidos se agrupan por orden de magnitud: 0 es 1..9, 1 es 10..99, 2 es 100..999. Un truco relacionado es contar los digitos de un entero: el numero de digitos es FLOOR(LOG10(n)) + 1.

SELECT
  id,
  salary,
  FLOOR(LOG(salary))::int + 1 AS digits   -- digits in the salary
FROM employees
WHERE salary > 0
ORDER BY salary DESC;

Cuidado: filtra siempre los valores no positivos con WHERE amount > 0 o NULLIF. Un solo amount = 0 o un reembolso negativo hara que toda la consulta falle con un error de dominio. Una proteccion: LOG(NULLIF(amount, 0)) convierte el cero en NULL en vez de provocar un error.

Relacion con LN y cambio de base

LOG y LN son parientes: ambos calculan un logaritmo, solo cambia la base. LN(x) es base e, LOG(x) es base 10 y LOG(b, x) es base b. Cualquier base se expresa con ellas mediante la formula de cambio de base.

SELECT
  LN(100)            AS natural_log,   -- 4.605
  LOG(100)           AS log10,         -- 2
  LN(8) / LN(2)      AS log2_via_ln,   -- 3
  LOG(2, 8)          AS log2_builtin;  -- 3

Diferencias por dialecto:

  • PostgreSQL: LOG(x) es base 10; LOG(b, x) es arbitraria; LN(x) es natural.
  • MySQL: LOG(x) es natural (base e); para base 10 usa LOG10(x); tambien existe LOG2(x).
  • ClickHouse: log(x) y ln(x) son naturales; usa log10(x) para base 10 y log2(x) para base 2. No hay forma log(b, x), asi que usa log(x) / log(b).

Recuerda tres cosas: en PostgreSQL LOG(x) es base 10, en MySQL ese mismo LOG(x) es el logaritmo natural, y para evitar confusiones escribe LOG10 y LN de forma explicita.

Practica con ejercicios reales

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

Abrir el entrenador