postgresql devuelve 0 si el valor devuelto es nulo

99

Tengo una consulta que devuelve avg (price)

  select avg(price)
  from(
      select *, cume_dist() OVER (ORDER BY price desc) from web_price_scan
      where listing_Type='AARM'
        and u_kbalikepartnumbers_id = 1000307
        and (EXTRACT(Day FROM (Now()-dateEnded)))*24 < 48
        and price>( select avg(price)* 0.50
                    from(select *, cume_dist() OVER (ORDER BY price desc)
                         from web_price_scan
                         where listing_Type='AARM'
                           and u_kbalikepartnumbers_id = 1000307
                           and (EXTRACT(Day FROM (Now()-dateEnded)))*24 < 48
                        )g
                   where cume_dist < 0.50
                 )
        and price<( select avg(price)*2
                    from( select *, cume_dist() OVER (ORDER BY price desc)
                          from web_price_scan
                          where listing_Type='AARM'
                            and u_kbalikepartnumbers_id = 1000307
                            and (EXTRACT(Day FROM (Now()-dateEnded)))*24 < 48
                        )d
                    where cume_dist < 0.50)
     )s

  having count(*) > 5

¿Cómo hacer que devuelva 0 si no hay ningún valor disponible?

Andrés
fuente
1
¿Estás seguro de que tu consulta está bien formada?
Luc M
2
@LucM: No puede ser una consulta bien formada. (cláusula "tener" sin una cláusula "agrupar por".)
Mike Sherrill 'Cat Recall'
todo funciona bien, excepto que a veces, cuando no se cumplen las reglas, no devuelve nada. Además, ¿cómo puedo engordar en promedio? No creo que sea posible || ¿cuál es el punto? Las selecciones múltiples from web_price_scanson selecciones independientes; ¿No estás seguro de cuál es el problema aquí?
Andrew
Está bien usar una havingcláusula sin un group by(que por defecto es un solo grupo). Actúa como una wherecláusula sobre resultados agregados. En este caso, las filas solo se devuelven si la subconsulta de primer nivel devuelve más de 5 filas.
bruceskyaus

Respuestas:

177

usar coalesce

COALESCE(value [, ...])
The COALESCE function returns the first of its arguments that is not null.  
Null is returned only if all arguments are null. It is often
used to substitute a default value for null values when data is
retrieved for display.

Editar

Aquí COALESCEtienes un ejemplo de tu consulta:

SELECT AVG( price )
FROM(
      SELECT *, cume_dist() OVER ( ORDER BY price DESC ) FROM web_price_scan
      WHERE listing_Type = 'AARM'
        AND u_kbalikepartnumbers_id = 1000307
        AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
        AND COALESCE( price, 0 ) > ( SELECT AVG( COALESCE( price, 0 ) )* 0.50
                                     FROM ( SELECT *, cume_dist() OVER ( ORDER BY price DESC )
                                           FROM web_price_scan
                                           WHERE listing_Type='AARM'
                                             AND u_kbalikepartnumbers_id = 1000307
                                             AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
                                         ) g
                                    WHERE cume_dist < 0.50
                                  )
        AND COALESCE( price, 0 ) < ( SELECT AVG( COALESCE( price, 0 ) ) *2
                                     FROM( SELECT *, cume_dist() OVER ( ORDER BY price desc )
                                           FROM web_price_scan
                                           WHERE listing_Type='AARM'
                                             AND u_kbalikepartnumbers_id = 1000307
                                             AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
                                         ) d
                                     WHERE cume_dist < 0.50)
     )s
HAVING COUNT(*) > 5

En mi humilde opinión COALESCE, no debería usarse con AVGporque modifica el valor. NULLsignifica desconocido y nada más. No es como usarlo en SUM. En este ejemplo, si reemplazamos AVGpor SUM, el resultado no se distorsiona. Agregar 0 a una suma no perjudica a nadie, pero calculando un promedio con 0 para los valores desconocidos, no se obtiene el promedio real.

En ese caso, me gustaría añadir price IS NOT NULLen WHEREla cláusula para evitar estos valores desconocidos.

Luc M
fuente
1
@Andrew Estaba tratando de darte un ejemplo usando tu consulta. Pero me pierdo. Dudo que esta consulta funcione. from web_price_scan...parece repetido ...
Luc M
Para aquellos que se preguntan, NULLIF(v1, v2)hace más o menos lo contrario COALESCEen que devuelve NULLsi v1es igual v2.
sm
24

(esta respuesta se agregó para proporcionar ejemplos más breves y genéricos de la pregunta, sin incluir todos los detalles específicos del caso en la pregunta original).


