在 Postgres 13.4 的 SELECT 查询中从 CTE 调用插入 *函数*
Calling an insert *function* from a CTE in a SELECT query in Postgres 13.4
我正在编写 运行 到 pg_cron
的实用程序代码,有时希望例程将一些结果插入 dba.event_log
处的自定义 table。我有一个基本日志 table 作为起点:
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 |
+----------------------------+------------------+---------------------------------------+
稍后我可能会丰富 table,现在我会将日志 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
的内容。有没有好的方法来做到这一点?查看文档并在此处搜索更多信息后,我对规则有了 位 的了解。但不完全是。如果我没看错,外部查询的数据修改 CTE 是 ruled/regulated。肯定有一些我没有掌握的微妙之处。我是否以某种方式更改上下文以将 INSERT
移动到一个函数中,从而使查询和 CTE 中的代码如何被解释?
https://www.postgresql.org/docs/13/queries-with.html#QUERIES-WITH-MODIFYING
您的函数需要 citext
类型的参数,但您传递的是 text
类型的值。您需要投射参数:
WITH values_cte AS (
select clock_timestamp() as ct
),log as (
select event_log_add('CTE event_log_add check'::citext,
('clock = ' || (select ct::text from values_cte))::citext)
)
select *
from log;
将参数定义为 text
可能更容易,在 INSERT 期间将自动完成转换:
CREATE FUNCTION event_log_add(
name_in text,
description_in text)
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 event_log_add('CTE event_log_add check',
'clock = ' || (select ct::text from values_cte))
)
select *
from log;
如果需要,可以在函数内添加显式强制转换。
我正在编写 运行 到 pg_cron
的实用程序代码,有时希望例程将一些结果插入 dba.event_log
处的自定义 table。我有一个基本日志 table 作为起点:
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 |
+----------------------------+------------------+---------------------------------------+
稍后我可能会丰富 table,现在我会将日志 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
的内容。有没有好的方法来做到这一点?查看文档并在此处搜索更多信息后,我对规则有了 位 的了解。但不完全是。如果我没看错,外部查询的数据修改 CTE 是 ruled/regulated。肯定有一些我没有掌握的微妙之处。我是否以某种方式更改上下文以将 INSERT
移动到一个函数中,从而使查询和 CTE 中的代码如何被解释?
https://www.postgresql.org/docs/13/queries-with.html#QUERIES-WITH-MODIFYING
您的函数需要 citext
类型的参数,但您传递的是 text
类型的值。您需要投射参数:
WITH values_cte AS (
select clock_timestamp() as ct
),log as (
select event_log_add('CTE event_log_add check'::citext,
('clock = ' || (select ct::text from values_cte))::citext)
)
select *
from log;
将参数定义为 text
可能更容易,在 INSERT 期间将自动完成转换:
CREATE FUNCTION event_log_add(
name_in text,
description_in text)
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 event_log_add('CTE event_log_add check',
'clock = ' || (select ct::text from values_cte))
)
select *
from log;
如果需要,可以在函数内添加显式强制转换。