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

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

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

Oracleは、米オラクルが取り扱うリレーショナルデータベース管理システムです。メインフレームからPCまで、多様なプラットフォームに対応しています。

SQL

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

Q&A

3回答

3225閲覧

oracle sql 1つのフィールドに文字列としてデータが登録されてしまっている場合のSELECT文について

nonono33021

総合スコア0

Oracle

Oracleは、米オラクルが取り扱うリレーショナルデータベース管理システムです。メインフレームからPCまで、多様なプラットフォームに対応しています。

SQL

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

0グッド

0クリップ

投稿2021/02/18 11:57

編集2021/02/18 16:10

以下のようなテーブルがあります。
表1は年度と型番をで部品IDを一意に特定できます
表2は年度と部品IDで部品名称を一意に特定できます
しかし表1の作りがよくなく
部品IDの1つのカラムにスペース区切りで文字列部品IDをまとめて登録しています。
2019年度の製品「AB01」部品ID「A1」部品名称「ヒューズ」
2019年度の製品「AB02」部品ID「A2」部品名称「ボルト」
2020年度の製品「AB01」部品ID「A1」部品名称「改良ヒューズ」

このようなSQL結果を得たいのですが方法が思いつきません。
表1の部品IDを分割して表1をきれいにする方法がいいと思ったのですが
なにかいい案はないでしょうか
部品は年度と部品で引っ張られるので型番が異なっても
同じ部品を使用しています。

表1の部品IDには30個以上の文字列がスペース区切りで連結されています。
レコードはどちらも1万以上
なのでfor文を回す必要があると思うのですが。。。。
全然思いつきません。

案だけでもいいのでご回答お待ちしております。

データ構造例

表1
年度 |製品型番 |部品ID
2019 AB01     A1 A2 A3 A4 A5  ←文字列
2019 AB02    A1 A2 A3 A4 A5
2020 AB01    A1 A2 A3 B1 B2
2020 AB02 A1 A2 A3 B1 B2

表2
年度 |部品ID |部品名称
2019 A1 ヒューズ
2019 A2    ボルト
.
.
2020 A1    改良ヒューズ

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

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

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

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

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

Orlofsky

2021/02/18 12:36

[DB2]タグは必要ですか?OracleとDB2はかなり違いますから、不要なら削ってください。
guest

回答3

0

表1が以下のように定義されているとします。

SQL

1CREATE TABLE t ( 2 year INT, 3 model VARCHAR(100), 4 id VARCHAR(100) 5); 6 7INSERT INTO t VALUES 8 (2019, 'AB01', 'A1'), 9 (2019, 'AB02', 'A1 A2'), 10 (2020, 'AB01', 'A1 A2 A3'), 11 (2020, 'AB02', 'A1 A2 A3 A4');

Oracleのバージョンにもよりますが、共通表式による再帰SQLがサポートされているなら、たとえば以下のようなSQLで正規化することはできます。

SQL

1WITH RECURSIVE r ( 2 year, 3 model, 4 depth, 5 pos, 6 id, 7 rest 8) AS ( 9 SELECT 10 year, 11 model, 12 0, 13 INSTR(id, ' '), 14 id, 15 id 16 FROM t 17 UNION ALL 18 SELECT 19 year, 20 model, 21 depth + 1, 22 INSTR(rest, ' '), 23 CASE WHEN pos = 0 THEN rest ELSE SUBSTR(rest, 1, pos - 1) END, 24 CASE WHEN pos = 0 THEN '' ELSE SUBSTR(rest, pos + 1) END 25 FROM r 26 WHERE rest <> '' 27) 28SELECT 29 year, 30 model, 31 id 32FROM r 33WHERE depth > 0

この実行結果は以下のようになるはずです。あとは表2とJOINなどすればよいかと思います。

yearmodelid
2019AB01A1
2019AB02A1
2019AB02A2
2020AB01A1
2020AB01A2
2020AB01A3
2020AB02A1
2020AB02A2
2020AB02A3
2020AB02A4

投稿2021/02/19 01:45

neko_the_shadow

総合スコア2349

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

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

0

表1の部品IDを分割して表1をきれいにする方法がいいと思ったのですが、なにかいい案はないでしょうか

部品IDを区切られた空白で分割しそれぞれをunionすれば良さそうです。
oracleにはsplit()のような分割して取り出すような関数はないので、自作関数などを流用して使えば楽できます。
文字列からトークンを切り出す
上記を使用すると、

SQL

1select 年度, 製品型番 , strtoken(部品ID, ' ', 1) 部品ID from1 where strtoken(部品ID, ' ', 1) is not null 2union all 3select 年度, 製品型番 , strtoken(部品ID, ' ', 2) from1 where strtoken(部品ID, ' ', 2) is not null 4union all 56

上記を元にcreate table xxx as selectでテーブルを作成して加工すれば良いかと。

投稿2021/02/18 17:55

編集2021/02/18 18:01
sazi

総合スコア25327

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

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

0

部品IDの1つのカラムにスペース区切りで文字列部品IDをまとめて登録しています。

正規化 に沿って設計します。通常第3正規化まで行います。
正規化を無視しているのが無駄にコードを複雑にしなければならい原因です。
今回は第1正規化を無視しています。

SQLだけでは部品IDを分割できないので、LOOPが使えるPL/SQLなどで部品IDの長さ分のLENGTHSUBSTR で個々の部品IDを抜き出して、表2をSELECTする条件にします。
INSTR も使うかも?

わたしなら、どんなに影響が大きくても間違ったテーブル設計を直させます。

投稿2021/02/18 12:35

Orlofsky

総合スコア16417

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問