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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Oracle Database 10g

Oracle DatabaseはRDBMSの商品です。具体的な発売商品として知られているのが、 Oracle9i、Oracle10g、Oracle 11gとOracle 12cです。

PL/SQL

PL/SQL (Procedural Language/Structured Query Language) はOracle CorporationによるSQL(非手続き型言語)を手続き型言語に拡張させるために開発されたプログラミング言語です。

SQL

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

Q&A

解決済

2回答

13505閲覧

Oracle SQLにおいて最終値+1の値から連番を振りたい

hatsuk0i1216

総合スコア14

Oracle Database 10g

Oracle DatabaseはRDBMSの商品です。具体的な発売商品として知られているのが、 Oracle9i、Oracle10g、Oracle 11gとOracle 12cです。

PL/SQL

PL/SQL (Procedural Language/Structured Query Language) はOracle CorporationによるSQL(非手続き型言語)を手続き型言語に拡張させるために開発されたプログラミング言語です。

SQL

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

0グッド

0クリップ

投稿2018/08/21 03:57

SQLを軽く本で勉強しただけの初心者です。
簡単なSELECTとUPDATEならばできますが、WHILEやLOOPはなんとなとく意味がわかる程度で、コードを書いたことはありません。

【前提】
■keycode_masterという一つのテーブルを用意し、データが20万件程度入っている。
|メーカー名|品番|管理用コード|採番用|
|:--|:--:|--:|
|AAA|10001|AAA001|1|
|AAA|10002|AAA002|2|
|AAA|10003|AAA003|3|
|AAA|10004|AAA004|4|
|BBB|AB001|BBB001|1|
|BBB|AB002|BBB002|2|
|BBB|AB003|BBB003|3|
|CCC|10001|CCC001|1|

■採番については下記のルールで実施
・採番用のフィールドにはメーカー毎の連番を入力。
・管理用キーコードは採番用のフィールド+メーカー名で生成。

下記のSQLでできた。

MERGE INTO "keycode_master" u USING ( SELECT rowid AS rid, ROW_NUMBER() OVER (PARTITION BY メーカー名 ORDER BY 品番) AS rn FROM "keycode_master" ) ON (u.rowid = rid) WHEN MATCHED THEN  UPDATE  SET 採番用 = rn;       管理用キーコード = メーカー名 || lpad(rn,10,'0');

【わからないところ】
■商品追加時は他のマスター(main_master)と品番でマージさせ、
メーカー名と品番をkeycode_masterにINSERTさせている。
★その際に自動で採番用の値+1からNULLの分だけ、自動採番をさせたい。

下図だと、メーカー名AAAには5と6を
メーカー名CCCには2を入れたい

|メーカー名|品番|管理用コード|採番用|
|:--|:--:|--:|
|AAA|10001|AAA001|1|
|AAA|10002|AAA002|2|
|AAA|10003|AAA003|3|
|AAA|10004|AAA004|4|
|AAA|10005||
|AAA|10006||
|BBB|AB001|BBB001|1|
|BBB|AB002|BBB002|2|
|BBB|AB003|BBB003|3|
|CCC|10001|CCC001|1|
|CCC|10002||

【聞きたいこと】
どのようなロジックで組めばいいか、まったくわかりませんので、
考えられるパターンを教えてください。

組めるかはわかりませんが、考えられるロジックとしては、
メーカー名毎に最終の値と、NULLの値を取得して、
NULLの数だけ最終の値+1をしていくというループをしていく?
その場合は、CASEでメーカー名を指定する?

です。
よろしくお願いいたします。

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

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

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

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

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

guest

回答2

0

こういう感じですか?

sql

1update 2 keycode_master m 3set 4 order_no = (select count(*) + 1 from ( 5 select 6 * 7 from 8 keycode_master 9 ) t 10 where 11 maker_name = m.maker_name 12 and 13 prd_number < m.prd_number 14 ) 15where 16 order_no is null 17;

ちょっと手元にMySQLしかないのでOracleだったら以下でも通るかもしれません。

sql

1update 2 keycode_master m 3set 4 order_no = (select count(*) + 1 from keycode_master 5 where 6 maker_name = m.maker_name 7 and 8 prd_number < m.prd_number 9 ) 10where 11 order_no is null 12;

投稿2018/08/21 11:02

denzow

総合スコア640

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

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

hatsuk0i1216

2018/08/22 01:49

ご回答ありがとうございます。 想像通りの採番ができました! 一点不明なのは、prd_number < m.prd_numberの不等号なのですが、 prd_numberは品番の列のことをさしていますよね? 品番は数値だけだったり、小数点もあったり、英語+数字だったり、バラバラなんですが、 それでも不等号で実行できて、連番がふれたのがよく理解できません、、、
sazi

2018/08/22 03:49

部品に欠番が無いなら大丈夫ですけど、あるなら駄目ですね。
denzow

2018/08/22 05:15

