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.