реализация ОБНОВЛЕНИЯ на SELECT в Postgres - PullRequest
2 голосов
/ 29 марта 2012

Я понимаю, что в Postgres нет TRIGGER ON SELECT.Для такой таблицы

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

я хочу увеличивать "qry_count" для каждого SELECT для каждого "enter_by", по сути отслеживая, сколько раз запрашивается любая запись для каждого "входящего".Например,

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

может возвращать "n" строк, введенных разными участниками.Для каждого участника я хочу qry_count ++.Впереди псевдокод

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

Я мог бы сделать это проще всего в своем приложении, но мне интересно, может быть лучше сделать это в самой базе данных.Я нашел пример о том, куда, я думаю, я хочу пойти, но это для 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.Проблема этого подхода в том, что мой запрос жестко запрограммирован в функции.Даже если он может принимать входные параметры, это все равно предварительно объявленный запрос.Это означает, что я должен создать отдельную функцию для каждого запроса.На самом деле, в моем приложении я строю запросы динамически на основе того, что запрашивает пользователь (через Интернет).Запрошенные столбцы могут измениться, предоставленные параметры могут измениться.Я думаю, что я ищу SQL, аналогичный псевдокоду Perl выше, без предварительно объявленной функции (псевдокод 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

Надеюсь, это прояснит мою цель.

Ответы [ 3 ]

2 голосов
/ 29 марта 2012

Обратите внимание на значение по умолчанию для столбца 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 голосов
/ 29 марта 2012

Вместо запроса SELECT вы можете использовать ОБНОВЛЕНИЕ, используя RETURNING :

UPDATE t 
SET 
  qry_count = qry_count + 1
WHERE 
  entered_by = <entered_by>
RETURNING a, b;

Если вы хотите обновить счетчик и объединить результат с другой таблицей, вы можете использовать выражение общей таблицы. CTE, использующие UPDATE, доступны с версии 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 голос
/ 30 марта 2012

PostgreSQL ОБНОВЛЕНИЕ функции ОТ предложение, которое обеспечивает обновления на основе данных. Пример:

UPDATE table1 t1 
SET blah = t2.c1 
FROM table2 t2 
WHERE t1.id = t2.t1id 

from_list :: = Список табличных выражений, допускающих столбцы из другие таблицы должны отображаться в состоянии WHERE и обновлении выражения. Это похоже на список таблиц, которые могут быть указано в предложении FROM оператора SELECT. Обратите внимание, что таблица назначения не должна появляться в списке_файлов, если вы не самостоятельное соединение (в этом случае оно должно появляться с псевдонимом в from_list).

Однако для вашего конкретного случая простое обновление с WHERE ... IN ... поможет:

UPDATE t
SET qry_count = qry_count + 1
WHERE entered_by IN ( SELECT entered_by FROM ... WHERE [your condition] )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...