web-dev-qa-db-ja.com

関数はクエリを実行し、結果を操作してから同じ結果を返します

私はこの疑似コードのようなことをする関数が必要です:

function get_data() RETURN SET OF something... as
BEGIN
    myResultSet = select id, some_other_column from ...... limit 20000;
    update some_other_table set status = 2 where id in (myResultSet.id);
    RETURN QUERY myResultSet;
END;

つまり、クエリを実行し、他の更新ステートメントで取得したIDを使用して、この同じクエリ結果を返す必要があります。

結果セットをある種の変数に格納する方法があるかどうか疑問に思っていましたが、私の研究では良い結果が見つかりませんでした。同じクエリを2回実行する必要がないので、他の種類の解決策もありがたいです。

2

カーソルを使用できます。

create type my_type as (id int, other_column text);

create or replace function get_data ()
returns setof my_type
language plpgsql as $$
declare
    cur cursor for select id, other_column from my_table limit 20000;
    rec record;
begin
    for rec in cur loop
        update other_table
            set status = 2 
            where id = rec.id;
        return next rec;
    end loop;
end $$;

select * from get_data();

ただし、この関数は1回だけではなく、20000回(場合によってはそれ以下)の更新を実行することに注意してください。さまざまな状況に依存するため、パフォーマンスが1つのクエリよりも良いか悪いかは明らかではありません。たとえば、アイドル状態のサーバーでは1つのクエリがはるかに高速になるはずですが、負荷の高いサーバーでは関数の方が優れている場合があります。これを確認する最良の方法は、実際の環境で機能をテストすることです。


一時テーブルを使用することもできます。この場合、行は1つのクエリで更新されます。

create or replace function get_data_2 ()
returns setof my_type
language plpgsql as $$
begin
    create temporary table temp_table of my_type on commit drop;
    insert into temp_table
        select id, other_column from my_table limit 20000;
    update other_table 
        set status = 2
        where id in (select id from temp_table);
    return query select * from temp_table;
end $$;
3
klin

共通テーブル式(CTE) を使用すると、これを1つのステートメントで実行できます。

WITH myResultSet AS 
  ( SELECT id, some_other_column
    FROM ...

    ORDER BY ...something
    LIMIT 20000
  ) 

, upd AS
  ( UPDATE some_other_table
    SET status = 2
    WHERE id IN (SELECT id FROM myResultSet)
  ) 

SELECT *
FROM myResultSet ;

SQL-Fiddleでテストされています。

1
ypercubeᵀᴹ