1

在 Postgres 数据库中导入数据后,我运行一个函数来规范化来自 ODBC 源的一些数据。一个字段是日期,但它以 varchar 形式出现,对于某些行,它为空,因此当我尝试将其转换为日期类型时,它会失败。我意识到这并不重要,因为数据仅用于显示,但我需要它采用有用的格式,所以我找到了以下 SQL:

UPDATE "MyTable" SET "VisitDate" =  to_char( DATE("VisitDate"), 'DD Mon YYYY' )  WHERE "VisitDate" <> '';

如果我直接在 SQL 浏览器中运行它,这会起作用,但是当我执行该函数时,它会说:

ERROR:  table row type and query-specified row type do not match
DETAIL:  Table has type character varying at ordinal position 6, but query expects text.

据我所知,这是因为该to_char()函数返回文本,但该字段是一个 varchar (并且考虑到它的内容是合乎逻辑的)所以我想也许我可以执行以下操作:

ALTER TABLE "MyTable" ALTER "VisitDate" TYPE "text";
UPDATE "MyTable" SET "VisitDate" =  to_char( DATE("VisitDate"), 'DD Mon YYYY' )  WHERE "VisitDate" <> '';
ALTER TABLE "MyTable" ALTER "VisitDate" TYPE varchar(12);

当然,这在函数中不起作用,因为-据我所知-Postgres 在单个事务中运行整个事物,因此在 UPDATE 之前不会发生 ALTER 指令,因此会出现相同的错误。

如果我尝试使用varchar( to_char( ...etc ))它只会抱怨 varchar 函数的内容。

在下面的评论之后,我尝试在函数中仅包含该行并且它成功,如果我在函数中有所有表更改语句它成功,如果我有两个它失败。该函数的基本形式是这样的:

CREATE OR REPLACE FUNCTION at_ebc_alterscorescolumns() RETURNS void AS
$BODY$
ALTER TABLE "MyTable" ALTER "Postcode" TYPE varchar(10);
UPDATE "MyTable" SET "VisitDate" =  to_char( DATE("VisitDate"), 'DD Mon YYYY' )  WHERE "VisitDate" <> '';
$BODY$
LANGUAGE sql VOLATILE
COST 100;

这让我想知道是否仅仅是不可能在单个函数中更改表和更改数据的情况。

我的问题是:如何更改字段的格式而不导致此错误?

4

1 回答 1

2

执行此操作时,我可以看到 PG 8.4 的错误:

create table foo(somedate text);

create function alter_foo() returns void as
$$
alter table foo alter somedate type varchar(10);
update foo set somedate = to_char(date(somedate),'DD Mon YYYY' );
$$
language sql;

select alter_foo();

函数调用失败并显示以下消息:

错误:表行类型和查询指定的行类型不匹配详细信息:表的类型字符在序号位置 1 处变化,但查询需要文本。上下文:SQL 函数“alter_foo”语句 2

简单的解决方法是选择plpgsql语言而不是sql语言。前者是程序性的,而后者更适合单行和自动内联候选的东西。我猜想sql语言处理器以某种方式预先解析查询,如果在函数执行期间更改数据类型,它会感到困惑。

无论如何,如果你这样声明:

create function alter_foo() returns void as
$$
 begin
   alter table foo alter somedate type varchar(10);
   update foo set somedate = to_char(date(somedate),'DD Mon YYYY' );
 end;
$$ language plpgsql;

然后它似乎按预期工作。

于 2012-05-09T14:16:20.880 回答