2015-10-20 107 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