postgresql gibt 0 zurück, wenn der zurückgegebene Wert null ist

99

Ich habe eine Abfrage, die avg (Preis) zurückgibt.

  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

Wie kann man 0 zurückgeben, wenn kein Wert verfügbar ist?

Andrew
quelle
1
Sind Sie sicher, dass Ihre Abfrage gut formuliert ist?
Luc M
2
@ LucM: Es kann keine wohlgeformte Abfrage sein. ("Haben" -Klausel ohne "Gruppieren nach" -Klausel.)
Mike Sherrill 'Cat Recall'
Alles funktioniert einwandfrei, außer dass manchmal, wenn Regeln nicht eingehalten werden, nichts zurückgegeben wird. Außerdem, wie kann ich durchschnittlich gruppieren, ich denke nicht, dass es möglich ist || was ist der Punkt? Mehrfachauswahl from web_price_scanist eine separate Auswahl. nicht sicher, was das Problem hier ist?
Andrew
Es ist in Ordnung, eine havingKlausel ohne a zu verwenden group by(standardmäßig eine einzelne Gruppe). Es fungiert als whereKlausel für aggregierte Ergebnisse. In diesem Fall werden die Zeilen nur zurückgegeben, wenn mehr als 5 Zeilen von der Unterabfrage der ersten Ebene zurückgegeben werden.
Bruceskyaus

Antworten:

177

Verwenden Sie Koaleszenz

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.

Bearbeiten

Hier ist ein Beispiel für COALESCEIhre Anfrage:

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

IMHO COALESCEsollte nicht mit verwendet werden, AVGda es den Wert ändert. NULLbedeutet unbekannt und sonst nichts. Es ist nicht so, als würde man es benutzen SUM. In diesem Beispiel ersetzen , wenn wir AVGdurchSUM , wird das Ergebnis nicht verzerrt. Das Hinzufügen von 0 zu einer Summe schadet niemandem, aber wenn Sie einen Durchschnitt mit 0 für die unbekannten Werte berechnen, erhalten Sie nicht den tatsächlichen Durchschnitt.

In diesem Fall würde ich hinzufügen , price IS NOT NULLin WHEREKlausel dieser unbekannten Werte zu vermeiden.

Luc M.
quelle
1
@ Andrew Ich habe versucht, Ihnen ein Beispiel mit Ihrer Abfrage zu geben. Aber ich verliere mich. Ich bezweifle, dass diese Abfrage funktioniert. from web_price_scan...scheint wiederholt zu werden ...
Luc M
Für diejenigen, die sich fragen, NULLIF(v1, v2)ist das Gegenteil der Fall, COALESCEdass es zurückkehrt, NULLwenn es v1gleich ist v2.
sm
24

(Diese Antwort wurde hinzugefügt, um der Frage kürzere und allgemeinere Beispiele zu geben - ohne alle fallspezifischen Details in die ursprüngliche Frage aufzunehmen.)


Hier gibt es zwei unterschiedliche "Probleme": Das erste ist, wenn eine Tabelle oder Unterabfrage keine Zeilen enthält, das zweite, wenn die Abfrage NULL-Werte enthält.

Bei allen von mir getesteten Versionen ignorieren postgres und mysql bei der Mittelwertbildung alle NULL-Werte und geben NULL zurück, wenn nichts zu mitteln ist. Dies ist im Allgemeinen sinnvoll, da NULL als "unbekannt" anzusehen ist. Wenn Sie dies überschreiben möchten, können Sie Coalesce verwenden (wie von Luc M vorgeschlagen).

$ 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)

Natürlich kann "from foo" durch "from (... jede komplizierte Logik hier ...) als foo" ersetzt werden.

Sollte nun die NULL-Zeile in der Tabelle als 0 gezählt werden? Dann muss die Koaleszenz innerhalb des durchschnittlichen Anrufs verwendet werden.

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

Ich kann mir zwei Möglichkeiten vorstellen, um dies zu erreichen:

  • IFNULL ():

    Die Funktion IFNULL () gibt einen angegebenen Wert zurück, wenn der Ausdruck NULL ist. Wenn der Ausdruck NICHT NULL ist, gibt diese Funktion den Ausdruck zurück.

Syntax:

IFNULL(expression, alt_value)

Beispiel für IFNULL () mit Ihrer Abfrage:

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
  • VERSCHMELZEN()

    Die Funktion COALESCE () gibt den ersten Wert ungleich Null in einer Liste zurück.

Syntax:

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

Beispiel für COALESCE () mit Ihrer Abfrage:

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
quelle
1
IFNULL () ist keine Funktion in Postgres. Dies könnte in anderen Datenbanken funktionieren, aber die Frage bezieht sich speziell auf Postgres.
Jon Wilson