【问题标题】:Cursor retrieves a deleted row in table created within plpgsql function光标检索在 plpgsql 函数中创建的表中已删除的行
【发布时间】:2015-08-31 13:52:36
【问题描述】:

在 plpgsql 函数中,我创建了一个表并使用游标访问其行。在第一行时,我删除了下一个,令人惊讶的是(至少对我而言)游标获取了它。在同一个函数中重复时,它会按我的预期工作。

但是,如果表预先存在并且未在函数中创建,则永远不会提取已删除的行。

我错过了什么?

DECLARE
curs1 refcursor;
rec record;

BEGIN
CREATE TABLE test as select generate_series(1,5,1) test_id;

OPEN curs1 FOR SELECT * FROM test ORDER BY test_id; 
  LOOP
    FETCH curs1 INTO rec;
    EXIT WHEN NOT FOUND;
    RAISE NOTICE 'ROW:%',rec.test_id;
    IF rec.test_id=1 THEN
      DELETE FROM TEST WHERE test_id=3;
    END IF;
  END LOOP;
CLOSE curs1;

RAISE NOTICE 'AGAIN';
--just repeating without deleting

OPEN curs1 FOR SELECT * FROM test ORDER BY test_id; 
  LOOP
    FETCH curs1 INTO rec;
    EXIT WHEN NOT FOUND;
    RAISE NOTICE 'ROW:%',rec.test_id;
  END LOOP;
CLOSE curs1;

输出是:

NOTICE:  ROW:1
NOTICE:  ROW:2
NOTICE:  ROW:3
NOTICE:  ROW:4
NOTICE:  ROW:5
NOTICE:  AGAIN
NOTICE:  ROW:1
NOTICE:  ROW:2
NOTICE:  ROW:4
NOTICE:  ROW:5

【问题讨论】:

    标签: postgresql cursor plpgsql


    【解决方案1】:

    原因是 Postgres 游标默认是“不敏感的”。 The documentation:

    SQL 标准说它是否依赖于实现 游标对底层数据的并发更新很敏感 默认。 在 PostgreSQL 中,游标默认是不敏感的,可以 通过指定FOR UPDATE 使其敏感。其他产品的工作方式可能不同。

    我的大胆强调。

    所以尝试使用FOR UPDATE 子句:

    DO
    $$
    DECLARE
       curs1 refcursor;
       rec record;
    BEGIN
       CREATE TABLE test AS SELECT generate_series(1,5) test_id;
    
       OPEN curs1 FOR SELECT * FROM test ORDER BY test_id FOR UPDATE; 
       DELETE FROM test WHERE test_id = 3;
       LOOP
          FETCH curs1 INTO rec;
          EXIT WHEN NOT FOUND;
          RAISE NOTICE 'ROW:%',rec.test_id;
       END LOOP;
       CLOSE curs1;
    END
    $$

    你会得到:

    NOTICE:  ROW:1
    NOTICE:  ROW:2
    NOTICE:  ROW:4
    NOTICE:  ROW:5
    

    第 3 行不再可见。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-13
      • 2015-03-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多