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

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

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

INSERTとは、行を追加する、コンピュータのデータベース言語SQLにおけるデータ操作言語(DML)ステートメントの1つである

PostgreSQL

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

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

Q&A

解決済

1回答

1939閲覧

PostgreSQLトリガーの履歴番号採番に関して

rei_rrrrr

総合スコア2

INSERT

INSERTとは、行を追加する、コンピュータのデータベース言語SQLにおけるデータ操作言語(DML)ステートメントの1つである

PostgreSQL

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

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

0グッド

0クリップ

投稿2021/12/10 09:37

PostgreSQLトリガーの履歴番号採番に関して

■質問内容

PostgreSQLのトリガー機能を使用し、履歴テーブルへinsertする際にインサートした日付を見て日付が同様の場合、同じ履歴番号を採番することは可能でしょうか。

履歴テーブルにマスタテーブルから履歴を書込む際の処理がうまくいかず、
何回かトリガーが更新される操作(画面上からマスタテーブルを書込むような)を行い、確認すると採番が合わない箇所が出てきており、困っております。
当方トリガーを用いて開発を行うことが初めてのため、何か解決策をお持ちの方は教えていただけると幸いです。(別の方法などもありましたらご教示頂けると幸いです)

■期待値の履歴テーブルデータ例

rireki_noにrireki_dateが同じ日付のものを同じ番号で採番したい

履歴テーブル

rireki_id rireki_no rireki_date 1 1 2021-12-10 13:45:00.544928 UPDATE 2 1 2021-12-10 13:45:00.544928 INSERT 3 1 2021-12-10 13:45:00.544928 INSERT 4 2 2021-12-10 13:45:35.682152 UPDATE 5 2 2021-12-10 13:45:35.682152 UPDATE 6 3 2021-12-10 14:34:42.002834 INSERT 7 3 2021-12-10 14:34:42.002834 DELETE

■試したこと(履歴テーブルへinsertする際のトリガ関数)

①履歴テーブルから最新日付を取得
②履歴テーブルから最大履歴番号を取得
③インサート時に履歴テーブルの最新日とCURRENT_TIMESTAMPで日付を比較し、
一致していたら最大履歴番号から-1(同時刻のものを同じ履歴番号として扱いたいため)
一致していなかったらそのまま最大履歴番号を挿入

create function insert_test_rireki() returns trigger as $insert_test_rireki$
DECLARE
-- 最新日付 ・・・①
latestTimeStamp timestamp without time zone := (SELECT MAX(rireki_date) FROM test_rirkei where id = NEW.id or id = OLD.id);
-- 最大rieki_no+1 ・・・②
maxRirekiNo INTEGER := (SELECT CASE WHEN max(group_no) is null THEN 1 ELSE max(rireki_no) + 1 END FROM test_rirkei whereid = NEW.id or id = OLD.id);

BEGIN ・・・③
INSERT INTO test_rirki(rireki_no,rireki_date,dml_status,........)
VALUES ( CASE WHEN latestTimeStamp = CURRENT_TIMESTAMP THEN maxRirekiNo -1 ELSE maxRirekiNo END,CURRENT_TIMESTAMP,TG_OP,........);
RETRUN NEW;
END;
・・・省略

■試した際の履歴テーブル結果

rireki_id rireki_no rireki_date 1 1 2021-12-10 13:45:00.544928 UPDATE 2 1 2021-12-10 13:45:00.544928 INSERT 3 1 2021-12-10 13:45:00.544928 INSERT 4 2 2021-12-10 13:45:35.682152 UPDATE 5 2 2021-12-10 13:45:35.682152 UPDATE 6 3 2021-12-10 14:34:42.002834 INSERT 7 3 2021-12-10 14:34:42.002834 DELETE 8 4 2021-12-10 14:38:04.488303 DELETE 9 4 2021-12-10 14:38:04.488303 INSERT 10 4 2021-12-10 14:44:11.494948 INSERT ←rireki_dateが異なるのに"5"で採番が行われない 11 4 2021-12-10 14:44:11.494948 INSERT ←rireki_dateが異なるのに"5"で採番が行われない

■トリガの設定

今回のデータ更新処理は、元のマスタデータが更新された後に履歴テーブルに書く処理を行いため、以下の設定にしております。
create trigger insert_test_rireki_trigger after insert or update or delete on mst_test for each row execute function insert_test_rireki();

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

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

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

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

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

guest

回答1

0

ベストアンサー

TIMESTAMP型には、秒よりも小さい単位の時刻成分も含まれているので、
正確に日付成分だけで比較したい場合には、
date_trunc('day', MAX(rireki_date))
みたいに加工しないと出ないかと思います。

秒未満の成分が不要であれば、timestamp型で宣言する際に精度0指定で
そもそも持たせないやり方もできるでしょうね。

アルゴリズムとしては、
最新日付が未来の値を取らないという前提が成り立つのであれば、
最新日付=今日の日付ということで、
WHERE date_trunc('day', rireki_date) = CURRENT_DATE
などとすれば、今日履歴テーブルに書き込みがあれば履歴番号ヒットするので、
簡素化できそうな気がします。

投稿2021/12/10 11:50

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

rei_rrrrr

2021/12/13 08:41

ご回答いただきありがとうございます。 >TIMESTAMP型には、秒よりも小さい単位の時刻成分も含まれているので、 >正確に日付成分だけで比較したい場合には、 >date_trunc('day', MAX(rireki_date)) >みたいに加工しないと出ないかと思います。 今回の履歴テーブルの仕様上、秒単位で履歴番号を振らないといけないためdate_trunc('second', MAX(rireki_date))の指定で試してみたのですが、やはりずれるときと成功するときがあり秒で比較するのは難しそうだなと思いました。 日付での比較でしたら、以下の取得方法で採番できそうだなと思いました。今回は別の方法で考えることにしようと思います。 >WHERE date_trunc('day', rireki_date) = CURRENT_DATE 丁寧なご回答いただきありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問