不能 select 来自临时 table

Can't select from a temporary table

我有 3 个 tables - T_USER,T_PRIVILEGET_USER_PRIVILEGES.

T_USER_PRIVILEGES 是一个引用 table,包含从 T_USER 行到 T_PRIVILEGE 行的引用。我想从 T_USER 中删除一行,为此我需要先删除 T_USER_PRIVILEGES 中的引用,以及 T_PRIVILEGE.

中的所有引用行

我想创建一个临时 table 来保存 T_PRIVILEGE 中的所有引用行,然后删除 T_USER_PRIVILEGES 中的所有引用,最后删除 [=16] 中的所有行=] 存储在临时 table.

我尝试做的是创建一个存储过程来完成它:

CREATE FUNCTION "SP_DELETE_USER"(userid character varying) RETURNS void AS
$BODY$CREATE TEMP TABLE temp_privilege_ids
(
    privilege_id VARCHAR(100)
);    

SELECT "PRIVILEGE_ID"
INTO temp_privilege_ids
FROM 
(SELECT * FROM "T_USER_PRIVILEGES"
WHERE "USER_ID" = userid) as foo;

DELETE FROM "T_USER_PRIVILEGES"
WHERE "USER_ID" = userid;

DELETE FROM "T_PRIVILEGE"
WHERE "ID" IN
(SELECT privilege_id FROM temp_privilege_ids);$BODY$
LANGUAGE sql VOLATILE NOT LEAKPROOF;
ALTER FUNCTION public."SP_DELETE_USER"(character varying)
  OWNER TO postgres;

userid 是 SP 的参数。

当我尝试创建 SP pgAdmin 时说:

relation "temp_privilege_ids" does not exist
LINE 19: (SELECT privilege_id FROM temp_privilege_ids);$BODY$

我到处寻找解释,但没有找到答案。 有人有想法吗?

这是参考table:

CREATE TABLE "T_USER_PRIVILEGES" (
  "USER_ID" character varying(100) NOT NULL,
  "PRIVILEGE_ID" character varying(100) NOT NULL,
  CONSTRAINT "PK_T_USER_PRIVILEGES" PRIMARY KEY ("USER_ID", "PRIVILEGE_ID"),
  CONSTRAINT "FK_T_USER_PRIVILEGES_PRIVILEGES" FOREIGN KEY ("PRIVILEGE_ID")
      REFERENCES "T_PRIVILEGE" ("ID") MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT "FK_T_USER_PRIVILEGES_USER" FOREIGN KEY ("USER_ID")
      REFERENCES "T_USER" ("ID") MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
);

CREATE INDEX "FKI_T_USER_PRIVILEGES_PRIVILEGES"
  ON "T_USER_PRIVILEGES" ("PRIVILEGE_ID" COLLATE pg_catalog."default");

语言 SQL 功能已计划一次,因此您不能引用任何尚不存在的 table。您可以手动创建 temp table 以在创建时通过表面语法检查并允许创建函数,但该函数在执行时仍然会失败。

可以使用 plpgsql 函数实现您正在尝试的功能(应用评论中已提供的一些建议@a_horse_with_no_name):

CREATE OR REPLACE FUNCTION "SP_DELETE_USER"(_userid varchar) RETURNS void AS
$func$
BEGIN
   CREATE TEMP TABLE temp_privilege_ids ON COMMIT DROP AS
   SELECT "PRIVILEGE_ID"
   FROM   "T_USER_PRIVILEGES"
   WHERE  "USER_ID" = _userid;

   DELETE FROM "T_USER_PRIVILEGES"
   WHERE "USER_ID" = _userid;

   DELETE FROM "T_PRIVILEGE" t
   USING temp_privilege_ids tmp
   WHERE t."ID" = tmp."PRIVILEGE_ID";
END
$func$ LANGUAGE plpgsql;

但这仍然是不必要的复杂。只需使用 data-modifying CTE:

WITH del1 AS (
   DELETE FROM "T_USER_PRIVILEGES"
   WHERE  "USER_ID" = _userid  -- provide userid here
   RETURNING "PRIVILEGE_ID"
   )
DELETE FROM "T_PRIVILEGE" t
USING  del1
WHERE  t."ID" = del1."PRIVILEGE_ID";

抛开我对您的数据库设计和命名约定的疑虑。


,你的 FK 约束 "FK_T_USER_PRIVILEGES_PRIVILEGES" 似乎指向了 错误的方向 :它适用于多个用户可以链接到相同的特权(这是有道理的)。

如果是这样,请删除此约束并改为在 "T_PRIVILEGE"."ID" 上创建一个约束:

ALTER TABLE "T_PRIVILEGE"
ADD CONSTRAINT "FK_T_PRIVILEGE_ID" FOREIGN KEY ("ID")
   REFERENCES "T_USER_PRIVILEGES"("PRIVILEGE_ID") 
   ON UPDATE CASCADE ON DELETE CASCADE;

当您删除 "T_USER_PRIVILEGES" 中的行时,由于 CASCADE 子句,权限会 自动删除

仍然是一个奇怪的设计。 "Privileges" 通常是多个用户可以共享的内容...