Re: Consultas complicada

From: Anthony Sotolongo <asotolongo(at)gmail(dot)com>
To: Francisco Olarte <folarte(at)peoplecall(dot)com>, ViBaSoft <vibasoft(at)gmail(dot)com>
Cc: Lista Postgres ES <pgsql-es-ayuda(at)postgresql(dot)org>
Subject: Re: Consultas complicada
Date: 2015-12-19 10:54:31
Message-ID: 56753767.5070403@gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-es-ayuda

Hola, me sumo a la respuesta de Francisco sobre todo de que la versión
9.0 ya no tiene soporte, y puede que con WITH tenga mejor resultado, el
cual es soportado desde la 8.4,
ahora si por casualidad te permiten subir de versión, lo cual es muy
recomendable, lo hagas a la 9.4 y que tiene una muy buena posible
solución para tu tema, es el caso de FILTER a las funciones de agregados
(http://www.postgresql.org/docs/9.4/interactive/sql-expressions.html#SYNTAX-AGGREGATES)

Tal vez te sirva entender como funciona en el ejemplo siguiente:
http://www.depesz.com/2013/07/23/waiting-for-9-4-implement-the-filter-clause-for-aggregate-function-calls/
y te pueda servir para sacar todos los meses de una vez, o tal vez
combinado varias cosas te pueda ser mejor (WITH, FILTER).

Y si al final decides subir de versión y el negocio te lo permite,
valora si las vistas materializadas(desde 9.3) las puedes utilizar,
donde tendrías precalculado estos valores por meses y el rendimiento
mejoraria muchoooo.

Saludos

El 12/19/2015 a las 6:57 AM, Francisco Olarte escribió:
> Buenos dias:
>
> Una respuesta, larga, te voy desarrollando cosas.
>
>
> On Fri, Dec 18, 2015 at 8:44 PM, ViBaSoft <vibasoft(at)gmail(dot)com> wrote:
>> Quiero sacar el precio minimo, máximo, media por mes por columna y una
>> general, en la general me sale bien pero por mes columna no me trae el
>> minimo. Me trae 0(cero) siempre en la columna min_enero
> Tu problema es el clasico de mal valor por defecto. Estas haciendo el
> MIN de una columna de precios ( >=0 ) con un 0 cuando no es enero, con
> lo que te sale 0:
>
>> MIN(CASE WHEN extract(month from c.fecha_factura)=1 THEN cd.preciocompra
>> ELSE 0 END) AS precio_min_enero,
> En cuanto una fila de febrero entra el el case da 0, el minimo es 0.
>
> Prueba a poner un numero enorme en el else, no se cual decirte ya que
> no has puesto el esquema de la tabla pero siendo precios si pones
> 'ELSE 999999999999999999' te deberia valer.
>
> Esa es la solucion clasica usada cuando calculas un minimo corrido en
> un lenguaje clasico, inicializar el minimo al nuero mas largo que
> puedas y si el valor leido es menor, actualizr ( min=99999999, if
> curr<min then min=curr ) ).
>
> En SQL puedes ademas hacer una mas astuta, ya que min filtra los
> nulos, unos ejemplos, tu query actual con unos datos de pruebas:
>
> s=> select min(case when mes=1 then precio else 0 end) from (
> values(1,2.0),(1,3.0),(2,1.0),(2,4.0)) as datos(mes,precio); min
> -----
> 0
> (1 row)
>
> La solucion con el 999999999:
>
> cdrs=> select min(case when mes=1 then precio else 999999999 end) from
> ( values(1,2.0),(1,3.0),(2,1.0),(2,4.0)) as datos(mes,precio);
> min
> -----
> 2.0
> (1 row)
>
> Que tiene un problema si no hubiera datos de enero, por ejemplo para
> el mes 3 pasa esto:
>
> cdrs=> select min(case when mes=3 then precio else 999999999 end) from
> ( values(1,2.0),(1,3.0),(2,1.0),(2,4.0)) as datos(mes,precio);
> min
> -----------
> 999999999
> (1 row)
>
> Que es necesario controlar fuera de banda, si en lugar de 9999999
> usas null te viene un null de resultado:
>
> cdrs=> select min(case when mes=3 then precio else null end) from (
> values(1,2.0),(1,3.0),(2,1.0),(2,4.0)) as datos(mes,precio);
> min
> -----
>
> (1 row)
>
> Que es mas facil de distinguir. Comprobamos que el caso del 1 sigue
> funcioanado igual:
>
> cdrs=> select min(case when mes=1 then precio else null end) from (
> values(1,2.0),(1,3.0),(2,1.0),(2,4.0)) as datos(mes,precio);
> min
> -----
> 2.0
> (1 row)
>
> Y ademas el null vale tambien para max:
>
> cdrs=> select max(case when mes=1 then precio else null end) from (
> values(1,2.0),(1,3.0),(2,1.0),(2,4.0)) as datos(mes,precio);
> max
> -----
> 3.0
> (1 row)
>
> E incluso para avg, sum y count:
>
> cdrs=> select avg(case when mes=1 then precio else null end) from (
> values(1,2.0),(1,3.0),(2,1.0),(2,4.0)) as datos(mes,precio);
> avg
> --------------------
> 2.5000000000000000
> (1 row)
> cdrs=> select count(case when mes=1 then precio else null end) from (
> values(1,2.0),(1,3.0),(2,1.0),(2,4.0)) as datos(mes,precio);
> count
> -------
> 2
> (1 row)
> cdrs=> select sum(case when mes=1 then precio else null end) from (
> values(1,2.0),(1,3.0),(2,1.0),(2,4.0)) as datos(mes,precio);
> sum
> -----
> 5.0
> (1 row)
>
>
> Lo que te simplificaria bastante tu query, y lo deja, IMHO, mas claro,
> ya que en SQL el NULL se ve enseguida como 'falta dato' o 'dato
> desconocido' o 'no procede'. Incluso, aprovechando que el null
> propaga, puedes hacerlo en dos partes, primero sacas una columna con
> los datos de enero luego agregas. Como usas una version EOL no voy ni
> a intentar hacerte una prueba real que no se si funcionara, no voy a
> ir buscando documentaciones historicas, pero seria algo asi.
>
> Tabla extendida:
>
> SELECT
> cd.codigo as codigo,
> cd.cantidad as cant,
> preciocompra,
> (CASE WHEN extract(month from c.fecha_factura)=1 THEN cd.cantidad
> ELSE NULL END) AS cant_enero,
> (CASE WHEN extract(month from c.fecha_factura)=1 THEN
> cd.preciocompra ELSE NULL END) AS precio_enero
> FROM compras cd inner join compra c on cd.idcompras=c.idcompras
> WHERE trim(cd.codigo)='90-131-00-00001' and c.fecha_factura>='2015-01-01'
>
> Y luego puedes agregar con eso:
>
> select
> codigo,
> sum(cant) as cant,
> min(preciocompra) as min_precio,
> max(preciocompra) as max_precio,
> sum(cant_enero) as cant_enero,
> min(precio_enero) as min_precio_enero,
> max(precio_enero) as max_precio_enero,
> sum(precio_enero*cant_enero)/sum(precio_enero) as media_enero
> FROM (** LO DE ARRIBA**) as extendida
> GROUP BY codigo.
>
> ******
>> Trabajo con porstgres 9.0
> Esa version esta EOL, yo que tu iria mirando de actualizar. De hecho
> el query de ejemplo te lo hubiera puesto con WITH pero ni recuerdo si
> lo soportaba en esa version.
>
> Francisco Olarte.
>
> -
> Enviado a la lista de correo pgsql-es-ayuda (pgsql-es-ayuda(at)postgresql(dot)org)
> Para cambiar tu suscripci�n:
> http://www.postgresql.org/mailpref/pgsql-es-ayuda

-
Enviado a la lista de correo pgsql-es-ayuda (pgsql-es-ayuda(at)postgresql(dot)org)
Para cambiar tu suscripcin:
http://www.postgresql.org/mailpref/pgsql-es-ayuda

In response to

Browse pgsql-es-ayuda by date

  From Date Subject
Next Message Alejandro Carrillo 2015-12-19 18:04:23 Capturar cual unique key esta en excepción
Previous Message Francisco Olarte 2015-12-19 09:57:54 Re: Consultas complicada