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
)
答案 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)