0

我有一个存储过程,我需要在其中查询一组,ids然后在UPDATE语句的WHERE子句中使用该组。我正在使用PostgresQL 9.0+。我宁愿不要在一组语句上使用循环ids并发出多个UPDATE语句——这不是很有效。

这是一个简单的例子:

CREATE OR REPLACE FUNCTION test_it()
RETURNS VOID AS $$
DECLARE
  cur_time  TIMESTAMP;
  ids       a%ROWTYPE;
BEGIN
  SELECT id FROM a INTO ids;
  UPDATE b
     SET state = 'foobar', updated_at = cur_time
   WHERE id IN ids;
END;
$$ LANGUAGE plpgsql;

这甚至不编译。

我也尝试过SELECT -ing 之ids类的......

CREATE OR REPLACE FUNCTION test_it()
RETURNS VOID AS $$
DECLARE
  cur_time  TIMESTAMP;
  ids       a%ROWTYPE;
BEGIN
  SELECT id FROM a INTO ids;
  UPDATE b
     SET state = 'foobar', updated_at = cur_time
   WHERE id IN (SELECT ids);
END;
$$ LANGUAGE plpgsql;

这会引发错误:提示:没有运算符与给定的名称和参数类型匹配。您可能需要添加显式类型转换。

我的实际存储过程要复杂得多,因为该集合的初始查询ids实际上是一个动态查询。

实际的错误输出是这样的(只是更多的上下文......):

ERROR:  operator does not exist: integer = task_responses
LINE 3:      WHERE id IN (SELECT task_response_ids)
                      ^
HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.
QUERY:  UPDATE task_responses
       SET state = state, updated_at = cur_time, rejected_at = cur_time
     WHERE id IN (SELECT task_response_ids)
CONTEXT:  PL/pgSQL function "reject_submissions_with_comment" line 38 at SQL statement
4

2 回答 2

1

在我的 SP 执行过程中的某个时刻,无论如何我都需要循环遍历结果,所以我选择跟踪我正在访问它们的 ID,并稍后在动态查询中使用它们来进行单次更新。

FWIW:我永远无法让@Steve 的建议起作用,因为task_response_ids它是一个结果集,而不是一个表表达式。如果我嵌入了可以工作的查询,但是我需要在我的用例中多次运行相同的查询,因为我有多个更新(不同的表)要做。

这是基于我上面和原始问题中概述的需求的(假)代码:

CREATE OR REPLACE FUNCTION test_it() RETURNS VOID AS $$
DECLARE
  cur_time    TIMESTAMP;
  state       varchar(20);
  a_response  RECORD;
  ids         bigint[];
  other_ids   bigint[];
  s_ids       varchar(4000);
  s_other_ids varchar(4000);
BEGIN
  state    := 'foobar';
  cur_time := CURRENT_TIMESTAMP;

  FOR a_response IN (SELECT id,other_id FROM a) LOOP
    ids[id_index]       := a_response.id;
    other_ids[id_index] := a_response.other_id;
    id_index            := id_index + 1;
    -- do other stuff with the current record
  END LOOP;
  s_ids       := array_to_string(ids, ',');
  s_other_ids := array_to_string(other_ids, ',');

  EXECUTE '
    UPDATE b
       SET state = $1, updated_at = $2
     WHERE id IN (' || s_ids || ')'
  USING state, cur_time;

  EXECUTE '
    UPDATE c
       SET state = $1, updated_at = $2
     WHERE id IN (' || s_other_ids || ')'
  USING state, cur_time;

END;
$$ LANGUAGE plpgsql;

这段代码非常虚构,但它演示了我需要完成的事情。

于 2012-06-21T18:38:39.770 回答
0

您想要一个 UPDATE ... FROM ... 样式查询,根据http://www.postgresql.org/docs/9.1/static/sql-update.html

UPDATE b
  SET state = 'foobar', updated_at = cur_time
FROM
  ids i
WHERE
  b.id = i.id;
于 2012-06-19T18:13:09.340 回答