質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

Q&A

解決済

3回答

3118閲覧

PostgreSQLのnow()とstatement_timestamp()の違いについて

new9

総合スコア19

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

0グッド

0クリップ

投稿2020/01/31 06:41

PostgreSQLのバージョンは、12.1で、Windows Server 2019で動かしています。

MySQLのON UPDATE CURRENT_TIMESTAMPと同様の動き(データをアップデートした日時を記録する)
をPostgreSQLでも実現させたく、ファンクションとトリガーを使って実現しようとしています。

以下のような仕組みを考えています。

・テーブルを作成

SQL

1CREATE TABLE aabbcc 2( 3 "id" integer DEFAULT nextval('aabbcc_id_seq'::regclass) NOT NULL, 4 "cd" character varying(9) NOT NULL, 5 "update_at" timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, 6 CONSTRAINT "aabbcc_pkey" PRIMARY KEY ("id") USING INDEX TABLESPACE "pg_default" 7) 8TABLESPACE "pg_default" 9;

・ファンクションを作成

SQL

1CREATE OR REPLACE FUNCTION fnc_update_at() 2 RETURNS trigger 3 LANGUAGE plpgsql 4AS $function$ 5 begin 6 new.update_at := 'now()'; 7 return new; 8 end; 9$function$ 10;

・トリガーを作成

SQL

1CREATE TRIGGER aabbcc_update_at 2BEFORE UPDATE 3ON aabbcc 4FOR EACH ROW 5EXECUTE PROCEDURE fnc_update_at() 6; 7

ファンクションの6行目が、「new.update_at := 'now()';」だとUPDATE時にupdate_atカラムが正しく更新されるのですが、
これだとトランザクションの開始日時になってしまうため、「new.update_at := 'statement_timestamp()';」
に変更して実行すると、データのアップデート時に以下のエラーになってしまいます。

ERROR:invalid input syntax for type timestamp with time zone:"statement_timestamp()"

now()もstatement_timestamp()も、戻り値の型はtimestamp with time zoneなので問題なく動くと
想定していましたが、エラーになってしまいました。

なぜエラーになってしまうのでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

amura

2020/01/31 07:47 編集

お答えになっていません(推測) now()はクォートで括る事が出来るようです、'now'でも行けます。 new.update_at := (select 'now'::timestamp); の動きと同じの様です。 nowだけ特別?? でもnow(),statement_timestamp()クォート取れば行けますけど
new9

2020/01/31 08:42

ありがとうございます。 ご指摘頂いた通り、クォートを外して 「new.update_at := clock_timestamp();」で正しく動きました。
sazi

2020/01/31 15:16

ここに回答と解決結果を書いても気付く人は少ないです。 ベストアンサーにでも、コメントとして書いておいた方が良いと思います。
guest

回答3

0

ベストアンサー

「PostgreSQLのnow()とstatement_timestamp()の違いに関して」のみ
begin;するとわかりますが、end;までの間

now() 変わらない transaction_timestamp() 変わらない当然 statement_timestamp() 変わる clock_timestamp() 変わる timeofday() 何故か変わる

があります。

マニュアルからすると

PostgreSQLでは利便性のために、下記に示されているような特別な日付/時刻入力値を サポートしています。 infinityと-infinityの値は、特別にシステム内部で表現され、 変更されずに表示されます。 他のものは、単に簡略化された表記で、 読み込まれるときに通常の日付/時刻値に変換されます。 (特にnowとその関連文字列は読み込まれるとすぐにその時点の値に変換されます。) epoch infinity -infinity now today tomorrow yesterday allballs

これらは’today()’でも動作しているので()までは見てないのでは?
'now' = 'now()' = 'now{}' = 'now$$'
利便性文字列の中で、nowだけ関数登録されていました、now()関数としても使えます。

投稿2020/01/31 07:54

編集2020/01/31 08:35
amura

総合スコア333

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

new9

2020/01/31 08:03

ありがとうございます。 私も実際に確認しました。 now()だと微妙に時間がずれていることがあったため、 実際にSQLを発行した時間に変更したいと思っております。
guest

0

PostgreSQL 11のドキュメントから:

statement_timestamp()は現在の文の実行開始時刻を返すものです(より具体的にいうと、直前のコマンドメッセージをクライアントから受け取った時刻です)。 statement_timestamp()およびtransaction_timestamp()はトランザクションの最初のコマンドでは同じ値を返しますが、その後に引き続くコマンドでは異なる可能性があります。

(あくまで想像でしかないですが)明示的に対話的コマンド実行において使えるものであって、トリガーのような非対話的コマンド実行では使えないってことでしょうか?
コマンド実行時点の日時であって、トリガー実行時点の日時ではない、っていう。

おなじく:

clock_timestamp()は実際の現在時刻を返しますので、その値は単一のSQLコマンドであっても異なります。

なので、使うならclock_timestamp()でしょうか。

投稿2020/01/31 07:21

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

new9

2020/01/31 08:01

ありがとうございます。 clock_timestamp()に変更して試してみましたが、 「ERROR:invalid input syntax for type timestamp with time zone:"clock_timestamp()"」 というエラーになってしまいました。
guest

0

9.9.4. 現在の日付/時刻

statement_timestamp()は現在の文の実行開始時刻を返すものです(より具体的にいうと、直前のコマンドメッセージをクライアントから受け取った時刻です)

内容からして、**statement_timestamp()**をトリガー内で使用するのは不適切だと思います。
clock_timestampを使用してみて下さい。

投稿2020/01/31 07:17

編集2020/01/31 15:17
sazi

総合スコア25195

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

new9

2020/01/31 08:01

ありがとうございます。 同じ回答で恐縮ですが、 「ERROR:invalid input syntax for type timestamp with time zone:"clock_timestamp()"」 というエラーになってしまいました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問