Hay dos "problemas" distintos aquí, el primero es si una tabla o subconsulta no tiene filas, el segundo es si hay valores NULL en la consulta.

Para todas las versiones que he probado, postgres y mysql ignorarán todos los valores NULL al promediar, y devolverán NULL si no hay nada sobre lo que promediar. Esto generalmente tiene sentido, ya que NULL debe considerarse "desconocido". Si desea anular esto, puede usar coalesce (como lo sugiere Luc M).

$ create table foo (bar int);
CREATE TABLE

$ select avg(bar) from foo;
 avg 
-----

(1 row)

$ select coalesce(avg(bar), 0) from foo;
 coalesce 
----------
        0
(1 row)

$ insert into foo values (3);
INSERT 0 1
$ insert into foo values (9);
INSERT 0 1
$ insert into foo values (NULL);
INSERT 0 1
$ select coalesce(avg(bar), 0) from foo;
      coalesce      
--------------------
 6.0000000000000000
(1 row)

por supuesto, "from foo" puede ser reemplazado por "from (... cualquier lógica complicada aquí ...) como foo"

Ahora, ¿la fila NULL en la tabla debe contarse como 0? Luego, coalesce debe usarse dentro de la llamada avg.

$ select coalesce(avg(coalesce(bar, 0)), 0) from foo;
      coalesce      
--------------------
 4.0000000000000000
(1 row)
tobixen
fuente
2

Puedo pensar en 2 formas de lograr esto:

  • IFNULL ():

    La función IFNULL () devuelve un valor especificado si la expresión es NULL. Si la expresión NO es NULL, esta función devuelve la expresión.

Sintaxis:

IFNULL(expression, alt_value)

Ejemplo de IFNULL () con su consulta:

SELECT AVG( price )
FROM(
      SELECT *, cume_dist() OVER ( ORDER BY price DESC ) FROM web_price_scan
      WHERE listing_Type = 'AARM'
        AND u_kbalikepartnumbers_id = 1000307
        AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
        AND IFNULL( price, 0 ) > ( SELECT AVG( IFNULL( price, 0 ) )* 0.50
                                     FROM ( SELECT *, cume_dist() OVER ( ORDER BY price DESC )
                                           FROM web_price_scan
                                           WHERE listing_Type='AARM'
                                             AND u_kbalikepartnumbers_id = 1000307
                                             AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
                                         ) g
                                    WHERE cume_dist < 0.50
                                  )
        AND IFNULL( price, 0 ) < ( SELECT AVG( IFNULL( price, 0 ) ) *2
                                     FROM( SELECT *, cume_dist() OVER ( ORDER BY price desc )
                                           FROM web_price_scan
                                           WHERE listing_Type='AARM'
                                             AND u_kbalikepartnumbers_id = 1000307
                                             AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
                                         ) d
                                     WHERE cume_dist < 0.50)
     )s
HAVING COUNT(*) > 5
  • JUNTARSE()

    La función COALESCE () devuelve el primer valor no nulo en una lista.

Sintaxis:

COALESCE(val1, val2, ...., val_n)

Ejemplo de COALESCE () con su consulta:

SELECT AVG( price )
FROM(
      SELECT *, cume_dist() OVER ( ORDER BY price DESC ) FROM web_price_scan
      WHERE listing_Type = 'AARM'
        AND u_kbalikepartnumbers_id = 1000307
        AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
        AND COALESCE( price, 0 ) > ( SELECT AVG( COALESCE( price, 0 ) )* 0.50
                                     FROM ( SELECT *, cume_dist() OVER ( ORDER BY price DESC )
                                           FROM web_price_scan
                                           WHERE listing_Type='AARM'
                                             AND u_kbalikepartnumbers_id = 1000307
                                             AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
                                         ) g
                                    WHERE cume_dist < 0.50
                                  )
        AND COALESCE( price, 0 ) < ( SELECT AVG( COALESCE( price, 0 ) ) *2
                                     FROM( SELECT *, cume_dist() OVER ( ORDER BY price desc )
                                           FROM web_price_scan
                                           WHERE listing_Type='AARM'
                                             AND u_kbalikepartnumbers_id = 1000307
                                             AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
                                         ) d
                                     WHERE cume_dist < 0.50)
     )s
HAVING COUNT(*) > 5
Joish
fuente
1
IFNULL () no es una función en Postgres. Esto podría funcionar en otras bases de datos, pero la pregunta es específicamente sobre Postgres.
Jon Wilson