Cursor检索在plpgsql函数中创建的表中的已删除行

时间:2015-08-31 13:52:36

标签: postgresql cursor plpgsql

在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

1 个答案:

答案 0 :(得分: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行不再可见。