【发布时间】:2021-12-22 16:18:09
【问题描述】:
我正在编写实用程序代码来运行pg_cron,有时希望例程将一些结果插入到位于dba.event_log 的自定义表中。我有一个基本的日志表作为起点:
DROP TABLE IF EXISTS dba.event_log;
CREATE TABLE IF NOT EXISTS dba.event_log (
dts timestamp NOT NULL DEFAULT now(),
name citext NOT NULL DEFAULT '',
details citext NOT NULL DEFAULT '');
下面的玩具示例执行select 操作,然后将该值用作外部查询的结果,并作为insert 的values 元素进入event_log:
WITH
values_cte AS (
select clock_timestamp() as ct
),
log as(
insert into event_log (
name,
details)
values (
'CTE INSERT check',
'clock = ' || (select ct::text from values_cte)
)
)
select * from values_cte;
select * from event_log;
每次运行此程序时,我都会收到一个新的日志条目,其中带有 clock_timestamp(),以便轻松查看正在发生的事情:
+----------------------------+------------------+---------------------------------------+
| dts | name | details |
+----------------------------+------------------+---------------------------------------+
| 2021-11-10 11:58:43.919151 | CTE INSERT check | clock = 2021-11-10 11:58:43.919821+11 |
| 2021-11-10 11:58:56.769512 | CTE INSERT check | clock = 2021-11-10 11:58:56.769903+11 |
| 2021-11-10 11:58:59.632619 | CTE INSERT check | clock = 2021-11-10 11:58:59.632822+11 |
| 2021-11-10 12:00:50.442282 | CTE INSERT check | clock = 2021-11-10 12:00:50.442646+11 |
+----------------------------+------------------+---------------------------------------+
稍后我可能会丰富表格,现在我将日志inserts 变成一个简单的调用。下面是一个简单的insert函数:
DROP FUNCTION IF EXISTS dba.event_log_add(citext,citext);
CREATE FUNCTION dba.event_log_add(
name_in citext,
description_in citext)
RETURNS int4
LANGUAGE sql AS
$BODY$
insert into event_log (name, details)
values (name_in, description_in)
returning 1;
$BODY$;
它看到我应该能够重写原始查询来调用函数,像这样:
WITH
values_cte AS (
select clock_timestamp() as ct
),
log as (
select * from dba.event_log_add(
'CTE event_log_add check',
'clock = ' || (select ct::text from values_cte)
)
)
select * from values_cte;
这里唯一的区别是VALUES 现在作为参数传递给dba.event_log_add,而不是直接在查询中用于INSERT。我收到此错误:
ERROR: function dba.event_log_add(unknown, text) does not exist
LINE 8: select * from dba.event_log_add(
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts. 0.000 seconds. (Line 1).
我试过了
- 显式转换
- 将函数重写为存储过程并使用
CALL - 重写PL/PgSQL中的函数,返回
VOID,运行PERFORM。
似乎没有任何效果。我检查了search_path,使用合格
名称,检查权限等。有些方法会抛出似乎不适用的错误,
像上面的一样,其他的没有错误,也没有插入数据。直接运行,功能正常,只是在CTE内炸了。
我想我在使用函数而不是直接INSERT 方面遗漏了一些东西。有没有好的方法来做到这一点?在查看文档并在此处搜索更多信息后,我对规则更清楚了bit。但也不完全。如果我没看错,数据修改 CTE 由外部查询规则/调节。肯定有一些我没有掌握的微妙之处。我是否以某种方式更改上下文以将 INSERT 移动到函数中,从而解释查询和 CTE 中的代码?
https://www.postgresql.org/docs/13/queries-with.html#QUERIES-WITH-MODIFYING
【问题讨论】:
标签: postgresql sql-insert common-table-expression stored-functions