昨天我们将 PostgreSQL 数据库升级到了 9.1.3 版本。我们以为我们已经测试并准备好了一切,但我们错过了一个功能。它返回一个像这样的表类型:
CREATE OR REPLACE FUNCTION myfunc(
patient_number varchar,
tumor_number_param varchar,
facility_number varchar
)
RETURNS SETOF patient_for_registrar
LANGUAGE plpgsql
AS
$body$
BEGIN
RETURN QUERY
SELECT cast(nfa.patient_id_number as varchar),
...
我只给出选择的第一列,因为那是错误发生的地方。今天之前这个函数运行得很好,但是现在它给出了这个错误:
错误:查询结构与函数结果类型不匹配
详细信息:返回的类型字符变化与预期类型不匹配 第 1 列中的字符变化(8)。其中:PL/pgSQL 函数 “getwebregistrar Patient_withdeletes”第 3 行位于 RETURN QUERY [SQL 状态=42804]
列
nfa.patient_id_number
是文本,正在为 patient_id_number
中的列 patient_for_registrar
进行转换,即 varchar(8)
。在阅读了一些内容后,我认为问题是因为从文本进行转换时未指定列长度。但问题是我已经尝试了各种子字符串组合来解决这个问题,但没有一个能解决问题:
substring(cast(nfa.patient_id_number as varchar) from 1 for 8),
cast(substring(nfa.patient_id_number from 1 for 8) as varchar),
cast(substring(nfa.patient_id_number from 1 for 8) as varchar(8)),
有没有人指点一下?
你的功能..
RETURNS SETOF patient_for_registrar
返回的行类型必须与声明的类型完全匹配。您没有透露
patient_for_registrar
的定义,可能是表的关联复合类型。我引用关于复合类型声明的手册:
每当你创建一个表时,复合类型也会自动生成 创建的,与表同名,代表表的行 类型。
如果定义了该类型(表)的第一列
varchar(8)
(带有长度修饰符) - 如错误消息所示,您必须返回带有相同长度修饰符的 varchar(8)
; varchar
不行。字符串长度是否只有 8 个字符并不重要,数据类型必须匹配。
varchar
、varchar(n)
和 varchar(m)
是 PostgreSQL 不同的数据类型。
旧版本没有强制执行类型修饰符,但是使用 PostgreSQL 9.0,这已针对 plpgsql 进行了更改:
PL/pgSQL 现在需要复合结果列来匹配 预期类型修饰符以及基本类型(Pavel Stehule、Tom Lane)
例如,如果结果类型的列被声明为 NUMERIC(30,2),不再接受返回某些值的 NUMERIC 该列中的其他精度。以前的版本忽略了检查 类型修饰符,因此允许未包含的结果行 实际上符合声明的限制。
您可以转换返回的值以匹配
patient_for_registrar
的定义:
nfa.patient_id_number::varchar(8)
或者您可以更改
RETURNS
子句。我会使用 RETURNS TABLE
并声明一个匹配的复合类型。这是一个示例。
RETURNS TABLE (patient_for_registrar varchar, col2 some_type, ...)
顺便说一句:如果可以避免的话,我从不使用
varchar
——尤其是不使用长度修饰符。它几乎提供了 text
类型无法做到的任何事情。如果我需要长度限制,我可以使用列约束,可以更改该约束而无需重写整个表。
我创建了
person
表,如下所示:
CREATE TABLE person (
id INTEGER,
name VARCHAR(20),
age INTEGER
);
然后,我创建了
my_func()
,它返回记录ROW(1,'John'::VARCHAR,27)
,如下所示:
CREATE FUNCTION my_func() RETURNS trigger
AS $$
BEGIN
RETURN ROW(1,'John'::VARCHAR,27);
END; -- ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
$$ LANGUAGE plpgsql;
然后,我创建了
my_t
触发器,如下所示:
CREATE TRIGGER my_t BEFORE INSERT OR UPDATE OR DELETE ON person
FOR EACH ROW EXECUTE FUNCTION my_func();
最后,向
person
表插入一行得到了同样的错误,如下所示:
postgres=# INSERT INTO person (id, name, age) VALUES (NULL, NULL, NULL);
ERROR: returned row structure does not match the structure of the triggering table
DETAIL: Returned type character varying does not match expected type character varying(20) in co
lumn 2.
CONTEXT: PL/pgSQL function my_func() during function exit```
所以,我将
::VARCHAR
替换为::VARCHAR(20)
,如下所示:
CREATE FUNCTION my_func() RETURNS trigger
AS $$
BEGIN
RETURN ROW(1,'John'::VARCHAR(20),27);
END; -- ↑ ↑ ↑ ↑ ↑ ↑ ↑
$$ LANGUAGE plpgsql;
然后,我可以向
person
表插入一行,不会出现错误,如下所示:
postgres=# INSERT INTO person (id, name, age) VALUES (NULL, NULL, NULL);
INSERT 0 1
postgres=# SELECT * FROM person;
id | name | age
----+------+-----
1 | John | 27
(1 row)