2014-01-21 34 views
1

我有鄰接表表賬號,與列ID代碼,並PARENT_ID。 爲了使排序和顯示更容易,我添加了兩列:深度路徑(物化路徑)。我知道,postgresql具有物化路徑的專用數據類型,但我想使用更通用的方法,而不是特定於postgresql。我還在我的設計中應用了幾條規則:
1)代碼可以長達10個字符
2)最大深度爲9;所以根賬戶最多可以有8個子賬戶。
3)一旦設置,parent_id永遠不會改變,所以沒有必要將樹的分支移動到樹的另一部分。
4)路徑是一個帳戶的物化路徑,最長可達90個字符;它是通過連接帳戶代碼構建的,右側填充爲10個字符;例如,像'10000______10001______'。
因此,自動保持深度路徑列,我創建了一個觸發併爲賬號表觸發功能:PostgreSQL中,保持分層數據與觸發器

CREATE FUNCTION public.fn_account_set_hierarchy() 
RETURNS TRIGGER AS $$ 
DECLARE d INTEGER; p CHARACTER VARYING; 
BEGIN 
    IF TG_OP = 'INSERT' THEN 
    IF NEW.parent_id IS NULL THEN 
     NEW.depth := 1; 
     NEW.path := rpad(NEW.code, 10); 
    ELSE 
     BEGIN 
     SELECT depth, path INTO d, p 
        FROM public.account 
        WHERE id = NEW.parent_id; 
     NEW.depth := d + 1; 
     NEW.path := p || rpad(NEW.code, 10); 
     END; 
    END IF; 
    ELSE 
    IF NEW.code IS DISTINCT FROM OLD.code THEN 
     UPDATE public.account 
       SET path = OVERLAY(path PLACING rpad(NEW.code, 10) 
            FROM (OLD.depth - 1) * 10 + 1 FOR 10) 
     WHERE SUBSTRING(path FROM (OLD.depth - 1) * 10 + 1 FOR 10) = 
                  rpad(OLD.code, 10); 
    END IF; 
    END IF; 
    RETURN NEW; 
END$$ 
LANGUAGE plpgsql 

CREATE TRIGGER tg_account_set_hierarchy 
BEFORE INSERT OR UPDATE ON public.account 
FOR EACH ROW 
EXECUTE PROCEDURE public.fn_account_set_hierarchy(); 

以上似乎INSERT的工作。但對於UPDATE,則會引發錯誤:「表'帳戶'上的UPDATE語句預計會更新1行;匹配0。」我對「UPDATE public.account ...」部分有疑問。有人可以幫助我糾正上述觸發器嗎?

回答

0

那麼,在上面的代碼中,更新部分更新觸發器觸發的所有記錄(包括記錄)(concurrency execption?)。這似乎不起作用。所以我不得不發出兩條不同的聲明:

UPDATE {0}.{1} SET path = OVERLAY(path PLACING rpad(NEW.code, 10) 
FROM (OLD.depth - 1) * 10 + 1 FOR 10) 
WHERE SUBSTRING(path FROM (OLD.depth - 1) * 10 + 1 FOR 10) = rpad(OLD.code, 10) 
       AND id <> NEW.id; 
NEW.path = OVERLAY(OLD.path PLACING rpad(NEW.code, 10) 
         FROM (OLD.depth - 1) * 10 + 1 FOR 10);