階層データのあるテーブルで親から最下層の子までのパスを列挙するクエリ

このQ&Aのポイント
  • 最上位の親から最下層の子までのパスを列挙するSQLクエリで親子関係のデータが自動的に作成されるシステムの問題を解決したい。
  • テーブル構造は直属の親と子を1レコードで保存しており、最上位の親のIDは0であり、それ以外の親のIDは1以上である。
  • 提供されたSQLクエリではパスの列挙はできるが、名前の表示が最上位の親だけであり、クエリの改善方法を求める。
回答を見る
  • ベストアンサー

階層データのあるテーブルで親から最下層の子までのパスを列挙するクエリ

階層データのあるテーブルで親から最下層の子までのパスを列挙するクエリ すでに存在するシステムより親子関係のデータが自動的に作成されるのですが、 それをSQLクエリで並び替えることに苦労しています。 やりたいこと: 最上位の親から最下層の子までのパスを列挙するクエリを作成したい。 テーブル構造: 直属の親と子を1レコードで保存しています。 (ID=0は最上位の為、1が最上位の親) TableName:Department ID ParentID ChildID Order ChildName -- -------- ------- ----- --------- 0    0    1   1   xx 1    0    2   1   aa 2    1    3   1   bb 3    1    4   2   cc 4    2    5   1   dd 5    2    6   2   ee 6    3    7   1   ff 7    3    8   2   gg 8    6    9   1   hh 9    6    10   2   ii 10    8    11   1   jj クエリで以下のように表示したい。 Level1 Level2 Level3 Level4 Level5 NodeName ------ ------ ------ ------ ------ --------   1                   xx   1    3              bb   1    4              cc   1    3    7          ff   1    3    8          gg   1    3    11         jj   2                  aa   2    5              dd   2    6              ee   2    6    9          hh   2    6    10         ii 私が試したSQLクエリは以下となります。 select lev3.Level1,lev3.Level2,Level3,Level4,Node5.ChildID as Level5,ChildName from Department as Node5 Right Join(select lev2.Level1,lev2.Level2,lev2.Level3,Node4.ChildID as Level4,ChildName from Department as Node4 Right Join(select level.Level1, level.Level2,Node3.ChildID as Level3,ChildName from Department as Node3 Right Join(select Node1.ChildID as Level1,Node2.ChildID as Level2,ChildName from Department as Node2 Right Join(select ChildID,NodeName.ChildName from Department as Node0 inner Join tbDepartment as NodeName on Node0.ChildID=NodeName.ID Right Join(select ChildID as N0 from Department where ParentID=0) as Node00 on Node00.N0=Node0.ParentID) as Node1 on Node1.ChildID=Node2.ParentID) as level on level.N2=Node3.ParentID) as lev2 on lev2.N3=Node4.ParentID) as lev3 on lev3.N4=Node5.ParentID これだと、パスの列挙はできるのですが、名前が最上位の親だけしかわからず、 あたまが混乱しています。 有効な列挙方法を教えてください。 よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • jamshid6
  • ベストアンサー率88% (591/669)
回答No.1

再帰CTEの話をすると混乱するかもしれませんので、とりあえず以下を。 ただ、クエリを見る限り、Accessっぽいのが気になります。 SELECT CASE WHEN d5.ChildID IS NOT NULL THEN d5.ChildID WHEN d4.ChildID IS NOT NULL THEN d4.ChildID WHEN d3.ChildID IS NOT NULL THEN d3.ChildID WHEN d2.ChildID IS NOT NULL THEN d2.ChildID WHEN d1.ChildID IS NOT NULL THEN d1.ChildID END, CASE WHEN d5.ChildID IS NOT NULL THEN d4.ChildID WHEN d4.ChildID IS NOT NULL THEN d3.ChildID WHEN d3.ChildID IS NOT NULL THEN d2.ChildID WHEN d2.ChildID IS NOT NULL THEN d1.ChildID END, CASE WHEN d5.ChildID IS NOT NULL THEN d3.ChildID WHEN d4.ChildID IS NOT NULL THEN d2.ChildID WHEN d3.ChildID IS NOT NULL THEN d1.ChildID END, CASE WHEN d5.ChildID IS NOT NULL THEN d2.ChildID WHEN d4.ChildID IS NOT NULL THEN d1.ChildID END, CASE WHEN d5.ChildID IS NOT NULL THEN d1.ChildID END, COALESCE(d1.ChildName,d2.ChildName,d3.ChildName,d4.ChildName,d5.ChildName) FROM Department d1 LEFT OUTER JOIN Department d2 ON d2.ChildID=d1.ParentID LEFT OUTER JOIN Department d3 ON d3.ChildID=d2.ParentID LEFT OUTER JOIN Department d4 ON d4.ChildID=d3.ParentID LEFT OUTER JOIN Department d5 ON d5.ChildID=d4.ParentID

