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

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

新規登録して質問してみよう
ただいま回答率
85.49%
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

2回答

1598閲覧

RULEで日内連番を振りたい

heart_crimson

総合スコア15

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クリップ

投稿2019/08/21 10:38

編集2019/08/21 10:39

前提・実現したいこと

こちらの質問の続きです。
前回の質問の経緯を簡単にご説明しますと、
DBにアイテムテーブルmst_itemと、アイテムが入庫された時に書き込まれるトランザクションtrn_item_lot_infoがあります。
上記二つのテーブル・トランザクションをjoinし、ビューview_item_resultを作成しました。
そのviewに日内連番・連携したかどうかのbooleanを持たせたいという質問です。

結局は
view専用のテーブルtmp_item_lot_infoを作成、tmp_item_lot_infoにinsertするルールrule_trn_item_lot_info_insertをtrn_item_lot_infoに作成する

アイテムが入庫される(=trn_item_lot_infoにinsertされる)

insertでruleに基づき、tmp_item_lot_infoにデータがinsertされる

tmp_item_lot_infoをselectしているviewに反映される
という流れに落ち着きました。

発生している問題・エラーメッセージ

プログラムからtrn_item_lot_infoにデータを複数insert(トランザクションでまとめている)する場合があります。
その際、tmp_item_lot_infoに複数データがinsertされてしまうと日内連番が同じになってしまうようです。
1つだけinsertされると特に問題ありません。
この連携は専用の機能なので、できればプログラム(VB.NET)を触らずにSQLだけで解決したいです。

該当のソースコード

mst_item

[PK]item_id(serial)item_code(varchar(20))item_name(varchar(128))
1ITEM001アイテム①
2ITEM002アイテム②
3ITEM003アイテム③

trn_item_lot_info

[PK]item_id(integer)[PK]lot_number(varchar(20))quantity(numeric(16,6))shelf_life(date)
120190808011.0000002020-08-08
220190808012.0000002020-01-01
1201908090110.0000002020-08-09

trn_item_lot_info.rule_trn_item_lot_info_insert

SQL

1CREATE OR REPLACE RULE rule_trn_item_lot_info_insert AS 2 ON INSERT TO trn_item_lot_info DO INSERT INTO tmp_item_lot_info (item_code, quantity, lot_number, shelf_life, seq_in_date, is_coordinated, insert_timestamp) 3 VALUES (( SELECT mst_item.item_code 4 FROM mst_item 5 WHERE mst_preparation.preparation_id = new.preparation_id), 6 new.quantity, 7 new.lot_number, 8 new.shelf_life, 9 CASE 10 WHEN (( SELECT max(tmp_item_lot_info.seq_in_date) AS max 11 FROM tmp_item_lot_info 12 WHERE tmp_item_lot_info.insert_timestamp::date = CURRENT_DATE 13 GROUP BY tmp_item_lot_info.insert_timestamp::date)) IS NULL THEN 1 14 ELSE (( SELECT max(tmp_item_lot_info.seq_in_date) AS max 15 FROM tmp_item_lot_info 16 WHERE tmp_item_lot_info.insert_timestamp::date = CURRENT_DATE 17 GROUP BY tmp_item_lot_info.insert_timestamp::date)) + 1 18 END, -- ここの書き方が悪いのだと思います。 19 FALSE, 20 CURRENT_TIMESTAMP 21 );

tmp_item_lot_info
|item_code(varchar(20))|quantity(numeric(16,6))|lot_number(varchar(20))|shelf_life(date)|seq_in_date(integer)|is_coordinated(boolean)|[PK]insert_timestamp|
|:--|:--|:--|:--|:--|:--|
|ITEM001|1.000000|2019080801|2020-08-08|1|false|2019-08-08 08:00:00.000000|
|ITEM002|2.000000|2019080801|2020-01-01|2|false|2019-08-08 12:00:00.000000|
|ITEM001|10.000000|2019080901|2019-08-09|1|false|2019-08-09 08:00:00.000000|

試したこと

MAXではなくCOUNTを使用してみたのですが同様にダメでした。
ruleでinsertされるデータだけトランザクション無しに出来ればいいのかなと思うのですが。

補足情報(FW/ツールのバージョンなど)

PostgreSQL 9.3

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

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

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

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

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

guest

回答2

0

テーブルtrn_item_lot_infoに項目seq_in_dateを追加しているので☓ですかね。
外部から日内連番をRULEに渡すためです。

sql

1CREATE OR REPLACE RULE rule_trn_item_lot_info_insert AS 2 ON INSERT TO trn_item_lot_info 3 DO INSTEAD INSERT INTO tmp_item_lot_info (item_code, quantity, lot_number, shelf_life, seq_in_date, is_coordinated, insert_timestamp) 4 VALUES ((SELECT item_code FROM mst_item WHERE item_id=new.item_id), 5 new.quantity, 6 new.lot_number, 7 new.shelf_life, 8 COALESCE((SELECT max(seq_in_date) from tmp_item_lot_info WHERE shelf_life=new.shelf_life),0) + new.seq_in_date, 9 FALSE, 10 CURRENT_TIMESTAMP) 11 ; 12 13INSERT INTO trn_item_lot_info (item_id, quantity,lot_number,shelf_life,seq_in_date) 14SELECT 15 mst_item.item_id AS item_id, 16 trn_item_lot_info.quantity AS quantity, 17 trn_item_lot_info.lot_number AS lot_number, 18 shelf_life, 19 ROW_NUMBER() OVER (PARTITION BY shelf_life) 20 FROM trn_item_lot_info 21 LEFT JOIN mst_item USING (item_id) 22 ORDER BY trn_item_lot_info.item_id, trn_item_lot_info.shelf_life 23;

投稿2020/01/06 11:20

amura

総合スコア333

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

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

0

同一のトランザクション内なので、max()やcount()では無理でしょうね。

シーケンスならトランザクションと関係なく処理されるので使えそうですけど、連番にするためには、insert前にそのシーケンスをリセットする必要があるでしょうね。

投稿2019/08/21 12:18

sazi

総合スコア25173

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

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

heart_crimson

2019/08/21 12:39

回答ありがとうございます。 おっしゃる通り、シーケンスですと日内の連番にならないため採用しておりません。 「1つのrule内に複数SQLを含めること」と「tmp_item_lot_info.insert_timestampの最大値<本日だった場合シーケンスをリセット(1スタート)にすること」が出来れば採用できそうです。少し調べてみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問