6

昨天我们有一个 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 函数“getwebregistrarpatient_withdeletes”第 3 行,位于 RETURN QUERY [SQL 状态 = 42804 ]

该列nfa.patient_id_number是文本,并且正在为该列转换patient_id_number为. 在阅读了一些内容后,我认为问题在于从文本转换时未指定列长度。但问题是我尝试了各种子字符串组合来解决这个问题,但没有一个能解决问题:patient_for_registrarvarchar(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)),

有没有人有任何指示?

4

1 回答 1

16

你的功能..

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无法做到的任何事情。如果我需要长度限制,我会使用一个列约束,它可以在不重写整个表的情况下进行更改。

于 2012-05-25T17:23:23.137 回答