postgresql where条件返回至少一个结果

时间:2011-12-17 12:57:12

标签: sql postgresql

postgreSQL问题...我在下面有一个更新查询,它使用子查询的结果更新一列,但是在某些情况下,子查询将返回null,这会在列上引发'not null'约束,我怎么能得到如果子查询返回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 个答案:

答案 0 :(得分:4)

coalesce,nvl,ifnull在大多数数据库引擎中都会执行一个条件语句,在这种情况下,当subselect返回null时,取字符串中的第一个非空值,它会将ave_price =设置为自身。

UPDATE user_stats as stats
SET ave_price = coalesce((
    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
),ave_price)

这并不会阻止udpate的请求,但它对数据有类似的影响。

有关合并的更多信息,请参阅: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

两次逻辑执行子查询会影响性能两次;而coalesce只需执行一次。总有多种方法可以做,并且根据要求,必须选择最适合他们的选项。

答案 1 :(得分:1)

使用实际的子查询来代替子查询表达式:

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; ,则以下查询可能会更快(虽然两者都会产生相同的结果) :

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编写的相同查询(稍微更优雅和可读):

{{1}}

请注意,虽然在PostgreSQL 8.4中引入了用于SELECT查询的CTE,但数据修改命令的CTE仅为introduced with PostgreSQL 9.1

  

允许WITH子句中的数据修改命令(INSERT / UPDATE / DELETE)