viernes, 18 de febrero de 2011

Factorial de n usando una sentencia SQL simple.

Quizás alguna vez se han preguntado porque no existe una función de agregación PROD, que obtenga el producto de una columna numerica o expresión de una tabla, me parece que no, verdad?. Muy probablemente a la mayoria, nunca se le ha generado esa inquietud, porque de hecho, no tiene, a priori, demasiada utilidad en los sistemas reales. De todas formas, la idea de la nota es mostrarles que tan simple y elegante puede ser una solución usando solo una simple sentencia SELECT, independientemente si le encuentran alguna utilidad o no.

Como una breve introducción, voy a repasar las funciones de agregación, que son variadas. Las mas conocidas y usadas mas frecuentemente son:

SUM: Retorna la suma de una columna o expresión
AVG: Retorna el promedio de una columa o expresión
MIN: Retorna el valor mínimo
MAX: Retorna el valor máximo

Otras funciones, son las estadisticas, que suelo usar cuando necesito analizar tendencias y patrones, y son:

STDDEV : Retorna la desviación standard de una columna o expresión
VARIANCE : Retorna la varianza de una columna o expresión
MEDIAN : Retorna la mediana de una columna o expresión

existen muchas mas funciones de agregación para usar, ver detalle en el manual oficial para la versión de BD que necesiten, por ejemplo para 11g R2: SQL Reference 11.2 R2 (Funciones de Agregación)

En esta oportunidad, voy a mostrar como simular la función PROD usando algunas reglas matematicas simples, y por ultimo, usar dicha función para obtener el factorial de un número dado:

Para comenzar, voy a definir las dos funciones que voy a utilizar:

ln(n) = Retorna el logarimo natural de n

y su función inversa:

exp(n) = Retorna e elevado a la n

Ahora, partiendo de la siguiente propiedad matematica de los logaritmos:

ln(a) + Ln(b) = ln(a * b)

Elevando e con cada lado de la ecuación anterior:

exp(ln(a)+ln(b)) = exp(ln(a*b))

Dado que exp y ln son funciones inversas, entonces se anulan y nos queda a multiplicado por b:

exp(ln(a*b)) = a*b

En este punto, ya tenemos definida y explicada la regla. Ahora voy a mostrar un ejemplo de uso, para obtener el factorial:

La sentencia SQL para obtener el factorial de N tiene la siguiente forma:

select exp(sum(ln(rownum))) from dual
connect by rownum <= N ;


Un ejemplo usando como consola sqlplus:

rop@DESA10G> variable n number
rop@DESA10G> exec :n := 3;

Procedimiento PL/SQL terminado correctamente.


rop@DESA10G> select exp(sum(ln(rownum))) from dual
2 connect by rownum <= :n ;

EXP(SUM(LN(ROWNUM)))
--------------------
6

rop@DESA10G> exec :n := 6;

Procedimiento PL/SQL terminado correctamente.

rop@DESA10G> select exp(sum(ln(rownum)))
from dual
2 connect by rownum <= :n ;

EXP(SUM(LN(ROWNUM)))
--------------------
720

Como se ve, se puede obtener el factorial de cualquier número con una simple sentencia. También se podria usar para multiplicar las columnas de una tabla, multiplicar expresiones, etc.