1

Postgresデータベースにデータをインポートした後、ODBCソースから入ってくるデータの一部を正規化する関数を実行します。1つのフィールドは日付ですが、varcharとして入力され、一部の行ではnullであるため、日付型に変換しようとすると失敗します。データは表示にのみ使用されるため、それほど重要ではないことに気付きましたが、有用な形式である必要があるため、次の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

これを行うと、PG8.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 に答える