テーブルのマージSQLで複数項目を出力する方法

このQ&Aのポイント
  • AテーブルとBテーブルをマージさせ、社員番号と内容を日付順に並べ替える方法について教えてください。
  • UNIONを使用することで、異なる項目を持つテーブルをマージさせることができますが、所属、時間、結果、理由の項目を全て出力する方法はありますか?
  • UNIONの場合、項目が異なるとエラーとなってしまう可能性があります。どのように記載すれば良いでしょうか?
回答を見る
  • ベストアンサー

テーブルのマージSQLに関して

初歩的なSQLの質問で申し訳ありません。 以前にも同じような内容で投稿させて頂きましたが、教えて下さい。 下記のような、ある異なる名前の同項目を持つ2つのテーブルが存在します。 《テーブル》 Aテーブル   社員番号、日付、内容、所属、時間、結果 Bテーブル  社員番号、日付、内容、理由  ※ 内容に関しては、AテーブルとBテーブルで全く違います。 これらの2つのテーブルをマージさせ、社員番号毎の内容毎、日付順に したいと考えています。 以前に以下のようなUNIONを教えてもらいましたが、所属、時間、結果、理由という 項目全てを出力するとした場合、どのように記載すれば良いでしょうか? UNIONの場合、項目が異なるとエラーとなってしまうかと、、、 《UNIONのSQL》 SELECT * FROM ( SELECT 社員番号, 日付, 内容 FROM Aテーブル UNION SELECT 社員番号, 日付, 内容 FROM Bテーブル ) ORDER BY 日付, 社員番号, 内容 教えて下さい。 よろしくお願いします。

  • Oracle
  • 回答数3
  • ありがとう数13

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

  • ベストアンサー
  • yamada_g
  • ベストアンサー率68% (258/374)
回答No.3

そもそもがUNIONの用途として正しくない気がしますしね。 複数のテーブルの同一キーのデータを簡単に取れないというのは、設計がよくないのではないかという気がします。 >1つ1つNULLを設定するのは難しいかと、、、 とありますが、ただ面倒だということですよね? ひとつひとつ項目を列挙していくだけなので難しいことはないと思うのですが。 たしかに、テーブルや項目が多ければ大変だとは思いますが、やらなければいけないことならやるしかないと思います。 役に立つか分かりませんが、複数のテーブルの全項目をUNIONで取得するSQLを組み立てるSQLを考えてみました。 --全角スペースでインデントしています select   case     when COL_NUM = 1 then       case         when TAB_NUM > 1         then 'UNION ALL' ||CHR(10)       end       || 'SELECT' || CHR(10)     else ','   end || coalesce(P_COLUMN_NAME, 'NULL') || ' AS ' || L_COLUMN_NAME || case     when max(COL_NUM) over() = COL_NUM then       CHR(10) || 'FROM ' || TABLE_NAME   end from   (     select       TABS.TABLE_NAME      , COLS.COLUMN_NAME L_COLUMN_NAME      , TAB_COLS.COLUMN_NAME P_COLUMN_NAME      , dense_rank() over(order by TABS.TABLE_NAME) TAB_NUM      , ROW_NUMBER() over(partition by TABS.TABLE_NAME order by COLS.COLUMN_NAME) COL_NUM     from       (         select distinct COLUMN_NAME         from USER_TAB_COLS         where TABLE_NAME in ('Aテーブル', 'Bテーブル') --対象のテーブルを列挙してください       ) COLS     cross join       (         select TABLE_NAME         from USER_TABLES         where TABLE_NAME in ('Aテーブル', 'Bテーブル') --対象のテーブルを列挙してください       ) TABS     left join USER_TAB_COLS TAB_COLS     on       (         TAB_COLS.TABLE_NAME = TABS.TABLE_NAME       and TAB_COLS.COLUMN_NAME = COLS.COLUMN_NAME       )   ) order by   TAB_NUM  , COL_NUM ; これを実行すると、たとえば今回提示されているテーブル定義であれば、 SELECT 内容 AS 内容 ,所属 AS 所属 ,日付 AS 日付 ,時間 AS 時間 ,NULL AS 理由 ,社員番号 AS 社員番号 ,結果 AS 結果 FROM Aテーブル UNION ALL SELECT 内容 AS 内容 ,NULL AS 所属 ,日付 AS 日付 ,NULL AS 時間 ,理由 AS 理由 ,社員番号 AS 社員番号 ,NULL AS 結果 FROM Bテーブル というSQLが出来ます。 これをインラインビューにして、SELECTする項目順を入れ替えたり、不要な項目を削除したりすれば少しは楽になるかもしれません。

