Обновление с помощью функции, вызываемой один раз для каждой строки в Postgres 8.4 - PullRequest
6 голосов
/ 30 декабря 2011

У меня есть следующий оператор UPDATE:

update mytable
   set a = first_part(genid()),
       b = second_part(genid()),
       c = third_path(genid())
 where package_id = 10;

В этом примере функция genid() вызывается три раза для каждой строки, что неправильно - я хочу, чтобы она вызывалась только один раз для каждой строки mytable.

Я использую базу данных PostgreSQL 8.4. Как правильно написать обновление?

Я пробовал что-то вроде этого:

update mytable
   set a = first_part(g),
       b = second_part(g),
       c = third_path(g)
 where package_id = 10
  from genid() as g;

Но это не сработало, потому что genid() был вызван только один раз для всего оператора обновления.

Ответы [ 3 ]

8 голосов
/ 30 декабря 2011

Вы пробовали нестандартное предложение Postgres UPDATE .. FROM?Я полагаю, это сработает

update mytable
   set a = first_part(gen.id),
       b = second_part(gen.id),
       c = third_path(gen.id)
  from (
          select genid() as genid, id
          from mytable 
          where package_id = 10
       ) gen
 where mytable.id = gen.id;
 --and package_id = 10 -- This predicate is no longer necessary as the subquery
                       -- already filters on package_id, as Erwin mentioned

Обратите внимание, что я заставляю genid() вызываться ровно один раз для каждой записи в mytable внутри подвыбора.Затем я сам объединяю mytable и gen, используя гипотетический столбец id.См. Документацию здесь:

http://www.postgresql.org/docs/current/interactive/sql-update.html

Похоже, что это было введено только с Postgres 9.0. Если это кажется слишком сложным (т.е. не очень читабельным), вы все еще можете прибегнуть к pgplsql как пользователь Флорин предложил здесь .

0 голосов
/ 30 декабря 2011

Я бы предложил использовать следующее -

DECLARE @genID VARCHAR(100) -- or appropriate datatype

SET @genID = genid() -- Or select @genID = genid()    
update mytable    
   set a = first_part(@genID),
       b = second_part(@genID),
       c = third_path(@genID)
where package_id = 10; 
0 голосов
/ 30 декабря 2011

Можете ли вы проверить, работает ли это в postgres?

update 
  (select 
     a, b, c, genid() as val
  from mytable
  where package_id = 10
  )
set a = first_part(val),
       b = second_part(val),
       c = third_path(val);

Обновление: только для идеи: вы можете попробовать это курсором?

DECLARE c1 CURSOR FOR 
      select 
         a, b, c, genid() as val
      from mytable
      where package_id = 10; 
...
UPDATE table SET ... WHERE CURRENT OF c1;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...