2012-06-13 13 views
55

Mam kwerendy, która zwraca AVG (cena)PostgreSQL zwraca 0 jeśli zwracana wartość jest null

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 

jak zrobić to zwraca 0, jeśli wartość nie jest dostępna?

+1

Czy jesteś pewien, że Twoje zapytanie jest dobrze sformułowane? –

+2

@LucM: To nie może być dobrze sformułowane zapytanie. (klauzula "mająca" bez klauzuli "grupa po".) –

+0

wszystko działa dobrze, z tym wyjątkiem, że czasami, gdy reguły nie są spełnione, nic nie zwraca. Ponadto, jak mogę gorup przeciętnie, nie sądzę, że jest to możliwe? Wiele wybiera 'from web_price_scan' to osobne selekcje; nie wiesz, co tu jest? – Andrew

Odpowiedz

116

użycie 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. 

Edit Here'san przykładem COALESCE z zapytanie:

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 COALESCE nie powinno być korzystanie z AVG ponieważ modyfikuje wartość. NULL oznacza nieznane i nic więcej. To nie jest tak, jak używanie go w SUM. W tym przykładzie, jeśli zastąpimy AVG przez SUM, wynik nie zostanie zniekształcony. Dodanie 0 do sumy nikomu nie zaszkodzi, ale obliczając średnią z 0 dla nieznanych wartości, nie otrzymasz rzeczywistej średniej.

W takim przypadku chciałbym dodać price IS NOT NULL w klauzuli WHERE, aby uniknąć tych nieznanych wartości.

+0

Nie mogłem sprawić, żeby działało; przykład pomógłby – Andrew

+1

@Andrew próbowałem dać ci przykład używając twojego zapytania. Ale się gubię. Wątpię, czy to zapytanie działa. 'od web_price_scan ...' wydaje się powtarzać ... –

+0

Dla tych, którzy się zastanawiają, ['NULLIF (v1, v2)'] (https://www.postgresql.org/docs/current/static/functions-citional.html) w przeciwieństwie do 'COALESCE' zwraca wartość' NULL', jeśli 'v1' jest równe' v2'. –

11

(ta odpowiedź została dodana w celu przedstawienia krótszych i bardziej ogólnych przykładów tego pytania - bez uwzględnienia wszystkich szczegółowych informacji dotyczących sprawy w pierwotnym pytaniu).


Istnieją dwa różne „problemy” tutaj, pierwszy jest, jeśli tabela lub podzapytanie nie ma wierszy, drugi to, czy istnieją wartości NULL w zapytaniu.

Dla wszystkich wersji, które przetestowałem, postgres i mysql zignorują wszystkie wartości NULL podczas uśredniania, a zwrócą wartość NULL, jeśli nie ma nic, co można by przeliczyć na średnią. Ma to na ogół sens, ponieważ NULL należy uważać za "nieznany". Jeśli chcesz to zmienić, możesz użyć koalescencji (jak sugeruje 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) 

oczywiście „z foo” może być zastąpione przez „z (... każdej skomplikowanej logiki tutaj ...) jako foo”

Teraz powinno wiersz NULL w tabeli liczy jako 0? Następnie koalesce musi być używane wewnątrz średniej wartości.

$ select coalesce(avg(coalesce(bar, 0)), 0) from foo; 
     coalesce  
-------------------- 
4.0000000000000000 
(1 row) 
Powiązane problemy