buraigasho
質問者

お礼

おお!いとも簡単に・・・ まだまだ勉強不足を痛感しています。こんな方法もあるんですね・・・ 教えていただいて本当にありがとうございます。 ちなみに、Accessっぽいのは、もともとAccessから勉強しだした人間なので、 基礎が抜けきらない状態です。 SQLServer2000を手にしてSQL文を勉強しだしたので、初心者に近いです。・・・ 再帰CTEなどの例文をいろいろやっていきま=す。

関連するQ&A

  • クエリで「データ型が一致しません」と表示される

    クエリ1とクエリ2をクエリ3で結合するとクエリ3で「データ型が一致しません」と表示されます。 クエリ1のSQL文 SELECT Trim(Replace([PC管理台帳.使用者氏名]," ","")) AS 式1, PC管理台帳.新PC名, PC管理台帳.部署名, PC管理台帳.マシンベンダ名, PC管理台帳.マシンモデル FROM PC管理台帳; クエリ1では[使用者氏名]の苗字と名前のスペースを置換しました。 クエリ2のSQL文 SELECT 職員アカウント.職員番号, Trim(Replace([職員アカウント.氏名]," ","")) AS 式1, 職員アカウント.パスワード, 職員アカウント.メールアドレス FROM 職員アカウント; クエリ2では[氏名]の苗字と名前のスペースを置換しました。 クエリ3で[使用者氏名]と[氏名]が一致しているものを抽出したいです。 ちなみにクエリ3のSQL文は SELECT [クエリ2].[式1], [クエリ2].[職員番号] FROM クエリ1 INNER JOIN クエリ2 ON [クエリ1].[式1]=[クエリ2].[式1]; これでクエリ3をひらくと 「データ型が一致しません」 と表示されます。 どなたかアドバイスお願いします

  • ACCESSテーブル2つのデータの比較について

    アクセステーブル2つのデータ比較について質問があります、 宜しくお願いいたします。 Access, Excel, VBは初心者レベルです。 TableA,TableBというフォーマットが同じなテーブルがあり、 データが同じかを比較をし、どちらかのテーブルにないエントリーが ある場合はそれを出したいと思います。 途中まで出来たのですが、uniqueではないデータがある為に正確な情報がでません。 具体的には: TableA        | TableB Field1 Field2 | Field1 Field2 AAA 10 | AAA 10 BBB 100 | BBB 100 CCC 200 | CCC 200 CCC 200 | EEE 100 DDD 100 | 希望の答えは Field1 Field2 Field3 CCC 200 NotInB <--- これがでません DDD 100   NotInB  <--- これはだせました EEE 100 NotInA  <--- これもだせました 以下のようなものを書いたのですが、CCCのエントリーがTableBに 一件あるので件数が違うにもかかわらずひけませんでした。 SELECT TableA.*, "NotInB" as Field3 FROM TableA LEFT JOIN TableB ON (TableA.Field1=TableB.Field1) AND (TableA.Field2=TableB.Field2) WHERE TableB.Field1 Is Null; UNION ALL SELECT TableA.*, "NotInB" as Field3 FROM TableA RIGHT JOIN TableB ON (TableA.Field1=TableB.Field1) AND (TableA.Field2=TableB.Field2) WHERE TableA.Field1 Is Null; 一致したらフラグを立てて、再チェックしないようにすればいいのだと思うのですが、アクセスのクエリ、VBなどでどのようにすればできますか?  もしくはアクセスからxlsなどに落としてから、ファイルの状態で比較 (会社で使うので外部ソフト等が使えません) をVBでするといった方法を検討した方がいいのでしょうか? 色々調べてみたのですが、どっちもやり方が分からないので、 それはそもそも出来ないよなどの アドバイスもございましたら、どうぞ宜しくお願いいたします。

  • 「#エラー」を含んでいても、並べ替えができるようになりたい。

    テーブル1 A-a B-b テーブル2 A-a C-c クエリ1 SELECT Replace(テーブル1![1],"-","") AS 1 FROM テーブル1; クエリ2 SELECT Replace(テーブル2![2],"-","") AS 2 FROM テーブル2; クエリ3 SELECT クエリ1.[1], クエリ2.[2] FROM クエリ2 RIGHT JOIN クエリ1 ON クエリ2.[2] = クエリ1.[1]; ****************************************************************** 各テーブルのクエリを作成し、Replace関数で置換して、 その置換後の各クエリを、さらにクエリを作成して結合しています。 その時に、 テーブル1にはあるのにテーブル2にない値が 「#エラー」となるのですが、 この状態でも並べ替えを出来るようにするにはどうすればいいでしょうか? 他の値にデータ型を変えるのでしょうか? 「#エラー」があるフィールドは並べ替えも出来ないですし、 デザインビューの抽出条件で 「Not Like "#エラー"」 としても 「抽出条件でデータ型が一致しません。」 というエラーになり、データシートビューで表示できません。 アドバイス宜しくお願い致します。

  • Accessの内部結合

    こんにちは。 Accessでcateテーブルとgoodsテーブルがあります。 select * from goods inner join cate on goods.cateid = cate.id; クエリデザインで、テーブルとテーブルを結合して上記のようなSQLができました。 これは動作することを確認しました。 SQLビューで下記のようなSQLを書きました。 select * from goods inner join cate on left(goods.cateid,5) = cate.id; しかしながら、動きませんでした。 VBAを使わずに、Accessの標準のクエリデザインから上記のようなSQLを実行させることは可能でしょうか? クエリデザインでselect left(cateid,5) as cateid from goodsというTESTクエリをつくり、TESTクエリとcateテーブルとジョインさせれば解決しそうなことはわかるのですが・・・ 宜しくお願いします。

  • ~JOIN ON句でこのような問い合わせはできるのでしょうか?

    SELECT * FROM `テーブル1` AS t1 LEFT JOIN `テーブル2` AS t2 ON ( ( t1.a * 100000 ) + t1.b ) = t2.a エラーはでませんが、意図したレコードが返ってきません。クエリの使い方が間違っているのでしょうか?教えてください。 検証環境:MySQL 4.0.24-standard

    • ベストアンサー
    • MySQL
  • ACCESSクエリで複数テーブルの値の結合について

    現在、ACCESS2000で2つのテーブルの値を表示するクエリを作成中です。 テーブルは外部データよりインポートしています。 Aテーブル KEY1 | KEY2 | 値1 -------------------------- 00000001 | AAAAAAAA | 100 00000001 | BBBBBBBB | 200 00000002 | AAAAAAAA | 1000 Bテーブル KEY1 | KEY2 | 値1 -------------------------- 00000001 | AAAAAAAA | 500 00000002 | BBBBBBBB | 300 これを、 KEY1 | KEY2 | 値1 ------------------------------------------------ 00000001:00000001 | AAAAAAAA:AAAAAAAA | 100:500 ←(1) 00000001:NULL | BBBBBBBB:NULL | 200:NULL ←(2) 00000002:NULL | AAAAAAAA:NULL | 1000:NULL ←(3) NULL:00000002 | NULL:BBBBBBBB | NULL:300 ←(4) と表示したいのです。 INNER JOIN では、上記(1)しか表示されません。 また、LEFT JOIN では、(1)(2)(3)は表示されますが、(4)が表示されません。 SQLは下記です(INNER JOINを使用した場合) SELECT [Aテーブル.KEY1] & ":" & [Bテーブル.KEY1] AS KEY1, [Aテーブル.KEY2] & ":" & [Bテーブル.KEY2] AS KEY2, [Aテーブル.値1] & ":" & [Bテーブル.値1] AS 値1 FROM Aテーブル INNER JOIN Bテーブル ON ([Aテーブル].[KEY1]=[Bテーブル].[KEY1]) AND ([Aテーブル].[KEY2]=[Bテーブル].[KEY2]); どなかた教えてください。お願いします。

  • アクセスクエリ メモ型だとエラーになる

    アクセスのテーブル1(主キーなし)に *********************************************************** フィールド1(メモ型) あああ いいい ううう いいい *********************************************************** と言うデータがあるのですが 「あああ」「ううう」は1個で「いいい」は2つあります。 これを、クエリ1で *********************************************************** SELECT テーブル1.フィールド1, Count(テーブル1.フィールド1) AS フィールド1のカウント FROM テーブル1 GROUP BY テーブル1.フィールド1; *********************************************************** と作り、 新しいクエリで *********************************************************** SELECT テーブル1.フィールド1, クエリ1.フィールド1のカウント FROM テーブル1 INNER JOIN クエリ1 ON テーブル1.フィールド1 = クエリ1.フィールド1; *********************************************************** としたいのですが、 メモ型ではダメなのでしょうか? メモ型でフィールドを宣言しつつ、 このようなクエリを作るにはどうすればいいですか? テキスト型にすると問題なくいけます。

  • SELCTを使って違うテーブルのデータを2度使って表示させたいのですが

    SELCTを使って違うテーブルのデータを2度使って表示させたいのですが どのようにしたらいいのか教えてください。 ---------------------- ■テーブルの構成 ・FoodList NO(主キー) Food ・MyList NO(主キー) fist second ---------------------- ■テーブルの内容 ・FoodList NO Food 1 りんご 2 みかん 3 ぶどう ・MyList NO fist second 1 2 3 2 1 2 3 2 1 ---------------------- これで 1 みかん ぶどう 2 りんご みかん 3 みかん りんご というように表示させたいのですが どのようにしたらいいのでしょうか? --------------------------------------------------------- SELECT MyLike.NO AS Expr1,FoodList.food,MyLike.Second FROM FoodList INNER JOIN MyLike ON FoodList.NO = MyLike.first --------------------------------------------------------- とすると 1 みかん 3 2 りんご 2 3 みかん 1 となってしまいますし --------------------------------------------------------- SELECT MyLike.NO AS Expr1,FoodList.food,MyLike.Second FROM FoodList INNER JOIN MyLike ON FoodList.NO = MyLike.first AND FoodList.NO=MyLike.Second --------------------------------------------------------- とすると表示されないですし どのようにしたら実現できるでしょうか? 教えてください。よろしくお願いします。

  • WHERE句はJOIN結合前結合後どちらに効くのか

    以下の2つのSQLを比較してどちらがパフォーマンスが良いでしょうか。 先に抽出して結合した方が良いと昔聞いた事がありましたが 記憶があいまいになってしまいました。 (1) SELECT * FROM A JOIN B ON A.*** = B.*** WHERE A.*** = '0001' (2) SELECT * FROM (SELECT * FROM A WHERE A.*** = '0001') AS A JOIN B ON A.*** = B.***

  • データベース上の全てのテーブルに対するクエリ

    mySQLでデータベース内の全てのテーブルに対するクエリーに関して質問があります(mySQL 5.5)。 仮に 「ichinensei」というデータベースにテーブル「1_kumi」「2_kumi」「3_kumi」 .....と複数のテーブルがあるとします。 テーブルは全て同じデータ形式で仮に name (char) | weight (int) という名前と体重の情報が登録されているとします。 やりたいことは全てのテーブルに対しweightを検索キーとして該当するレコードのnameをとってくる、という操作です。 weight(体重)が41,42,43,50,51であるレコードの名前を列挙するためには SELECT name FROM (全てのテーブル) WHERE weight IN (41,42,43,50,51) 上記のようなクエリ文が考えられますが(全てのテーブル)に対する検索を1文で済ます方法が分かりません。 実際の作業ではテーブル数が数十個なのでなるべくunionなどを使ってテーブルの数分クエリ文を書くというのは避けたいと考えています。 このような場合どのようなクエリ文が使えるのでしょうか?

    • ベストアンサー
    • MySQL