0

一連のクエリを実行し、そのセットをステートメントの句idsで使用する必要があるストアド プロシージャがあります。PostgresQL 9.0+を使用しています。一連のステートメントに対してループを使用したり、複数のステートメントを発行したりしたくありません。これはあまり効率的ではありません。UPDATEWHEREidsUPDATE

簡単な例を次に示します。

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 -ingidsなどを試しました...

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;

これによりエラーがスローされます: HINT: 指定された名前と引数の型に一致する演算子はありません。明示的な型キャストを追加する必要がある場合があります。

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 を追跡し、後で動的クエリでそれらを使用して単一の更新を行うことにしました。

task_response_idsFWIW:テーブル式ではなく結果セットだったため、@Steveの提案を機能させることはできませんでした。クエリを埋め込んだ場合は機能しますが、複数の更新 (異なるテーブル) を行う必要があるため、ユース ケースで同じクエリを複数回実行する必要がありました。

上記と元の質問で概説した私のニーズに基づく(偽の)コードは次のとおりです。

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

http://www.postgresql.org/docs/9.1/static/sql-update.htmlに従って、UPDATE ...FROM...スタイルのクエリが必要です。

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