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

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

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

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

Java

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

SQL

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

Q&A

解決済

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

onakahetta
onakahetta

総合スコア23

Oracle Database

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

Java

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

SQL

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

3回答

0グッド

1クリップ

300閲覧

投稿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;

取得結果
イメージ説明

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

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

onakahetta

2022/12/01 03:02

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

2022/12/01 05:42

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

回答3

1

ベストアンサー

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

投稿2022/12/01 10:27

sazi

総合スコア24573

KOZ6.0👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

onakahetta

2022/12/01 11:46

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

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

総合スコア10817

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

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

総合スコア1720

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

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

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

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

ただいまの回答率
86.02%

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

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

質問する

関連した質問

同じタグがついた質問を見る

Oracle Database

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

Java

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

SQL

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