Postgres:函数中的临时 table 是持久的。为什么?

Postgres: Temporary table in function is persistent. Why?

我的 postgresql 数据库中有以下函数:

CREATE OR REPLACE FUNCTION get_unused_part_ids()
  RETURNS integer[] AS
$BODY$
DECLARE
  part_ids integer ARRAY;
BEGIN
  create temporary table tmp_parts
      as
  select vendor_id, part_number, max(price) as max_price
    from refinery_akouo_parts
   where retired = false
   group by vendor_id, part_number
  having min(price) < max(price);

  -- do some work etc etc

  -- simulate ids being returned
  part_ids = '{1,2,3,4}';
  return part_ids;

END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION get_unused_part_ids()
  OWNER TO postgres;

这可以编译,但是当我 运行:

select get_unused_part_ids();

临时 table、tmp_parts 仍然存在。之后我可以在上面做一个 select。请原谅我,因为我已经习惯了 t-sql/MSSQL 的特定功能。 MSSQL 不会出现这种情况。我做错了什么?

manual

之后

Temporary tables are automatically dropped at the end of a session, or optionally at the end of the current transaction (see ON COMMIT below)

断开连接后会话结束。不是在事务提交之后。所以默认行为是保留 temp table 直到你的连接仍然打开。您必须添加 ON COMMIT DROP; 才能实现您想要的行为:

create temporary table tmp_parts on commit drop
      as
  select vendor_id, part_number, max(price) as max_price
    from refinery_akouo_parts
   where retired = false
   group by vendor_id, part_number
  having min(price) < max(price)
on commit drop;

临时 table 在两个数据库中的处理方式不同。在 SQL 服务器中,它们将在创建它们的存储过程结束时自动删除。

在 Postgres 中,临时 table 被分配给会话(或事务),如 documentation:

中所述

If specified, the table is created as a temporary table. Temporary tables are automatically dropped at the end of a session, or optionally at the end of the current transaction (see ON COMMIT below). Existing permanent tables with the same name are not visible to the current session while the temporary table exists, unless they are referenced with schema-qualified names. Any indexes created on a temporary table are automatically temporary as well.

这个概念介于 SQL 服务器中的常规临时 table 和全局临时 table 之间(全局临时 table 以 ##).

table只会在会话结束时删除。您需要指定 ON COMMIT 选项才能删除,它会在事务结束时删除 table。

  create temporary table tmp_parts 
  on commit drop
      as
  select vendor_id, part_number, max(price) as max_price
    from refinery_akouo_parts
   where retired = false
   group by vendor_id, part_number
  having min(price) < max(price);