Как сделать обновление на основе подсчета - SQL (postgres) - PullRequest
2 голосов
/ 10 августа 2009

У меня есть таблица, назовем ее «записи», которая выглядит следующим образом (упрощенно):

id [pk]
user_id [fk]
created [date]
processed [boolean, default false]

и я хочу создать запрос UPDATE, который установит для обработанного флага значение true для всех записей, кроме последних 3 для каждого пользователя (самое последнее в терминах созданного столбца) Итак, для следующих записей:

1,456,2009-06-01,false
2,456,2009-05-01,false
3,456,2009-04-01,false
4,456,2009-03-01,false

Только для записи 4 флаг обработки будет изменен на true.

Кто-нибудь знает, как я могу это сделать?

Ответы [ 2 ]

4 голосов
/ 10 августа 2009

Сначала давайте начнем с запроса, в котором будут перечислены все строки, подлежащие обновлению:

select e.id
from entries as e
where (
    select count(*)
    from entries as e2
    where e2.user_id = e.user_id
        and e2.created > e.created
) > 2

Здесь перечислены все идентификаторы записей, которые имеют более 2 таких записей, что user_id одинаков, но создан позже, чем создан в строке, которую нужно вернуть.

То есть в нем будут перечислены все записи, но последние 3 на пользователя.

Теперь мы можем:

update entries as e
set processed = true
where (
    select count(*)
    from entries as e2
    where e2.user_id = e.user_id
        and e2.created > e.created
) > 2;

Одна мысль - это может быть медленно. В этом случае вам лучше использовать пользовательские агрегаты или (если вы используете 8.4) оконные функции.

4 голосов
/ 10 августа 2009

Я не знаю postgres, но это стандартный SQL и может работать для вас.

update entries set
  processed = true
where (
  select count(*)
  from entries as E
  where E.user_id = entries.user_id
  and E.created > entries.created
) >= 3

Другими словами, обновляйте обработанный столбец до true, если в более поздние даты есть три или более записей для того же user_id. Я предполагаю, что [созданный] столбец уникален для данного user_id. Если нет, вам понадобится дополнительный критерий, чтобы определить, что вы подразумеваете под «последним».

В SQL Server вы можете сделать это, что немного проще и, вероятно, будет выполняться более эффективно:

with T(id, user_id, created, processed, rk) as (
  select
    id, user_id, created, processed,
    row_number() over (
      partition by user_id
      order by created desc, id
    )
  from entries
)
  update T set
    processed = true
  where rk > 3;

Обновление CTE является нестандартной функцией, и не все системы баз данных поддерживают row_number.

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