postgresql 中的更新语句后未触发规则

发布于 2024-10-28 06:20:34 字数 1277 浏览 1 评论 0原文

按照 www.postgresql.org 中的指南

我创建了此语句:

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)"

我还尝试将 VERBOSE 选项与 EXPLAIN 一起使用,但我无法理解为什么我的事件没有被触发。

Following the guide in www.postgresql.org

I created this statement:

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
                            );

When i try to execute the query in pgAdmin3 query console:

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

Only the update query are executed, and the rule isn't fired. I try to use the command EXPLAIN to understand why.

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

The log says:

"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)"

I also try to use VERBOSE option with EXPLAIN, but i can't understand why my event isn't trigged.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

通知家属抬走 2024-11-04 06:20:34

您选择了错误的功能。完全忘记规则——它们很难,几乎不可能做好。

这里你需要的是一个触发器:

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

You have chosen wrong feature. Forget rules altogether — they're very hard, almost impossible to do right.

What you need here is a trigger:

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();

Try it:

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
梅倚清风 2024-11-04 06:20:34

您可能还想考虑使用为您执行此操作的预构建插件:

http://pgfoundry.org/项目/表日志/

You might also want to consider using the pre-built addon that does that for you:

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

凤舞天涯 2024-11-04 06:20:34

我尝试了这个例子,它成功了。但我必须先创建hoelace_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_data 中的 sl_avail 列有更新时插入到 shoelace_log 中。

I tried the example, and it worked. But I had to create the shoelace_data table first. That table isn't in the example.

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

Now if you select from the log table . . .

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

Note carefully that the rule says to insert into shoelace_log when there's an update to the sl_avail column in shoelace_data.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文