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

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

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

Oracle Databaseは、米オラクルが開発・販売を行うリレーショナルデータベース管理システムです。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

SQL

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

Q&A

解決済

3回答

812閲覧

深さの決まっていない親子関係のデータを上手く取得する方法が知りたい

onakahetta

総合スコア23

Oracle Database

Oracle Databaseは、米オラクルが開発・販売を行うリレーショナルデータベース管理システムです。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

SQL

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

0グッド

1クリップ

投稿2022/12/01 02:48

編集2022/12/01 12:02

前提

まず例として、企業の合併情報を管理している下記のようなテーブルがあるとします。

イメージ説明

現時点で一番親の会社はA社ですが、このA社の情報を取得する際に紐づくすべての子会社の情報も取ってきたいです。
(A社の直属の子会社であるB社、C社だけでなくB社の子会社、その下のE社の子会社も取りたい)

上記の子会社情報を階層のない1つのリストするのが最終目標です。

現状

最初はA社の直属とその下(B社の子会社)まで取ってくる仕様でしたので、今の実装では
合併明細テーブルにAAAで検索をかけて取得したリストをループ→その中で更に合併明細にBBB、CCCで検索かけてリストに追加
という形で一度だけループをしています。

知りたいこと

親子関係の階層がどれくらいの深さになるかが分からないためループで取得するのは非現実的かと思っているのですが、
調べてもなかなかいい方法が出てこず困っています。
JavaでもSQLでも構いませんので何かアドバイスをいただけたら幸いです。
言葉足らずな部分ありましたら補足しますのでコメントください。よろしくお願い致します。

解決後追記

以下、ベストアンサーを参考に組んだSQLです。

SQL

1with temp (親会社ID, 子会社ID, lvl) as ( 2 select 親会社ID, 子会社ID, 1 from 合併明細テーブル 3 where 親会社ID = 'AAA' 4 union all 5 select G.親会社ID, G.子会社ID, T.lvl+1 from 合併明細テーブル G, temp T 6 where G.親会社ID = T.子会社ID 7) search breadth first by 子会社ID set order1 8select 親会社ID, 子会社ID, lvl from temp;

取得結果
イメージ説明

ご協力いただいた皆様ありがとうございました。

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

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

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

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

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

onakahetta

2022/12/01 03:02

ありがとうございます。階層問い合わせについて知らなかったので勉強します。
68user

2022/12/01 05:42

ああ、Oracle にそういう機能があるんですね。ではこっちの方がいいですね。失礼しました。
guest

回答3

0

ベストアンサー

合併明細テーブルはツリー構造なので、再帰を使用すれば取得できると思います。
図でイメージするOracle DatabaseのSQL全集 第7回 再帰with句
津島博士のパフォーマンス講座 第31回 再帰的問合せについて

投稿2022/12/01 10:27

sazi

総合スコア25206

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

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

onakahetta

2022/12/01 11:46

階層問い合わせとはまた別に再起問い合わせというものがあるんですね。 記載いただいた記事を参考にして、まさに欲しかったデータを取得することができました! 本当にありがとうございます。
guest

0

一応 java も。普通になぞっているだけですが。

java

1import java.util.*; 2 3public class Main { 4 public static void main(String[] args) throws Exception { 5 List<Entry> 合併明細 = new ArrayList<>(); 6 合併明細.add(new Entry("AAA", "BBB")); 7 合併明細.add(new Entry("AAA", "CCC")); 8 合併明細.add(new Entry("BBB", "DDD")); 9 合併明細.add(new Entry("BBB", "EEE")); 10 合併明細.add(new Entry("EEE", "FFF")); 11 合併明細.add(new Entry("EEE", "GGG")); 12 13 List<String> 結果 = new ArrayList<>(); 14 結果.add("AAA"); 15 for(int i=0; i<結果.size(); i++) { 16 for(Entry entry : 合併明細) { 17 if(entry.親会社ID.equals(結果.get(i)) && !結果.contains(entry.子会社ID)) { 18 結果.add(entry.子会社ID); 19 } 20 } 21 } 22 System.out.println("" + 結果); 23 } 24 private static class Entry { 25 final String 親会社ID; 26 final String 子会社ID; 27 Entry(String 親会社ID, String 子会社ID) { 28 this.親会社ID = 親会社ID; 29 this.子会社ID = 子会社ID; 30 } 31 } 32}

plain

1[AAA, BBB, CCC, DDD, EEE, FFF, GGG]

(paiza.io で作成・実行)

投稿2022/12/01 18:10

jimbe

総合スコア12696

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

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

0

階層数が一定でないツリー構造を一発の SQL で取るのは難しいです。
ご参考:
https://www.wantedly.com/companies/autoro/post_articles/299434
https://bbh.bz/2020/07/18/tree-structure-in-rdb/

そもそもデータ構造がよくない気がします。子会社をフラットにもったテーブルを作り、会社情報変動時にレコード再作成してはどうでしょうか。

本題と関係ないですが、下記が気になりました。
・「合併」したのに「親会社」「子会社」という関係性が出てくるのがしっくりこない
・あるタイミングの合併において、どの会社と合併したのかという情報が見えなくなっている。そもそも「合併ID」があるべきでは。

投稿2022/12/01 03:11

68user

総合スコア2005

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

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

onakahetta

2022/12/01 03:50

ありがとうございます。 合併したら新しい会社ができて合併元の会社と親子関係になる、という動きをするので親会社・子会社という表現を使いました。あくまで例えなので、一般的な企業間の合併とは少し感じが違うかもしれないです。かえって分かりづらくしてしまいすみません。 データ構造は他機能との兼ね合いもあり今から変えるのが難しく...ビューを使用すれば実現できるでしょうか?
68user

2022/12/01 05:38 編集

実際のデータがツリー構造であるべき or 現状そうなっているのは仕方がないというならそれはそれでよくて、であるなら 1回のSQLでは取れないので  ・SELECT 時に頑張る (階層分SELECTを続けるとか、SELF JOIN 5回おこなって 5階層までは取得できるがまだ深いデータがあるなら再度 SELECT するなど)  ・SELECT 時に頑張らなくてよいよう INSERT/UPDATE 時に親子関係情報をふまえたキャッシュテーブル的なものを作っておく (全件メモリやRedis上に持っておくとか、最上位会社IDと子会社ID のマッピングテーブルを作っておくとか) のどちらかではないでしょうか。 どちらで頑張るかは SELECT と、INSERT/UPDATE の頻度やデータ件数によるのではと思います。
onakahetta

2022/12/01 08:56

具体的に方法を示していただきありがとうございます。とても参考になります。 回答に記載くださった記事も読みましたがそもそものデータ構造がこういうデータの取得に向いていないかもしれない、という発想は自分にはなかったので勉強になりました。 コメントにいただいていた階層問い合わせも含め、検討しようと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問