Эффективный способ условно обновить значения в 2-х записях в PostgreSQL - PullRequest
0 голосов
/ 15 октября 2018

У меня есть таблица, которая содержит 4 столбца

id | category | score | enabled
1  |  news    |  95   |    t

id - серийный

category - varchar

score - float

enabled - bool

Я хочу обновить enabled до False, если есть другая запись с более высоким счетом.

Например, если у меня есть:

id | category | score | enabled
1  |  news    |  95   |    t

Затем, после некоторой операции, добавляется новая запись с той же категорией:

id | category | score | enabled
1  |  news    |  95   |    t
2  |  news    |  100  |    f

Поскольку оценка для id=2 выше, я хочу изменить enabled для id=2 на True и изменение enabled для id=1 на False.

Мне интересно, могу ли я объединить эти операции в 1 запрос.Прямо сейчас я делаю 2 SELECT запросов, чтобы получить 2 записи, затем сравниваю результаты локально, а затем изменяю значение enabled (если необходимо).

Так просто,

SELECT id, score
FROM table
WHERE category = %s
AND enabled = True

SELECT id, score
FROM table
WHERE category = %s
AND id = (SELECT max(id) WHERE category=%s)

if score2>= score1:
    UPDATE table SET enabled = True
    WHERE id = id2

    UPDATE table SET enabled = False
    WHERE id = id1

Это работает, но кажется очень неэффективным.Есть ли способ улучшить эти запросы?

1 Ответ

0 голосов
/ 16 октября 2018

Вы можете сделать это с помощью одного обновления:

update the_table 
  set enabled = (score = t.max_score)
from (
  select id, category, max(score) over (partition by category) as max_score
  from the_table
  where category = 'news'
) t
where t.id = the_table.id
  and t.category = the_table.category;

Это установит флаги enabled для всех строк одной категории в одном выражении.

Онлайн пример: https://rextester.com/DXR80618

Если у вас более одной строки с одинаковым наивысшим баллом для одной категории, приведенный выше оператор изменит enabled на true для всехиз,.

Например,

id | category | score
---+----------+------
 1 | news     |    95
 2 | news     |   100
 3 | news     |   100

Если вы этого не хотите и, например, всегда выбираете тот, у которого наименьший id является включенной строкой, вы можете использовать следующее:

update the_table 
  set enabled = (rn = 1)
from (
   select id, category, 
          row_number() over (partition by category order by score desc, id) as rn
   from the_table
   where category = 'news'
) t
where t.id = the_table.id
  and t.category = the_table.category;

Онлайн пример: https://rextester.com/JPA61125

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