その他の回答 (2)

  • yamada_g
  • ベストアンサー率68% (258/374)
回答No.2

すみません。質問をきちんと読めていませんでした・・・ Bテーブルだけに存在する項目もあるのですね。 であれば、AテーブルのSELECT文でNULLを設定すればいいです。 SELECT 社員番号, 日付, 内容, 所属, 時間, 結果, NULL AS 理由 FROM Aテーブル UNION SELECT 社員番号, 日付, 内容, NULL, NULL, NULL, 理由 FROM Bテーブル ORDER BY 社員番号, 内容, 日付; でいかかでしょうか。

asamix_000
質問者

お礼

yamada_g様、ご回答ありがとうございます。 返事が遅くなりまして申し訳ありません。 教えて頂いた件、問題なくできました! ちなみに、もしこれらのテーブルが複数存在し、社員番号、日付、内容は キーになるものの、それ以外の項目を、テーブルがある分だけ表示させるような 場合はどのようにするのが良いのでしょうか? 1つ1つNULLを設定するのは難しいかと、、、 よろしくお願いします。

  • yamada_g
  • ベストアンサー率68% (258/374)
回答No.1

存在しない項目にNULLを設定すればUNIONすることができます。 SELECT 社員番号, 日付, 内容, 所属, 時間, 結果 FROM Aテーブル UNION SELECT 社員番号, 日付, 内容, NULL, NULL, NULL FROM Bテーブル ORDER BY 社員番号, 内容, 日付; もし、それぞれのテーブルが社員番号と日付で一意になり、それらのデータは1行にしたいということであれば完全外部結合してもいいと思います。 SELECT NVL(A.社員番号, B.社員番号) AS 社員番号, NVL(A.日付, B.日付) AS 日付, A.内容 AS A内容, B.内容 AS B内容, A.所属, A.時間, A.結果 FROM Aテーブル A FULL OUTER JOIN Bテーブル B ON (A.社員番号 = B.社員番号 AND A.日付 = B.日付) ORDER BY 社員番号, A.内容, B.内容, 日付; みたいな感じです。

asamix_000
質問者

お礼

yamada_g 様、ご回答ありがとうございます。 NULLの件ですが、Bテーブルの方も社員番号、日付、内容だけでなく、理由 も出力したいと考えています。 その場合は、NULLでは難しいですよね、、、 また、残念ながら両テーブルは、社員番号と日付では一意にならず、N:Nの 関係となっています。 何もわからず申し訳ありませんが、もう少し教えて頂ければ幸いです。 よろしくお願いします。

