2012-06-13 13 views
55

Ho una query che restituisce AVG (prezzo)PostgreSQL restituisce 0 se il valore restituito è nullo

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 

come farlo tornare 0 se nessun valore è disponibile?

+1

Sei sicuro che la query è ben formata? –

+2

@LucM: non può essere una query ben formata. (clausola "having" senza clausola "group by".) –

+0

tutto funziona correttamente, tranne che a volte, quando le regole non vengono soddisfatte, non restituisce nulla. Inoltre, come posso gorupare in media, non penso sia possibile || qual è il punto? Multiple select 'from web_price_scan' sono selezioni separate; non sei sicuro di quale sia il problema qui? – Andrew

risposta

116

uso 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. 

Modifica Here'san esempio di COALESCE con la query:

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 non deve essere utilizzato con AVG perché modifica il valore. NULL significa non sapere e nient'altro. Non è come usarlo in SUM. In questo esempio, se sostituiamo AVG per SUM, il risultato non è distorto. Aggiungere 0 a una somma non fa male a nessuno ma calcola una media con 0 per i valori sconosciuti, non ottieni la media reale.

In tal caso, aggiungere price IS NOT NULL nella clausola WHERE per evitare questi valori sconosciuti.

+0

Non riuscivo a farlo funzionare; esempio potrebbe aiutare – Andrew

+1

@Andrew Stavo cercando di darti un esempio usando la tua query. Ma mi perdo. Dubito che questa query funzioni. 'da web_price_scan ...' sembra ripetuto ... –

+0

Per chi si chiede, ['NULLIF (v1, v2)'] (https://www.postgresql.org/docs/current/static/functions-conditional.html) fa praticamente l'opposto di 'COALESCE' in quanto restituisce' NULL' se 'v1' è uguale a' v2'. –

11

(questa risposta è stata aggiunta per fornire esempi più brevi e più generici alla domanda, senza includere tutti i dettagli specifici del caso nella domanda originale).


Ci sono due "problemi" distinti qui, il primo è se una tabella o sottointerrogazione ha nessuna riga, il secondo è se ci sono valori NULL nella query.

Per tutte le versioni che ho provato, postgres e mysql ignoreranno tutti i valori NULL durante la media, e restituiranno NULL se non c'è nulla da superare. Questo ha generalmente senso, dato che NULL deve essere considerato "sconosciuto". Se vuoi scavalcare questo puoi usare la coalescenza (come suggerito da 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) 

naturalmente, "da foo" può essere sostituito da "da (... qualsiasi logica complicata qui ...) come foo"

Ora, dovrebbe riga NULL nella tabella essere contato come 0? Quindi la coalesce deve essere utilizzata all'interno della chiamata AVG.

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