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)
Tobixen
источник
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.
Джон Уилсон,