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

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

ただいまの
回答率

88.37%

SQLでJOINするテーブルをカラムの値によって変えたい

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 681

TonToroJP

score 11

前提

初めて質問させていただきます。
当方IT職ではなく、慣れませんが宜しくおねがいします。

例として以下のようなテーブルがあります。
FOOD_MENUにはご飯のメニューが入っています。

MENU_ID NAME (中略) REQUIRED_FOOD1 REQUIRED_FOOD2 REQUIRED_FOOD3
1 カレー ... 201 202 301
2 焼肉 ... 301 302
3 白米 ...

REQUIRED_FOOD1 と 2 と3には必要な食材のIDが格納されています。


VEGETABLE_FOODには野菜データが入っています。

FOOD_ID NAME PRICE
201 じゃがいも 100
202 にんじん 100
201 たまねぎ 80

野菜テーブルのFOOD_IDは必ず2で始まります。


MEAT_FOODにはお肉データが入っています。

FOOD_ID NAME PRICE
301 豚肉 300
302 牛肉 500

肉テーブルのFOOD_IDは必ず3で始まります。

実現したいこと

SQLでJOINするテーブルをカラムの値によって変えたいです。

具体的には、REQUIRED_FOODxの左端の値が2であればVEGETABLE_FOODテーブルをJOIN、3であればMEAT_FOODテーブルをJOINといった具合です。
しかし後述するクエリでは、私が求める結果が出ないのです。

試した事・ 発生している問題

以下のことを試しました。

LEFT JOINのテーブル名をCASE演算子で指定する
SELECT * 
FROM FOOD_MENU

LEFT JOIN 
(CASE LEFT(REQUIRED_FOOD1,1)
WHEN '2' THEN (VEGETABLE_FOOD AS VEGE1 ON FOOD_MENU.REQUIRED_FOOD1 = VEGE1.FOOD_ID) 
WHEN '3' THEN (MEAT_FOOD AS MEAT1 ON FOOD_MENU.REQUIRED_FOOD1 =  MEAT1.FOOD_ID)
END)
LEFT JOIN
(CASE LEFT(REQUIRED_FOOD2,1)
WHEN '2' THEN (VEGETABLE_FOOD AS VEGE2 ON FOOD_MENU.REQUIRED_FOOD2 = VEGE2.FOOD_ID) 
WHEN '3' THEN (MEAT_FOOD AS MEAT2 ON FOOD_MENU.REQUIRED_FOOD2 =  MEAT2.FOOD_ID)
END)

LEFT JOIN...(以下REQUIRED_FOOD3も同じようにJOIN) 


結果:

[IBM]SQL0104 - トークン(は正しくない。有効なトークンはTO OUTER EXCEPTIONです。

エラーメッセージが帰ってきました。

必要なテーブルをすべてLEFT JOINする
SELECT * 
FROM PEPOLE 

LEFT JOIN VEGETABLE_FOOD AS VEGE1 ON FOOD_MENU.MENU_ID = VEGE1.FOOD_ID
LEFT JOIN MEAT_FOOD AS MEAT1 ON FOOD_MENU.MENU_ID = MEAT1.FOOD_ID
LEFT JOIN VEGETABLE_FOOD AS VEGE2 ON FOOD_MENU.MENU_ID = VEGE2.FOOD_ID
LEFT JOIN MEAT_FOOD AS MEAT2 ON FOOD_MENU.MENU_ID = MEAT2.FOOD_ID

LEFT JOIN .....(以下REQUIRED_FOOD3も同じようにJOIN) 


結果:

MENU_ID NAME (中略) VEGE1.NAME MEAT1.NAME VEGE2.NAME MEAT2.NAME VEGE3.NAME MEAT3.NAME
1 カレー ... じゃがいも にんじん
1 カレー ... 豚肉
2 焼肉 ... 豚肉 牛肉
3 白米 ...

結果は出るが、1行目と2行目を一緒にしたい。(後述)

理想

MENU_ID NAME (中略) VEGE1.NAME MEAT1.NAME VEGE2.NAME MEAT2.NAME VEGE3.NAME MEAT3.NAME
1 カレー ... じゃがいも にんじん 豚肉
2 焼肉 ... 豚肉 牛肉
3 白米 ...

MENU_IDを重複させずに、JOINしたテーブルの値も一つのレコードに集めたい(マージさせる?)

言い方が拙くて本当に申し訳ないのですがご教授ください。

補足情報(FW/ツールのバージョンなど)

IBM DB2 VER 9.7

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

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

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

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • hihijiji

    2019/06/08 13:49

    まずは、データベースの正規化を行うことをお勧めします。
    このままではどんどん酷いことになります。

    キャンセル

  • TonToroJP

    2019/06/08 14:46

    ご指摘ありがとうございます。

    権限はありませんが正規化についても調べてみようと思います。

    キャンセル

回答 1

checkベストアンサー

+1

SQLでJOINするテーブルをカラムの値によって変えたいです。

動的にSQLを組み立てない限りできません。
SQLの基本は集合を作成する事です。ケースがあるなら先ず全ての場合を含んだ集合を作ること。


WITH式で纏めて、それを結合

with FOOD as (
   slect * from VEGETABLE_FOOD
 union all
   slect * from MEAT_FOOD
)
SELECT MENU.*, FOOD1.NAME, FOOD2.NAME, FOOD3.NAME  
FROM FOOD_MENU AS MENU 
     LEFT JOIN FOOD AS FOOD1 ON MENU.REQUIRED_FOOD1= FOOD1.FOOD_ID
     LEFT JOIN FOOD AS FOOD2 ON MENU.REQUIRED_FOOD2= FOOD2.FOOD_ID
     LEFT JOIN FOOD AS FOOD3 ON MENU.REQUIRED_FOOD3= FOOD3.FOOD_ID

相関副問合せで行う。
FOOD_MENU の件数が少なければ(where条件で絞り込まれる場合も含む)こちらの方が高速。

SELECT MENU.*
     , coalesce(
         (select NAME from VEGETABLE_FOOD where FOOD_ID=MENU.REQUIRED_FOOD1)
        ,(select NAME from MEAT_FOOD where FOOD_ID=MENU.REQUIRED_FOOD1)
       ) FOOD1_NAME
     , coalesce(
         (select NAME from VEGETABLE_FOOD where FOOD_ID=MENU.REQUIRED_FOOD2)
        ,(select NAME from MEAT_FOOD where FOOD_ID=MENU.REQUIRED_FOOD2)
       ) FOOD2_NAME
     , coalesce(
         (select NAME from VEGETABLE_FOOD where FOOD_ID=MENU.REQUIRED_FOOD3)
        ,(select NAME from MEAT_FOOD where FOOD_ID=MENU.REQUIRED_FOOD3)
       ) FOOD3_NAME
FROM FOOD_MENU AS MENU

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

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

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

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/06/08 15:46

    そもそも、menuにしろfoodにしろテーブルが正規化されていませんので、可能ならそこからですね。

    キャンセル

  • 2019/06/08 16:25

    どうもありがとうございました。
    正規化については直ちに正すことはできないと思います。(会社のレベルが知れてしまいますが…)

    正規化もいろいろと検索して勉強してみます。本当にありがとうございました。

    キャンセル

  • 2019/06/08 16:30

    わざわざもう一パターンまでありがとうございました。

    キャンセル

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

  • ただいまの回答率 88.37%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

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