标签: plpgsql

即使函数中止,也会在 UDF 中持久插入

我有一个相当复杂的 UDF(在一堆表中移动并创建一堆新表),其中可能会发生多次中止。在每次操作之前,我想记录操作发生的时间和查询本身。UDF 如下所示:

log function_start

log sql1
execute sql1

log sql2
execute sql2

...

log sqlN
execute sqlN

log function_end
Run Code Online (Sandbox Code Playgroud)

每条日志语句都意味着向下表中插入一条新记录:

CREATE TABLE backup_logs
(
  id serial NOT NULL,
  t timestamp with time zone default now(),
  sql text,
  CONSTRAINT backup_logs_pkey PRIMARY KEY (id)
)
Run Code Online (Sandbox Code Playgroud)

如果发生中止,我希望sql1, sql2, ... sqlN回滚,但inserto into backup_logs会继续存在。问题:我怎样才能实现这一目标?

postgresql insert transaction plpgsql postgresql-9.4

5
推荐指数
1
解决办法
1076
查看次数

使用当前行和当前表名作为变量的触发函数(最后部分)

就像我的第一个问题中详细介绍的那样,我有一个Postgres 9.1数据库,其中有多个表,这些表具有完全相同的列名,它们仅在列值上有所不同:

tbl_log_a
tbl_log_b
tbl_log_c
...
Run Code Online (Sandbox Code Playgroud)

26 个表(从 a 到 z)。trfn_tbl_log_%letter%每个表都有一个触发器,它调用名为(from ato )的触发器函数z,该函数执行完全相同的操作:

CREATE OR REPLACE FUNCTION trfn_tbl_log_a_timetypespan()
  RETURNS trigger AS
$BODY$
DECLARE
v_timetype character varying;
v_timestmp_timetype timestamp without time zone;
v_timetypespan_resume interval;
v_stmtserial real;
v_sumtimetypespan_fnname interval;

BEGIN

IF NEW.timetype = 'lap' THEN
  SELECT timetype, timestmp, timetypespan FROM tbl_log_a WHERE fnname = NEW.fnname AND (timetype = 'start' OR timetype = 'resume') ORDER BY stmtserial DESC LIMIT 1 INTO v_timetype, v_timestmp_timetype, v_timetypespan_resume; …
Run Code Online (Sandbox Code Playgroud)

postgresql trigger dynamic-sql plpgsql postgresql-9.1

5
推荐指数
1
解决办法
274
查看次数

“错误:“EXECUTE .. USING ..;”中没有参数 $1” plpgsql 中的语句

我有一个 plpgsql 函数来使用 PostgreSQL 中的表继承创建子表,如下所示:

CREATE TABLE parent_table (
  value integer,
  end_time timestamp without time zone
);

CREATE OR REPLACE FUNCTION mk_child(_year INTEGER, _month INTEGER)
  RETURNS text AS $$
DECLARE
  tname varchar;
  start_date date;
  end_date date;
  next_month varchar := (_month + 1)::text;
  next_year varchar := (_year + 1)::text;
BEGIN
  tname := 'child_y' || substring(_year::text from 3 for 2)
           || 'm' || lpad(_month::text, 2, '0');
  start_date := DATE (_year::text || '-' || _month::text || '-01');
  IF ( _month = 12 ) …
Run Code Online (Sandbox Code Playgroud)

postgresql dynamic-sql ddl plpgsql postgresql-9.4

5
推荐指数
1
解决办法
1万
查看次数

如何使用变量的值设置列 DEFAULT

在设置使用随机 UUID 作为主键的数据库的脚本中,我有:

CREATE TABLE alpha (id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), value INT);
CREATE TABLE beta (aref UUID REFERENCES alpha (id));

INSERT INTO alpha (value) VALUES (42);
Run Code Online (Sandbox Code Playgroud)

然后通过外键,让“alpha”中的记录成为插入“beta”表的默认目标:

