无法从临时表中进行选择

时间:2015-10-20 11:39:34

标签: postgresql temp-tables postgresql-9.4

我有3个表格 - T_USERT_PRIVILEGET_USER_PRIVILEGES

T_USER_PRIVILEGES是一个参考表,其中包含从T_USER行到T_PRIVILEGE行的引用。我想删除T_USER中的一行,我需要首先删除T_USER_PRIVILEGES中的引用,以及T_PRIVILEGE中所有引用的行。

我想创建一个临时表,其中包含T_PRIVILEGE中所有引用的行,然后删除T_USER_PRIVILEGES中的所有引用,最后删除存储在T_PRIVILEGE中的所有行临时表。

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

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$

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

这是参考表:

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");

1 个答案:

答案 0 :(得分:0)

语言SQL函数是一次计划的,因此您无法引用任何尚未存在的表。您可以手动创建临时表以在创建时传递表面语法检查并允许创建函数,但该函数在执行时仍会失败。

可以使用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";

不管我对数据库设计和命名惯例的怀疑。

According to your comment,您的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中的行时,权限会自动删除

仍然是一个奇怪的设计。 "权限"通常是多个用户可以共享的东西......