postgresql возвращает 0, если возвращаемое значение равно null


102

У меня есть запрос, который возвращает среднюю (цену)

  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: Это не может быть правильно сформированный запрос. (предложение "имеющий" без предложения "группировать по".)
— Майк Шерилл 'Cat Recall'

все работает нормально, за исключением того, что иногда при несоблюдении правил ничего не возвращает. Вдобавок, как я могу разбить группу в среднем, я не думаю, что это возможно || какой смысл? Множественный выбор from web_price_scan- это отдельный выбор; не уверен, в чем проблема?
— Эндрю

Можно использовать havingпредложение без group by(по умолчанию это одна группа). Он действует как whereпункт о совокупных результатах. В этом случае строки возвращаются только в том случае, если подзапрос 1-го уровня возвращает более 5 строк.
— bruceskyaus

Ответы:


180

использовать 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.

редактировать

Вот пример 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...кажется, повторяется ...
— Люк М

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

24

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


Здесь есть две различные «проблемы»: первая - если в таблице или подзапросе нет строк, вторая - если в запросе есть значения NULL.

Для всех версий, которые я тестировал, postgres и mysql игнорируют все значения NULL при усреднении и возвращают NULL, если усреднять нечего. Обычно это имеет смысл, поскольку NULL следует считать «неизвестным». Если вы хотите переопределить это, вы можете использовать coalesce (как предлагает Люк М).

$ 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 (... здесь любая сложная логика ...) as foo"

Теперь следует ли считать NULL строку в таблице за 0? Затем нужно использовать coalesce внутри вызова avg.

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