DO $$
    DECLARE l_id UUID;
    BEGIN
        SELECT alpha.id FROM alpha INTO l_id;
        ALTER TABLE beta ALTER COLUMN aref SET DEFAULT l_id;
    END;
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
ERROR:  column "l_id" does not exist
CONTEXT:  SQL statement "ALTER TABLE beta ALTER COLUMN aref SET DEFAULT l_id"
PL/pgSQL function inline_code_block line 1 at SQL statement …
Run Code Online (Sandbox Code Playgroud)

postgresql dynamic-sql default-value alter-table plpgsql

5
推荐指数
1
解决办法
4661
查看次数

如何在 Postgres 中一次更新多个表?

我有几个结构完全相同的表,我需要更新所有表中的值。

为此,我尝试构建以下脚本:

DO
$do$
DECLARE
  i pg_tables%rowtype;
BEGIN
FOR i IN SELECT * FROM pg_catalog.pg_tables where schemaname like 'public' and tablename like '%_knex_migrations'
LOOP
    UPDATE i.tablename SET name = replace(name, '.js', '.ts');
END LOOP;
END
$do$;
Run Code Online (Sandbox Code Playgroud)

我可以看到它i.tablename具有正确的值(我插入到 tmp 表中进行检查),但更新失败。

name: error
length: 223
severity: ERROR
code: 42P01
internalPosition: 8
internalQuery: UPDATE i."tablename" SET name = replace(name, '.js', '.ts')
where: PL/pgSQL function inline_code_block line 7 at SQL statement
file: parse_relation.c
line: 965
routine: parserOpenTable
Run Code Online (Sandbox Code Playgroud)

只是声明i.tablename上的插件UPDATE不起作用。 …

postgresql dynamic-sql plpgsql update

5
推荐指数
1
解决办法
1万
查看次数

触发函数更新列

我是 PL/pgSQL 的新手……我使用 Postgres 9.5.0,每次插入新记录时都需要更新一列。该列应从area_pol和 中输入的值中填写area_ofi

我正在尝试创建此功能以适合我的情况:

CREATE OR REPLACE FUNCTION sch_cap.fc_atualiza_dif_area()
  RETURNS trigger AS
$$
BEGIN
    UPDATE
        sch_cap.tbl_cap
    SET
        dif_area = abs(100 - (tbl_cap.area_pol / (tbl_cap.area_ofi * 100)));
END;
$$
LANGUAGE plpgsql;

CREATE TRIGGER tg_atualiza_dif_area
  BEFORE INSERT OR UPDATE ON sch_cap.tbl_cap
  FOR EACH ROW EXECUTE PROCEDURE sch_cap.fc_atualiza_dif_area();
Run Code Online (Sandbox Code Playgroud)

但是当我尝试插入记录时,出现以下错误:

错误:超出堆栈深度限制
提示:在确保平台的堆栈深度限制足够后,增加配置参数“max_stack_depth”(当前为 2048kB)。

如何做对?

trigger plpgsql functions postgresql-9.5

5
推荐指数
2
解决办法
1358
查看次数

带有 SELECT 的 SQL 函数与带有 RETURN QUERY SELECT 的 PLPGSQL 函数?

执行 SQL 查询的普通 SQL 函数之间是否有区别:

create function get_sports() returns setof sport as
$body$
    select * from sport;
$body$
language sql stable;
Run Code Online (Sandbox Code Playgroud)

和 PLPGSQL 函数返回相同的 SQL 查询:

create function get_sports() returns setof sport as
$body$
begin
    return query select * from sport;
end
$body$
language plpgsql stable;
Run Code Online (Sandbox Code Playgroud)

关于性能?在什么情况下应该使用哪个版本?

如果我们传递参数,那会改变什么吗?如:

create function get_sports(status int) returns setof sport as
$body$
    select * from sport where status = $1;
$body$
language sql stable;

create function get_sports(status int) returns setof sport as
$body$
begin
    return …
Run Code Online (Sandbox Code Playgroud)

postgresql performance plpgsql functions postgresql-performance

5
推荐指数
1
解决办法
1915
查看次数

PostgreSQL UDF(用户定义函数)开销

免责声明

这项任务可能看起来很深奥,但我还是想创建某种 POC。

目标

我的目标是让 PostgreSQL 数据库(版本 10)向使用它的应用程序公开一个 API。

