postgresql повертає 0, якщо повернуте значення є нульовим


99

У мене є запит, який повертає avg (ціна)

  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

як змусити його повернути 0, якщо значення недоступне?


1
Ви впевнені, що ваш запит правильно сформований?
Luc M

2
@LucM: Це не може бути правильно сформований запит. ("речення" без речення "згрупувати за".)
Майк Шеррілл "Відкликання кота"

все працює нормально, за винятком того, що іноді, коли правила не виконуються, це нічого не повертає. Крім того, як я можу в середньому зростати, я не думаю, що це можливо || у чому справа? Кілька виділень - from web_price_scanце окремі виділення; не впевнені, в чому тут проблема?
Ендрю

Добре використовувати havingречення без group by(яке за замовчуванням є однією групою). Він діє як whereположення про сукупні результати. У цьому випадку рядки повертаються, лише якщо підзапитом 1-го рівня повертається більше 5 рядків.
bruceskyaus

Відповіді:


178

використовувати злиття

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.

Редагувати

Ось приклад COALESCEвашого запиту:

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не слід використовувати з, AVGоскільки це змінює значення. NULLозначає невідоме і більше нічого. Це не як використовувати його в SUM. У цьому прикладі, якщо замінити AVGна SUM, результат не спотворюється. Додавання 0 до суми нікому не шкодить, але, обчислюючи середнє з 0 для невідомих значень, ви не отримуєте реальне середнє.

У цьому випадку, я хотів би додати price IS NOT NULLв WHEREпункті , щоб уникнути цих невідомих значень.


1
@Andrew Я намагався навести вам приклад, використовуючи ваш запит. Але я загублюсь. Я сумніваюся, що цей запит працює. from web_price_scan...здається повтореним ...
Luc M

Для тих, хто цікавиться, NULLIF(v1, v2)чи робить майже протилежне COALESCEтому, що повертається, NULLякщо v1дорівнює v2.
см

24

(ця відповідь була додана, щоб надати коротші та загальніші приклади до запитання - без включення всіх деталей до конкретного випадку в оригінальне запитання).


Тут є дві різні "проблеми", перша - якщо таблиця або підзапит не має рядків, друга - якщо в запиті є значення NULL.

Для всіх версій, які я перевірив, postgres і mysql ігноруватимуть усі значення NULL при усередненні, і повертатиме NULL, якщо немає чого середнього. Як правило, це має сенс, оскільки NULL слід вважати "невідомим". Якщо ви хочете замінити це, ви можете використовувати злиття (як запропонував Люк М).

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

звичайно, "from foo" можна замінити на "from (... будь-яка складна логіка тут ...) як foo"

Тепер, чи слід рядок NULL в таблиці вважати 0? Тоді злиття повинно бути використано всередині середнього виклику.

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

2

Я можу придумати 2 шляхи досягнення цього:

  • IFNULL ():

    Функція IFNULL () повертає вказане значення, якщо вираз NULL. Якщо вираз NOT NULL, ця функція повертає вираз.

Синтаксис:

IFNULL(expression, alt_value)

Приклад IFNULL () з вашим запитом:

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

    Функція COALESCE () повертає перше ненульове значення у списку.

Синтаксис:

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

Приклад COALESCE () з вашим запитом:

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

1
IFNULL () не є функцією в Postgres. Це може працювати в інших базах даних, але питання стосується Postgres.
Джон Вілсон,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.