当对 TABLE1 进行 SELECT 查询时,如何创建将 TABLE1 的值插入到 TABLE2 的规则

How can I create a RULE that INSERTS values of TABLE1 to TABLE2 when a SELECT query is made on TABLE1

我意识到我无法为 SELECT 创建触发器,因此要依靠规则。

CREATE OR REPLACE RULE log_select AS 
ON SELECT TO usertable 
DO ALSO INSERT INTO selectLOG(prim_key,val)
VALUES(prim_key,val);

以上示例不工作,出现以下错误:

ERROR:  column "prim_key" does not exist
LINE 4: VALUES(prim_key,val)
               ^
HINT:  There is a column named "prim_key" in table "old", but 
it cannot be referenced from this part of the query.

基本上,我想在用户对表 1 进行 SELECT 时将行插入表 2。

The documentation 说:

Currently, there can be only one action in an ON SELECT rule, and it must be an unconditional SELECT action that is INSTEAD. This restriction was required to make rules safe enough to open them for ordinary users, and it restricts ON SELECT rules to act like views.

所以你将无法为所欲为。

您可以选择使用日志文件或编写挂接到查询执行程序的 C 代码。

如果要使用日志记录,请设置 log_statement = alllog_min_duration_statement = 0,然后将记录所有语句,包括 SELECTs。

作为源代码中的钩子,您可以使用 include/executor/executor.h 中的 ExecutorEnd_hook。这将在执行程序结束时调用,并且 queryDesc->sourceText 将指向正在处理的语句。阅读 auto_explain 以了解如何使用此挂钩的示例。

正如 Laurenz 所指出的,这在规则中是不可能的。

但是您是否考虑过一个可以访问 table 而不是直接访问 table 本身的函数?

您可以创建一个函数来运行查询、存储结果并 returns 它。然后仅授予该函数的执行权限并撤销对该函数的任何直接访问 table.

类似于:

create function get_usertable(p_key integer)
  returns setof usertable
as
$$
  with result as (
     select *
     from usertable
     where id = p_key
  ), log_query as (
     insert into selectlog (prim_key, val)
     select *
     from result
  )
  select *
  from result;
$$
language sql;

此解决方案的主要缺点是,您必须为可能需要的任何条件提供参数(参数 p_key 只是一个示例)。如果 WHERE 子句的选项有限,那么这可能是一个替代方案。如果你需要更复杂的 where 条件,你可以使用动态 SQL (和 PL/pgSQL 函数而不是 SQL 函数),但这也很快变得丑陋。