API 需要采用一组 UDF 的形式:所有函数都属于一个公共方案,这是应用程序唯一可以访问的。桌子和其他东西隐藏在私人计划中。几乎就像,您知道的,面向对象的数据库
这就是我试图让它发挥作用的原因:

  • 它将数据库与应用程序分离,因此您可以重构/优化/非规范化前者,而破坏后者的风险较小。您甚至可以将其维护委托给另一个团队或部门(哦,天哪)
  • API 将服务的要求形式化。数据库当然是一种服务,但称为迁移的传统机制并不能很好地用于弄清楚其中发生了什么。想想多年来收集的成百上千的迁移,其中一些已经损坏,再也不会工作了,并且

好吧,没关系。

问题

因此,当我尝试创建一些非常简单的函数(例如从表中获取所有记录)时,我提到它们总是比它包装的查询慢。虽然这本身是完全可以接受和理解的,但时间差异可能很大。因此,无法接受。

这个例子

我有一张这样的桌子。

CREATE TABLE notifications (
    id SERIAL PRIMARY KEY,
    source_type INTEGER NOT NULL,
    content JSONB,
    created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP(3)
)
Run Code Online (Sandbox Code Playgroud)

并且其中有 >120k 条记录。
想象一下,我们想要获得所有这些。
在这里,我们通过一个简单的查询来完成。没有索引,JSONB 数据几乎每条记录 1kb。

EXPLAIN (ANALYZE,VERBOSE,BUFFERS) SELECT * FROM private.notifications;
                                                         QUERY PLAN                                                              
-------------------------------------------------------------------------------------------------------------------------------------
Seq Scan on private.notifications  (cost=0.00..16216.13 rows=120113 width=877) (actual time=0.015..496.473 rows=120113 loops=1)
  Output: id, source_type, content, created
  Buffers: …
Run Code Online (Sandbox Code Playgroud)

postgresql performance plpgsql functions postgresql-performance

5
推荐指数
1
解决办法
940
查看次数

如何从命令行将变量传递给 PL/pgSQL 代码?

我正在从命令行运行 psql 脚本,其中的变量类似于:

psql ...... -v now_utc=$NOW_UTC 
Run Code Online (Sandbox Code Playgroud)

然后我想在我的脚本中使用它,例如:

$$
DECLARE
   _now_date timestamp := :now_utc;
BEGIN
  -- do something
END
$$
Run Code Online (Sandbox Code Playgroud)

但我得到了一个错误,如:

syntax error at or near ':'
Run Code Online (Sandbox Code Playgroud)

一旦我从:now_utc变为now(),脚本就很好,它就像一个魅力。

问题是如何将变量从命令行传递给 PL/pgSQL 代码?

postgresql psql plpgsql string-manipulation

5
推荐指数
1
解决办法
2708
查看次数

通过基于传入的数组进行过滤,允许来自 plpgsql 函数的动态结果集?

我想我已经避免了这里的 XY 问题,因为我正在为真正的潜在问题(以动态方式总结多个表)列出我的解决方案,而且我只询问我卡住的最后一个部分。因此,首先有一些背景知识。我提供了一个最小的示例数据集,以及用于以我描述的方式汇总数据的工作代码。


考虑如下设置:

create temp table tbl1 (id int primary key, category text, passing boolean);

insert into tbl1 values
(1, 'A', 't'),
(2, 'A', 't'),
(3, 'A', 't'),
(4, 'A', 'f'),
(5, 'B', 't'),
(6, 'B', 'f'),
(7, 'C', 't'),
(8, 'C', 't'),
(9, 'C', 'f'),
(10, 'C', 'f'),
(11, 'C', 'f'),
(12, 'C', 'f'),
(13, 'B', 't'),
(14, 'B', 'f'),
(15, 'B', 't'),
(16, 'B', 'f'),
(17, 'B', 't'),
(18, 'B', 'f'),
(19, 'B', 't'),
(20, …
Run Code Online (Sandbox Code Playgroud)

postgresql aggregate plpgsql array postgresql-10

5
推荐指数
1
解决办法
66
查看次数