2015-10-20 67 views
0

我有3个表格 - T_USER,T_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

无关,但:'select .. into temp_privilege_ids'应该是'insert into temp_privilege_ids select ...'。或者更好:只使用一个'create table ... as select ...' –

+0

在_compile_ time期间检查表的存在,并且在创建函数时,表确实不存在。编译器不知道表在运行时会存在。 –

+0

Plus:临时表完全没用。这可以用这两个滑动delete语句来完成(或:创建两个表之间的FK约束与'上删除cascade') –

回答

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条款。

尽管如此奇数设计。 “特权”通常是多个用户可以共享的东西...

+1

如果特权被其他用户使用,也 –

+0

@a_horse_with_no_name的'从t_privilege'删除会失败:是的。我怀疑这个设置是否合理。只是展示适当的技术。无法修复这里的破碎设计。我也会使用不同的名称和数据类型。 –

+0

用户与特权之间的关系是一对多关系,意味着其他人不会使用该特权。 – Elliko