sazi様がおっしゃるように採番用列が欠番してない前提ですね。 prd_numberは文字列の場合、辞書順なので同じメーカ内でprd_numberが辞書順でみて 大きくなるのであれば大丈夫です。 自身の行よりも若い行の数を取得して、それの+1を採番するというSQLでした。
guest

0

ベストアンサー

SQLクエリで実施する方法を回答します。

質問文には書いていないですが、メーカー名と品番を主キーとしますね。
最終的な目標は以下のようになると考えます。

メーカー名品番管理用コード採番
AAA100055
AAA100066
CCC100022

まず、元の表から、更新前の採番値の最大値を列に連結するクエリを作ります。
max() over (partition by 条件)で作れます。

sql

1select 2 maker_name 3 ,hinban 4 ,kanri_code 5 ,saiban 6 ,max(saiban) over (partition by maker_name) max_saiban 7from keycode_master tbl1 8order by maker_name, hinban 9; 10 11MAK HINBA KANRI_ SAIBAN MAX_SAIBAN 12--- ----- ------ ---------- ---------- 13AAA 10001 AAA001 1 4 14AAA 10002 AAA002 2 4 15AAA 10003 AAA003 3 4 16AAA 10004 AAA004 4 4 17AAA 10005 4 18AAA 10006 4 19BBB AB001 BBB001 1 3 20BBB AB002 BBB002 2 3 21BBB AB003 BBB003 3 3 22CCC 10001 CCC001 1 1 23CCC 10002 1 24 2511行が選択されました。

MAX_SAIBAN に各メーカーごとの現時点での最大値が出てきました。

次に、この表を基に採番がNULLのレコードに対し、row_numberを最大値に加えたNEW_SAIBAN列を作成します。

sql

1with sub1 as ( 2select 3 maker_name 4 ,hinban 5 ,kanri_code 6 ,saiban 7 ,max(saiban) over (partition by maker_name) max_saiban 8from keycode_master tbl1 9order by maker_name, hinban 10) 11select 12 maker_name 13 ,hinban 14 ,kanri_code 15 ,saiban 16 ,row_number() over (partition by maker_name order by maker_name, hinban) row_num_by_maker 17 ,max_saiban + row_number() over (partition by maker_name order by maker_name, hinban) new_saiban 18from sub1 19 where sub1.saiban is null 20 ; 21 22 23MAK HINBA KANRI_ SAIBAN ROW_NUM_BY_MAKER NEW_SAIBAN 24--- ----- ------ ---------- ---------------- ---------- 25AAA 10005 1 5 26AAA 10006 2 6 27CCC 10002 1 2

withで作った一時表のsub1は上のクエリと同一です。

最後に、この表とメーカー名、品番を連結してNEW_SAIBANを元表のSAIBANに更新するUPDATE文を作成します。

sql

1update keycode_master upd 2set saiban = ( 3 with sub1 as ( 4 select 5 maker_name 6 ,hinban 7 ,kanri_code 8 ,saiban 9 ,max(saiban) over (partition by maker_name) max_saiban 10 from keycode_master tbl1 11 order by maker_name, hinban 12 ),sub2 as ( 13 select 14 maker_name 15 ,hinban 16 ,kanri_code 17 ,saiban 18 ,max_saiban + row_number() over (partition by maker_name order by maker_name, hinban) new_saiban 19 from sub1 20 where saiban is null 21 ) 22 select 23 new_saiban 24 from sub2 25 where upd.maker_name = sub2.maker_name 26 and upd.hinban = sub2.hinban 27 and sub2.saiban is null 28 ) 29where saiban is null 30;

最後に全体をSELECTしてみましょう。

sql

1select * from keycode_master; 2 3MAK HINBA KANRI_ SAIBAN 4--- ----- ------ ---------- 5AAA 10001 AAA001 1 6AAA 10002 AAA002 2 7AAA 10003 AAA003 3 8AAA 10004 AAA004 4 9AAA 10005 5 10AAA 10006 6 11BBB AB001 BBB001 1 12BBB AB002 BBB002 2 13BBB AB003 BBB003 3 14CCC 10001 CCC001 1 15CCC 10002 2 16 1711行が選択されました。

以上のような手順で、作りたいデータを順番に生成していくとそんなに難しくないよ!ということです。


まあPL/SQLでループ回して書いたほうが遥かに簡単なんですけどね。

投稿2018/08/21 10:55

hope_mucci

総合スコア4447

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

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

hatsuk0i1216

2018/08/22 01:40

ご回答ありがとうございました! 無事に思い描いた通りの値を得ることができました。 またわかりやすく経過まで書いていただき、理解を深めることができました。 WITH句についてはまったく触れたことがなかったのですが、 まずは最大値を取得してその後最大値+NULLの行数を取得してSETするというロジックということは理解できました。
sazi

2018/08/22 03:49 編集

部品に欠番が無いなら大丈夫ですけど、あるなら駄目ですね。 あ、こっちじゃなかった、すみません。(汗)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問