CURSOR 与循环中的 select 语句

ROB*_*SON 3 postgresql plpgsql

我刚刚在另一个 StackOverflow 问题中看到了一个简单的例子,它使用游标循环遍历表格。我只是循环遍历选择查询的结果,而不是将选择查询包装在游标中。使用游标有什么好处?

(我不能在这里包含这个例子,因为 StackOverflow 认为我的问题主要是代码,并要求更多细节。我以前遇到过那个烦人的限制。如果我能用几句话清楚地提出我的问题,我应该能够到。我会看看是否可以找到该问题的链接,如果可以,我将在此处添加链接。)

这是我看到使用 CURSOR 的原始问题。

kli*_*lin 7

使用游标有什么好处?

唯一的优点是您必须编写更多代码(如果他们为每行代码付费)。

do $$
declare
    rec record;
    cur cursor for select i from generate_series(1, 3) i;
begin
    open cur;
    loop
        fetch cur into rec;
        exit when rec is null;
        raise notice '%', rec.i;
    end loop;
    close cur;
end
$$;
Run Code Online (Sandbox Code Playgroud)

循环查询结果只是打开一个(虚拟)游标,获取行,检查范围,在需要时退出并为您关闭游标。

do $$
declare
    rec record;
begin
    for rec in select i from generate_series(1, 3) i
    loop
        raise notice '%', rec.i;
    end loop;
end
$$;
Run Code Online (Sandbox Code Playgroud)


Lau*_*lbe 6

有以下几种方法:

  1. 在 PL/pgSQL 中使用显式游标并循环遍历它并处理每个结果行。

    例子:

    OPEN c FOR SELECT id FROM a WHERE ok;
    LOOP
       UPDATE b SET a_ok = TRUE WHERE a_id = c.id;
    END LOOP;
    
    Run Code Online (Sandbox Code Playgroud)
  2. FOR r IN SELECT ... LOOP在 PL/pgSQL 中使用 a 。这实际上与 1. 相同,但语法更清晰。

    例子:

    FOR c IN SELECT id FROM a WHERE ok LOOP
       UPDATE b SET a_ok = TRUE WHERE a_id = c.id;
    END LOOP;
    
    Run Code Online (Sandbox Code Playgroud)
  3. 运行SELECT不带游标的查询并在客户端处理每个结果行,可能会为每个结果发出数据库查询。

    示例(伪代码):

    resultset := db_exec('SELECT id FROM a WHERE ok');
    while (resultset.next()) {
        db_exec('UPDATE b SET a_ok = TRUE WHERE a_id = ' || resultset.get('id'));
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 用一个JOIN

    例子:

    UPDATE b SET a_ok = TRUE
    FROM a
    WHERE a.id = b.a_id AND a.ok;
    
    Run Code Online (Sandbox Code Playgroud)

方法3是解决问题的最糟糕的方法,因为它会导致大量的客户端-服务器往返,并使数据库解析大量的语句。唉,这通常是 SQL 新手解决问题的方式。我称之为本土嵌套循环连接。最重要的是,客户端软件通常会将第一个查询的完整结果集抓取到内存中,这会导致另一个问题。

方法 1. 和 2. 是等效的,只是 2. 更优雅。它保存了往返并在幕后使用准备好的语句,因此UPDATE不必一直解析。不过,执行器必须运行多次,而且 PL/pgSQL 的速度并不是特别快。它也是一种本土的嵌套循环连接。

方法 4 是要走的路。不仅所有内容都在单个查询中运行,而且 PostgreSQL 还可以使用更有效的连接策略(如果更好的话)。