Используйте фактический подзапрос для выбора вместо выражения подзапроса:
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