2011-03-30 109 views
2

更新語句後沒有被解僱繼www.postgresql.org規則PostgreSQL中

引導我創造了這個說法:

CREATE TABLE shoelace_log (
sl_name text,   -- shoelace changed 
sl_avail integer,  -- new available value 
log_who text,   -- who did it 
log_when timestamp  -- when); 
CREATE RULE log_shoelace AS ON UPDATE TO shoelace_data 
WHERE NEW.sl_avail <> OLD.sl_avail 
DO INSERT INTO shoelace_log VALUES (
           NEW.sl_name, 
           NEW.sl_avail, 
           current_user, 
           current_timestamp 
          ); 

當我嘗試執行在pgAdmin3查詢臺查詢:

UPDATE shoelace_data SET sl_avail = 6 WHERE sl_name = 'sl7'; 

只執行更新查詢,並且規則未被觸發。我嘗試使用EXPLAIN命令來理解原因。

EXPLAIN UPDATE shoelace_log SET sl_avail = 6 WHERE sl_name = 'sl7'; 

日誌說:

"Seq Scan on shoelace_log (cost=0.00..19.66 rows=4 width=32)" 
" Filter: (sl_name = 'sl7'::text)" 
"Seq Scan on shoelace_log (cost=0.00..19.62 rows=4 width=78)" 
" Filter: (sl_name = 'sl7'::text)" 

我也嘗試使用EXPLAIN與VERBOSE選項,但我不明白爲什麼不觸發我的事件。

+0

我試着運行你在pg9上鍊接的樣本,並且有同樣的問題。 – Kuberchaun 2011-03-30 15:25:53

+1

你說你的pgAdmin3查詢是UPDATE * shoelace_data *,但是你解釋了更新* shoelace_log *(日誌表)......你確定你正在鍵入你認爲你正在輸入的查詢嗎? – pilcrow 2011-03-30 19:07:31

回答

3

您選擇了錯誤的功能。完全忘記規則—他們非常努力,幾乎不可能做對。

你所需要的就是一個觸發器:

create or replace function shoelace_log_who_when() 
returns trigger language plpgsql as 
$$ 
begin 
    if OLD.sl_avail is distinct from NEW.sl_avail then 
    NEW.log_who = current_user; 
    NEW.log_when = current_timestamp; 
    end if; 
    return NEW; 
end; 
$$; 

create trigger shoelace_log_who_when before update on shoelace_log 
    for each row execute procedure shoelace_log_who_when(); 

試試:

insert into shoelace_log values ('foo', 1, NULL, NULL); 
select * from shoelace_log; 
sl_name | sl_avail | log_who | log_when 
---------+----------+---------+---------- 
foo  |  1 |   | 
update shoelace_log set sl_avail=2; 
select * from shoelace_log; 
 sl_name | sl_avail | log_who |   log_when   
---------+----------+----------+--------------------------- 
foo  |  2 | tometzky | 2011-03-30 17:06:21.07137 
+0

+1對於很好的答案,但仍不能解釋爲什麼這樣一個簡單的例子不起作用。 – Kuberchaun 2011-03-30 15:32:57

+0

這就是爲什麼你不應該使用規則。它們非常複雜,即使經驗豐富的Postgres用戶也不會試圖解釋他們的行爲。我認爲他們考慮在Postgres —中使用INSTEAD OF觸發器在9.1中查看它們,因爲它們不再需要任何東西。 – Tometzky 2011-03-30 15:39:31

+0

太糟糕了,pg文檔沒有說明你不應該使用它們。我已經閱讀了幾個原因,他們爲什麼是痛苦的,應該避免,但不是因爲它們不像文檔描述的那樣運作。 – Kuberchaun 2011-03-30 15:48:11

1

您可能還需要考慮使用預構建的插件那是爲你做的:

http://pgfoundry.org/projects/tablelog/

+0

它不是tablelog。它只是爲了填寫自動上次修改時間戳和表中的用戶。 – Tometzky 2011-03-30 15:21:40

0

我試過這個例子,它工作。但我必須先創建shoelace_data表。該表不在該示例中。

create table shoelace_data (
    sl_name text, 
    sl_avail integer 
); 
insert into shoelace_data values ('Catcall', 3); 
update shoelace_data set sl_avail = 5; 

現在,如果你從日誌表中選擇。 。 。

select * from shoelace_log; 
"Catcall";5;"postgres";"2011-03-31 20:40:10.906" 

注意仔細該規則說要插入shoelace_log時,有在shoelace_data一個更新的sl_avail列。