2013-07-25 77 views
3

我有以下的 - 不工作 - 功能:plgpsql - 是否可以聲明setof記錄或表變量?

CREATE FUNCTION permission_cache_update(affected_user_list int[]) 
    RETURNS TABLE(user_id INT4, permission_id INT4) 
AS 
    $BODY$ 
    DECLARE 
    current_relations SETOF RECORD; 
    BEGIN 

    WITH 
    affected_user AS (
    SELECT unnest(affected_user_list) AS u_id 
), 
    affected_relations AS (
    SELECT user_role.user_id, role_permission.permission_id 
     FROM user_role 
     JOIN role_permission ON user_role.role_id = role_permission.role_id 
     JOIN affected_user ON affected_user.u_id = user_role.user_id 
    UNION 
    SELECT user_permission.user_id, user_permission.permission_id 
     FROM user_permission 
     JOIN affected_user ON affected_user.u_id = user_permission.user_id 
) 
    SELECT affected_relations.user_id, affected_relations.permission_id FROM affected_relations 
    INTO current_relations; 

    DELETE FROM permission_cache WHERE ARRAY[user_id] <@ affected_user_list; 
    INSERT INTO permission_cache (user_id, permission_id) SELECT user_id, permission_id FROM current_relations; 

    END 
    $BODY$ 
LANGUAGE plpgsql; 

我想將當前用戶的權限關係,current_relations存儲爲(INT4,INT4)。是否有可能做到這一點與變量沒有循環和臨時表?

我會用這樣的事情以後,所以我真的需要它作爲變量,而不是子查詢

DELETE FROM permission_cache WHERE ARRAY[user_id] <@ affected_user_list AND NOT IN (SELECT user_id, permission_id FROM current_relations); 

INSERT INTO permission_cache (user_id, permission_id) SELECT user_id, permission_id FROM current_relations WHERE NOT EXIST (SELECT user_id, permission_id FROM permission_cache); 

我認爲這是可能的表 - >二維數組轉換,但這是複雜的,因此,如果它可能與記錄,它會更好...

解決方案:

這是比較容易創建一維數組,而不是使用記錄或二維數組循環:

CREATE FUNCTION permission_cache_update(
    IN affected_user_list INT4 [] 
) 
    RETURNS VOID 
AS 
    $BODY$ 
    DECLARE 
    user_index     INT4; 
    current_user_id INT4; 
    current_permission_relations INT4 []; 
    deleted_permission_relations INT4 []; 
    inserted_permission_relations INT4 []; 
    BEGIN 
    FOR user_index IN 1 .. array_upper(affected_user_list, 1) LOOP 
     current_user_id := affected_user_list[user_index]; 

     WITH 
      user_permission_summary AS 
     (
      SELECT 
      role_permission.permission_id 
      FROM user_role, role_permission 
      WHERE role_permission.role_id = user_role.role_id AND user_role.user_id = current_user_id 
      UNION 
      SELECT 
      user_permission.permission_id 
      FROM user_permission 
      WHERE user_permission.user_id = current_user_id 
     ) 
     SELECT 
     array_agg(permission_id) 
     FROM user_permission_summary 
     INTO current_permission_relations; 

    SELECT 
     array_agg(permission_cache.permission_id) 
    FROM permission_cache 
    WHERE permission_cache.user_id = current_user_id AND (current_permission_relations IS NULL OR 
      NOT (ARRAY [permission_cache.permission_id] <@ current_permission_relations)) 
    INTO deleted_permission_relations; 

    SELECT 
     array_agg(inserted_permission_id) 
    FROM unnest(current_permission_relations) AS inserted_permission_id 
    WHERE NOT EXISTS(SELECT 
         1 
        FROM permission_cache 
        WHERE permission_cache.user_id = current_user_id AND 
          permission_cache.permission_id = inserted_permission_id) 
    INTO inserted_permission_relations; 

    DELETE FROM permission_cache 
    WHERE permission_cache.user_id = current_user_id AND 
      permission_cache.permission_id = ANY (deleted_permission_relations); 

    INSERT INTO permission_cache (user_id, permission_id) 
     SELECT 
     current_user_id, 
     inserted_permission_id 
     FROM unnest(inserted_permission_relations) AS inserted_permission_id; 

    END LOOP; 
    END; 
    $BODY$ 
LANGUAGE plpgsql VOLATILE; 

關: Pplpgsql是一個更差勁的文檔一個非常貧窮的語言,我不喜歡它... 很抱歉的代碼格式,套用在我的IDE也不是那麼好...:S

+0

您仍然聲明:'RETURNS TABLE(user_id INT4,permission_id INT4)'。這是一個神器還是你真的想要另外返回行? –

+0

Ohh no:D它只是以前代碼的一部分... – inf3rno

回答

1

我覺得這個簡化SQL函數可能你在找什麼:

CREATE FUNCTION permission_cache_update(affected_user_list int[]) 
    RETURNS void AS 
$func$ 

DELETE FROM permission_cache p 
USING (SELECT unnest($1) AS u_id) a 
WHERE p.user_id = a.u_id; 

INSERT INTO permission_cache (user_id, permission_id) 
SELECT u.user_id, r.permission_id 
FROM user_role u 
JOIN role_permission r USING (role_id) 
JOIN (SELECT unnest($1) AS u_id) a ON a.u_id = u.user_id 
UNION 
SELECT p.user_id, p.permission_id 
FROM user_permission p 
JOIN (SELECT unnest($1) AS u_id) a ON a.u_id = p.user_id; 

$func$ LANGUAGE sql; 

Writable CTE (a.k.a. data-modifying CTE)將大大簡化這一點,但只用9.1 Postgres的介紹。再一次,你的過時版本正在發揮作用。

通過名稱引用參數僅在Postgres 9.2中爲SQL函數(先前爲plpgsql)引入。所以我使用位置參數$1

+0

Yepp,但我不想簡化,在下一個版本的函數中,我將刪除並只插入真正需要的東西......我想關於它,2維數組有可能嗎?我不認爲這是可能的記錄和沒有循環... Setof記錄不工作,我不認爲有這樣的事情作爲記錄數組... – inf3rno

+0

我編輯了這個問題... – inf3rno

+0

@ inf3rno :當然有這樣的事情。您可以使用多維數組或記錄數組,即使在舊的Postgres 8.4中也是如此。我昨天回答了一個[密切相關的問題](http://stackoverflow.com/questions/12009822/how-to-pass-custom-type-array-to-postgres-function/17840058#17840058)。以同樣的方式工作8.4。順便說一句,臨時表有什麼問題?對於更大的組合,這通常會更快。在現代Postgres中,您可以使用單個數據修改CTE完成所有工作。 –

相關問題