Cast 产生“返回的类型字符变化与预期的类型字符变化不匹配(8)”

问题描述 投票:0回答:2

昨天我们将 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)),

有没有人指点一下?

database postgresql types plpgsql varchar
2个回答
17
投票

你的功能..

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
类型无法做到的任何事情。如果我需要长度限制,我可以使用列约束,可以更改该约束而无需重写整个表。


0
投票

我创建了

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)
© www.soinside.com 2019 - 2024. All rights reserved.