postgresql, где условие возвращает хотя бы один результат - PullRequest
2 голосов
/ 17 декабря 2011

postgreSQL вопрос ... У меня есть запрос на обновление ниже, который обновляет столбец с результатами из подзапроса, однако в некоторых случаях подзапрос будет возвращать ноль, который бросает ограничение «не ноль» для столбца, как я могу получитьНЕ обновлять, если подзапрос возвращает null?

Я пробовал EXISTS, но, похоже, это работает только с предложением WHERE?

UPDATE user_stats as stats
SET ave_price = (
    SELECT AVG(l.price)
    FROM lengths as l, user_sessions as us
    WHERE l.product_type = 'car'
    AND l.session_id = us.session_id
    AND stats.user_id = us.user_id
)

Ответы [ 2 ]

4 голосов
/ 17 декабря 2011

coalesce, nvl, ifnull в большинстве обработчиков дБ выполнит условный оператор, который говорит, что примет первое ненулевое значение в строке в этом случае, когда подвыбор возвращает ноль, он установит ave_price = для себя.1002 *

Это не предотвращает обновление в соответствии с запросом, но оказывает аналогичное влияние на данные.

Для получения дополнительной информации о объединении см .: PostgreSQL

Чтобы действительно предотвратить обновление, вам нужно добавить условие where в обновление и повторно выполнить подзапрос, такой как:

    UPDATE user_stats as stats
    SET ave_price = (
        SELECT AVG(l.price)
        FROM lengths as l, user_sessions as us
        WHERE l.product_type = 'car'
        AND l.session_id = us.session_id
        AND stats.user_id = us.user_id)
WHERE (SELECT AVG(l.price)
        FROM lengths as l, user_sessions as us
        WHERE l.product_type = 'car'
        AND l.session_id = us.session_id
        AND stats.user_id = us.user_id) is not null

Логическое выполнение подзапроса дважды будет влиять на производительность в два раза;тогда как объединение требует выполнения только один раз.Всегда есть несколько способов сделать что-то и, в зависимости от требований, нужно выбрать, какой вариант им подходит лучше всего.

1 голос
/ 17 декабря 2011

Используйте фактический подзапрос для выбора вместо выражения подзапроса:

UPDATE user_stats s
SET    ave_price = x.ave_price
FROM  (
    SELECT user_id
          ,avg(l.price) AS ave_price
    FROM   lengths l
    JOIN   user_sessions us ON us.session_id = l.session_id
    WHERE  l.product_type = 'car'
    GROUP  BY us.user_id
    HAVING avg(l.price) IS NOT NULL
    ) x
WHERE x.user_id = s.user_id;

Это также будет быстрее.Если у вас есть соответствующая доля user_id, которая существует в таблице user_sessions, но не в user_stats, то следующий запрос может быть быстрее (хотя оба дают одинаковый результат в каждом случае):

UPDATE user_stats s
SET    ave_price = x.ave_price
FROM  (
    SELECT user_id
          ,avg(l.price) AS ave_price
    FROM   lengths l
    JOIN   user_stats usr USING (user_id)
    JOIN   user_sessions us ON us.session_id = l.session_id
    WHERE  l.product_type = 'car'
    GROUP  BY us.user_id
    HAVING avg(l.price) IS NOT NULL
    ) x
WHERE x.user_id = s.user_id;

Смысл второй версии состоит в том, чтобы исключить ненужные строки на ранней стадии.Тот же запрос, написанный с помощью CTE (несколько более элегантный и читабельный):

WITH x AS (
    SELECT user_id
          ,avg(l.price) AS ave_price
    FROM   lengths l
    JOIN   user_stats usr USING (user_id)
    JOIN   user_sessions us ON us.session_id = l.session_id
    WHERE  l.product_type = 'car'
    GROUP  BY us.user_id
    HAVING avg(l.price) IS NOT NULL
    )
UPDATE user_stats s
SET    ave_price = x.ave_price
FROM   x
WHERE  x.user_id = s.user_id;

Имейте в виду, что хотя запросы CTE для SELECT были введены в PostgreSQL 8.4, CTE для команд изменения данных были только , введенные сPostgreSQL 9.1 :

Разрешить команды изменения данных (INSERT / UPDATE / DELETE) в предложениях WITH

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...