UPDATE FROM subquery с использованием той же таблицы в подзапросе WHERE - PullRequest
1 голос
/ 03 марта 2012

У меня есть 2 целочисленных поля в таблице «пользователь»: leg_count и leg_length.Первый хранит количество ног пользователя, а второй - их общую длину.

Каждая нога, принадлежащая пользователю, хранится в отдельной таблице, поскольку у обычного интернет-пользователя могут быть ноги от нуля до бесконечности.:

CREATE TABLE legs (
    user_id int not null,
    length  int not null
);

Я хочу пересчитать статистику для всех пользователей в одном запросе, поэтому я пытаюсь:

UPDATE users SET
    leg_count = subquery.count, leg_length = subquery.length
FROM (
    SELECT COUNT(*) as count, SUM(length) as length FROM legs WHERE legs.user_id = users.id
) AS subquery;

и запрос "get" во FROM не может ссылаться на другие отношения того же запросауровень "ошибка.

Так что я должен сделать

UPDATE users SET
    leg_count =  (SELECT COUNT(*)    FROM legs WHERE legs.user_id = users.id),
    leg_length = (SELECT SUM(length) FROM legs WHERE legs.user_id = users.id)

, что заставляет базу данных выполнять 2 SELECT для каждой строки, хотя необходимые данные могут быть рассчитаны в одном SELECT:

SELECT COUNT(*), SUM(length) FROM legs;

Можно ли оптимизировать мой запрос UPDATE для использования только одного подзапроса SELECT?

Я использую PostgreSQL, но, как я полагаю, решение существует для любого диалекта SQL.

TIA.

Ответы [ 2 ]

7 голосов
/ 03 марта 2012

Я бы сделал:

WITH stats AS
   ( SELECT COUNT(*)    AS cnt
          , SUM(length) AS totlength
          , user_id
       FROM legs
      GROUP BY user_id
   )
UPDATE users
   SET leg_count = cnt, leg_length = totlength
  FROM stats
 WHERE stats.user_id = users.id
3 голосов
/ 03 марта 2012

Вы можете использовать расширенный синтаксис обновления PostgreSQL :

update  users as u
set     leg_count = aggr.cnt
,       leg_length = aggr.length
from    (
        select  legs.user_id
        ,       count(*) as cnt
        ,       sum(length) as length 
        from    legs 
        group by
                legs.user_id
        ) as aggr
where   u.user_id = aggr.user_id
...