我意识到Postgres中没有TRIGGER ON SELECT。给出一个像这样的表
CREATE TABLE t (
a INTEGER PRIMARY KEY,
b TEXT,
entered_by INTEGER,
qry_count INTEGER
);
我想为每个“entered_by”增加每个SELECT的“qry_count”,基本上跟踪每个“enterer”查询任何记录的次数。例如,
SELECT * a, b FROM t WHERE <condition>;
可能返回不同的enterers输入的“n”行。对于每个进入者,我想要qry_count ++。前面的伪代码
FOR EVERY entered_by IN SELECT
UPDATE t
SET qry_count = qry_count + 1
WHERE entered_by = <entered_by>
我可以在我的应用程序中最容易地做到这一点,但我想知道在数据库中执行此操作可能是最好的。我找到了example我认为我想去的地方,但它适用于PL / SQL。使用Pg实现这一目标的最佳方法是什么?
更新:在Perl中,我会这样做
$sth_sel = $dbh->prepare( .. complicated SELECT includes "entered_by" ..);
$sth_upd = $dbh->prepare("UPDATE t SET qry_count = qry_count + 1 WHERE entered_by = ?");
$sth_sel->execute( .. bind params ..);
while (my $r = $sth_sel->fetchrow_arrayref) {
my $entered_by = $r->[ 7 ]; # or whatever
$sth_upd->execute($entered_by);
.. do other things with $sth_sel, perhaps build a JSON obj to return ..
}
这看起来似乎最简单,但将此功能构建为数据模式的核心部分会很好。
UPDATE2:大多数示例(包括下面的建议)都依赖于创建PL / PgSQL函数。这种方法的问题是我的查询在函数中是硬编码的。即使它可以接受输入参数,它仍然是一个预先声明的查询。这意味着我必须为每个查询创建一个单独的函数。实际上,在我的应用程序中,我根据用户请求的内容(通过Web)动态构建查询。请求的列可以更改,提供的参数可以更改。我想我正在寻找一个类似于上面的Perl伪代码的SQL而没有预先声明的函数(下面的SQL伪代码)
BEGIN
FOR row IN
SELECT to my hearts content
FROM whatever tables I want JOINed horrendously
WHERE any arbitrary param
LOOP
eb := row[entered_by]
UPDATE t SET qry_count = qry_count + 1 WHERE entered_by = eb
RETURN NEXT row;
END LOOP;
RETURN;
END
希望这能使我的目标更清晰。
答案 0 :(得分:2)
您可以使用RETURNING
来使用UPDATE,而不是SELECT查询UPDATE t
SET
qry_count = qry_count + 1
WHERE
entered_by = <entered_by>
RETURNING a, b;
如果要更新计数器并将结果连接到另一个表,可以使用公用表表达式。使用UPDATE的CTE从版本9.1开始提供。
WITH cte AS (
UPDATE t
SET
qry_count = qry_count + 1
WHERE
entered_by = <entered_by>
RETURNING a, b
)
SELECT
*
FROM cte
JOIN other_table ON <..> = <..>;
答案 1 :(得分:2)
请注意qry_count列的默认值:
CREATE TABLE t (
a INTEGER PRIMARY KEY,
b TEXT,
entered_by INTEGER,
qry_count INTEGER default 0
);
create function select_and_update(parameter text)
returns setof t as $$
update t
set qry_count = qry_count + 1
from (
select a
from t
where b = $1
) s
where t.a = s.a
;
select *
from t
where b = $1
;
$$ language sql;
现在使用上述函数查询表:
select * from select_and_update('a');
根据评论更新:
你可以动态地构建它,而不是函数只是在事务中包装sql代码,无论它是什么。不需要游标。
begin;
update t
set qry_count = qry_count + 1
from (
select a
from t
where b = 'a'
) s
where t.a = s.a
;
select *
from t
where b = 'a'
;
commit;
答案 2 :(得分:1)
PostgreSQL UPDATE功能FROM子句,提供数据驱动的更新。例如:
UPDATE table1 t1
SET blah = t2.c1
FROM table2 t2
WHERE t1.id = t2.t1id
from_list :: =表表达式列表,允许列来自 其他表出现在WHERE条件和更新中 表达式。这类似于可以的表列表 在SELECT语句的FROM子句中指定。请注意 目标表不得出现在from_list中,除非您打算使用 自联接(在这种情况下,它必须出现在别名中 from_list)。
但是对于您的特定情况,使用WHERE ... IN ...
进行简单更新可以解决问题:
UPDATE t
SET qry_count = qry_count + 1
WHERE entered_by IN ( SELECT entered_by FROM ... WHERE [your condition] )