関連するQ&A

  • 簡単なSQLに関して

    初歩的なSQLの質問で申し訳ありません。 教えて下さい。 下記のような、ある2つの異なる名前の同項目のテーブルが存在します。 《テーブル》 Aテーブル   社員番号、日付、内容 Bテーブル  社員番号、日付、内容  ※ 内容に関しては、AテーブルとBテーブルで全く違います。 これらの2つのテーブルをマージさせ、社員番号毎の内容毎、日付順に したいと考えています。 どのようなSQLを書けば良いでしょうか?? 尚、テーブルに関しては、諸事情であえて2つに分けてあります。 よろしくお願いします。

  • SQLの問題です。

    以下のような二つのテーブルがあります。 社員テーブル 社員番号 社員氏名 1     花子 2     太郎 所属テーブル 社員番号 所属番号 1     10 1     20 2     30 欲しいのは以下の結果です。 1 花子 2 太郎 以下のSQLを実行すると、 SELECT distinct a.社員番号, a.社員氏名, b.所属番号 FROM 社員 a,所属 b where a.社員番号 = b.社員番号 order by 所属番号 1 花子 1 花子 2 太郎 となってしまいます。 先に述べたとおりの結果を取得するにはどういうSQLを書いたらいいでしょうか? お知恵を貸してください。宜しくお願いします。 Oracle8iを使用しています。   

  • SQL 複数のテーブルから重複なしでデータを取得

    同じフィールド名[名前]を持つテーブルが複数個あります。 仮にテーブル名を、A、B、C、Dの4個だとします。 それらのテーブルから、フィールド名[名前]のデータを重複なしで取得したいのですが、SQL文が思いつきません。 取得するフィールドは[名前]だけです。 select distinct(名前) from A union select distinct(名前) from B union select distinct(名前) from C union select distinct(名前) from D だと、各表に同じ名前が存在する場合は結果も重複してしまい、期待する結果が得られませんでした。 環境はOracle 9iです。 SQL文を教えてください。よろしくお願いします。

  • 年齢分布テーブルの再集計SQL

    テーブルA 年齢,人数 20,15 21,11 22,26 .... 30,5 31,88 ... 60,5 上記テーブルAからのSQLで下記のデータが欲しいと思っております。 【欲しい結果】 年齢範囲,人数 20~24,50 25~29,33 30~34,199 ... ただし、 select '20~24'as 年齢範囲,count(*)as 人数 from テーブルA where 条件1 union select '25~29'as 年齢範囲,count(*)as 人数 from テーブルA where 条件2 union select '30~34'as 年齢範囲,count(*)as 人数 from テーブルA where 条件3 ... というSQLは使いたくないです。(テーブルAの記述が長めなので、同じものを複数記述したくないのです) また結果が 項目名:20~24,25~29,30~34,... レコード:50,33,199,... というのも遠慮したいです。 CASE文やsum、groupを使えば、できそうな気がするのですが、、、 ご教授お願い致します。

  • テーブル名をカラムとして取得する方法

    テーブル名をカラムとして取得する方法はありますでしょうか? オラクル8とVB6でプログラムを組んでいます。 例 TABLE Aの内容 カラム1 1 2 3 TABLE B カラム1の内容 4 5 6 SQLは簡略化してかきます。下記のSQLを実行した場合、 select A.カラム1 from A union select b.カラム1 from b 1 2 3 4 5 6 を取得できます。 例えば、上記で、SQL実行後、 下記のような値を取得したいです。 1 ,Aのテーブルだよ 2 ,Aのテーブルだよ 3 ,Aのテーブルだよ 4 ,Bのテーブルだよ 5 ,Bのテーブルだよ 6 ,Bのテーブルだよ それぞれのテーブルの名前を別名で結果に格納したいのです。 何か方法はありますでしょうか? なければ、unionせずに、2回SQLを発行し、それぞれに、 プログラム上で、「Aのテーブルだよ」を後で挿入したいと思っています。

  • Access2002 2つのテーブルのマージ方法

    いつもお世話になっております。 クエリについてお聞きします。 現在、2つのAccessDBが稼動しており、それを1つにまとめる作業をしています。 2つのDBには似通ったテーブルが存在し、それをマージする方法で悩んでいます。 テーブルA ・社員番号 ・社員氏名 ・フリガナ ・会社コード ・部署コード テーブルB ・従業員コード ・従業員名カナ ・従業員名 ・所属コード フィールドの定義としましては、 社員番号=従業員コード 社員氏名=従業員名 フリガナ=従業員名カナ 部署コード=所属コード となります。 全てテキストのレコードです。 これを、テーブルAを正にして、テーブルBのデータをAにマージしたいのです。 要件としましては、 1.テーブルAに存在する社員コードにマッチするレコードはそのまま残す(Bのデータは無視) 2.テーブルAに存在せず、Bに存在するものをAに追加する ということです。 クエリを使って色々試しましたが、どうしてもテーブルAに存在するものもアップデートしてしまい、困っています。 どなたかご教授願えれば幸いです。 よろしくお願いいたします。

  • テーブル結合について、下記SQLをANSI結合の書き方で表したい。

    テーブル結合について、下記SQLをANSI結合の書き方で表したい。 select * from (select key from A union select key from B union select key from C) X, A,B,C where X.key=A.key(+) and X.key=B.key(+) and X.key=C.key(+) このSQLをANSI結合の記述で書きたいのですが、 (+)での結合文になれておらず試行錯誤しております。 下記のようなのかなとは模索しておりますが、 手元に実行環境がなくわかりません。 また、要所気付く点などありましたら、ご指摘願います。 select A.*, B.*, C.* from (select key from A union select key from B union select key from C) X, LEFT JOIN A ON X.key=A.key LEFT JOIN B ON X.key=B.key LEFT JOIN C ON X.key=C.key

  • SQL文をどう記述すれば良いか教えて下さい。

    テーブルAが以下の様に在るとします。 連番(ユニークキー)/日付/社員コード/所属コード そして、社員コード、所属コードの名称が、テーブルBに登録されています。 区分/コード/名称 ここで、区分+コードでユニークキーとなっていて、区分=1は社員コード、区分=2は所属コードとなっています。 単純に、テーブルAから、ある日付を指定して、連番・社員コード・所属コードを取得する場合、SQL文は以下の様になると思います。 SELECT 連番,社員コード,所属コード FROM テーブルA WHERE 日付='20030401' この時、同時に、テーブルBから社員コードに対応する名称、及び所属コードに対応する名称を取得したい場合は、どの様に記述すれば良いのでしょうか?

  • 2つのテーブルAとBをマージして新しいテーブルCを作成したいのです。

    2つのテーブルAとBをマージして新しいテーブルCを作成したいのです。マージするときは、最新の売上日フィールドをもつレコードを取得します。環境はAccess2000です。どんなSQL文を作成すればいいのでしょうか?  また、テーブルAにしかないレコード、又はテーブルBにしかないレコードは、そのままテーブルCに追加したいです。 ※下記テーブルAとBは、Access内に存在します。テーブルCはAとBのマージ後の結果作成されるテーブルです。 テーブルA 顧客番号   売上日   商品名   備考    1  2000-01-01  ふでばこ   A    2  2000-02-02  鉛筆     A    3  2000-03-03  定規     A    4  2000-04-04  シャーペン  A   99  2000-09-09  パソコン   A テーブルB 顧客番号   売上日   商品名   備考    4  2001-04-04  シャーペン  B    2  2000-02-02  鉛筆     B    3  2001-03-03  定規     B    1  1999-01-01  ふでばこ   B  100  2005-11-11  ワープロ   B テーブルAとBを、最新の売上日の条件でレコードを取得し新しいテーブルCを作成する。 テーブルC 顧客番号   売上日   商品名   備考    1  2000-01-01  ふでばこ   A    2  2000-02-02  鉛筆     A    3  2001-03-03  定規     B    4  2000-04-04  シャーペン  A   99  2000-09-09  パソコン   A  100  2005-11-11  ワープロ   B SQL文で処理可能なのでしょうか?

  • MAX関数と複数問い合わせ?

    Oracle8 Release 8.0.5.0.0 - Production を使用しています。 以下のテーブル内容から、社員ごとの一番新しい日付のデータを取得したいのですがお知恵をお貸しください。 t_table ------------------------------- 社員番号     作成日付 1         2003/04/07 13:03:57 1         2003/04/05 13:03:57 2         2003/04/10 13:03:57 3         2003/03/01 13:03:57 欲しい結果 1         2003/04/07 13:03:57 2         2003/04/10 13:03:57 3         2003/03/01 13:03:57 です。 select a.社員番号, a.作成日時 from t_table a, t_table b where a.社員番号 = b.社員番号 and b.作成日時 = (select max(作成日時) from t_table) とやると、 1         2003/04/07 13:03:57 1         2003/04/05 13:03:57 だけ持ってきてしまいます。 あと、できればDB2でも使えるようなSQL文にしたいのですが・・・ これはできればでかまいません。 宜しくお願いいたします。