在Postgres中的SELECT上实现UPDATE [英] implementing an UPDATE on SELECT in Postgres

查看:2105
本文介绍了在Postgres中的SELECT上实现UPDATE的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道Postgres中没有TRIGGER ON SELECT。给定这样的表

I realize there are is no TRIGGER ON SELECT in Postgres. Given a table like so

CREATE TABLE t (
    a INTEGER PRIMARY KEY, 
    b TEXT, 
    entered_by INTEGER, 
    qry_count INTEGER
);

我想为每个 entered_by的每个SELECT增加 qry_count,本质上是跟踪如何很多时候查询每个输入者的记录。例如,

I want to increment "qry_count" for every SELECT for every "entered_by", essentially keeping track of how many times any record is queried for every "enterer". For example,

SELECT * a, b FROM t WHERE <condition>;

可能返回由不同输入者输入的 n行。对于每个输入者,我要qry_count ++。伪代码

might return "n" rows entered by different enterers. For each enterer, I want to qry_count++. Pseudocode ahead

FOR EVERY entered_by IN SELECT
    UPDATE t
    SET qry_count = qry_count + 1
    WHERE entered_by = <entered_by>

我可以在应用程序中最轻松地执行此操作,但是我想知道是否可以在数据库本身中执行此操作可能是最好的。我找到了示例关于我想去的地方,但它适用于PL / SQL。用Pg完成此操作的最佳方法是什么?

I could do this most easily in my application, but I am wondering if doing this in the database itself might be best. I found an example of where I think I want to go, but it is for PL/SQL. What is the best way to accomplish this with Pg?

更新:在Perl中,我会这样做

Update: In Perl I would do it like so

$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 ..
}

这似乎是最简单的方法,但是最好将此功能构建为数据模式的核心部分。

That does seem the easiest, but it would be nice to build this functionality right as a core part of the data schema.

UPDATE2::大多数示例(包括以下建议)都依赖于创建PL / PgSQL函数。这种方法的问题是我的查询是在函数中硬编码的。即使可以接受输入参数,它仍然是预先声明的查询。这意味着我必须为每个查询创建一个单独的函数。实际上,在我的应用程序中,我根据用户(通过Web)的请求动态构建查询。请求的列可以更改,提供的参数可以更改。我想我正在寻找类似于上述Perl伪代码的SQL,但没有预先声明的函数(下面的SQL伪代码)

UPDATE2: Most examples (including suggestions below) rely on creating a PL/PgSQL function. The problem with this approach is that my query is hard-coded in the function. Even if it can take input params, it is still a pre-declared query. This means I have to create a separate function for each query. In reality, in my application I construct the queries dynamically based on what is requested by the user (via the web). The requested columns can change, the supplied params can change. I think I am looking for a SQL analogous to the Perl pseudocode above without a predeclared function (SQL pseudocode below)

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

希望这使我的目标更清晰。

Hope this makes my objective clearer.

推荐答案

注意qry_count列的默认值:

Notice the default value for the qry_count column:

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;

现在使用上述函数查询表:

Now query the table using the above function:

select * from select_and_update('a');

根据评论进行更新:

您可以动态地构建它,而不是使用它来构建函数,只需将sql代码包装在事务中即可。

You can build it dynamically and in instead of a function just wrap the sql code, whatever it is, in a transaction. No need for cursors.

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;

这篇关于在Postgres中的SELECT上实现UPDATE的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