postgres,使用另一个表中的数据进行批量更新

时间:2016-08-04 20:22:23

标签: postgresql

我有一个目标表(已填充数据)和另一个(源表),我需要将数据检索到第一个。

target_table

postgres=# select id,id_user from ttasks;
 id | id_user
----+---------
  1 |
  2 |
  3 |
  4 |
  5 |
(5 rows)

source_table

postgres=# select id from tusers where active;
  id
------
 1011
 1012
 1013
 1014
(4 rows)

我需要使用来自tusers表的id来更新ttasks表的id_user列,因此ttasks上的最终结果应为:

# expected result after update [select id, id_user from ttasks;]
 id | id_user
----+---------
  1 |    1011
  2 |    1012
  3 |    1013
  4 |    1014
  5 |    1011
(5 rows)

我尝试过(类似于INSERT ... FROM ...语句):

postgres=# update ttasks t1 set id_user = q1.id from (select id from tusers where active) q1 returning t1.id,t1.id_user;
 id | id_user
----+---------
  1 |    1011  
  2 |    1011
  3 |    1011
  4 |    1011  
  5 |    1011  
(5 rows)

但是这个查询总是使用q1子查询中的第一个id。

有关如何完成此任务的任何想法,帮助甚至解决方案? 非常感谢你!

P.S。这是我在这个社区的第一篇文章,所以如果我的问题中的某些内容不符合你的规则,请对我保持温和。

1 个答案:

答案 0 :(得分:0)

最后,在我的一个朋友告诉我并非一切都可以用“保持愚蠢的简单”方式编码之后,我编写了一个plpqsql(PL / PGSQL)函数来完成这项工作,并且允许在里面使用一些高级过滤器。

CREATE OR REPLACE FUNCTION assign_workers_to_tasks(i_workers_table regclass, i_workers_table_tc text, i_tasks_table regclass, i_tasks_table_tc text, i_workers_filter text DEFAULT ''::text, i_tasks_filter text DEFAULT ''::text)
  RETURNS void AS
$BODY$
  DECLARE workers int[]; i integer; total_workers integer; r record; get_tasks text;
begin
    i_workers_filter := 'where '||nullif(i_workers_filter,'');
    i_tasks_filter := 'where '||nullif(i_tasks_filter,'');
    EXECUTE format('select array_agg(%s) from (select %s from %s %s order by %s) q', i_workers_table_tc, i_workers_table_tc,i_workers_table, i_workers_filter,i_workers_table_tc)
    INTO workers; --available [filtered] workers
    total_workers := coalesce(array_length(workers,1),0); --total of available [filtered] workers
    IF total_workers = 0 THEN
      EXECUTE format('update %s set %s=null %s', i_tasks_table, i_tasks_table_tc, i_tasks_filter);
      RETURN;
    END IF;
    i :=1;
    get_tasks := format('select * from %s %s',i_tasks_table,i_tasks_filter); --[filtered] tasks
    FOR r IN EXECUTE (get_tasks) LOOP
      EXECUTE format('update %s set %s=%s where id = %s', i_tasks_table, i_tasks_table_tc, workers[i],r.id);
      i := i+1;
      IF i>total_workers THEN i := 1; END IF;
    END LOOP;
    RETURN;
end;
  $BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION assign_workers_to_tasks(regclass, text, regclass, text, text, text)
  OWNER TO postgres;

并完成我自己的问题:

select assign_workers_to_tasks('tusers','id','ttasks','id_user','active');