• ベストアンサー

テーブルの結合(GROUP BY句の制約について)

次のような操作がしたいのですが、 Test1 t1 1 2 Test2 tt1 tt2 tt3 1  1  aa 1  2  bb -ココ 2  1  cc 2  2  dd 2  3  ee -ココ 結果 Test1とTest2を関連付けて t1 tt1 tt2 tt3 1 1 2 aa 1 2 3 ee Test2.tt2をマックス関数での参照です。 一応次のような操作をしてみました。 select T1, X.tt1, X.tt2, X.tt3 from Test1 inner join (select tt1, max(tt2) as tt2, tt3 from Test2 group by tt1, tt3) as X on (t1 = X.tt1) group by句にtt1とtt3を付けいるせいか、 すべて(Test1とTest2)が表示されます。 groupBY句の制約のせいですが・・・ 何かアドバイス等がありましたら、宜しく御願いします。

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

  • ベストアンサー
回答No.1

結果の2行目は、以下の誤りですよね? t1 tt1 tt2 tt3 2 2 3 ee 幾つかのステップを踏んで、SQLを組んだ方がいいでしょう。 【step1】 Test2表のtt1列でグループ化し、tt1列の値毎のtt2列の最大値を得る select tt1,max(tt2) as tt2 from Test2 group by tt1 ※単純なselect文では、同時にtt3列の値は得られない 【step2】 step1の問い合わせで得たtt1列、tt2列(tt1列の値毎の最大値)から、対応するtt3列の値を得る select y.tt1,y.tt2,y.tt3 from Test2 as y where (tt1,tt2) in(select tt1,max(tt2) as tt2 from Test2 group by tt1) と書ければいいのですが、SQL Serverは、「(列1,列2) in(select ~)」という書き方ができないようなのです。 そこで、existsかjoinにしますが、ここではjoinの例にします。 select y.tt1,y.tt2,y.tt3 from Test2 as y inner join (select tt1,max(tt2) as tt2 from Test2 group by tt1) as z on y.tt1=z.tt1 and y.tt2=z.tt2; 【step3】 t1列とtt1列でTest1表とTest2表を結合します。 select t1,tt1,tt2,tt3 from Test1 inner join (select y.tt1 as tt1,y.tt2 as tt2,y.tt3 as tt3 from Test2 as y inner join (select tt1,max(tt2) as tt2 from Test2 group by tt1) as z on y.tt1=z.tt1 and y.tt2=z.tt2) as x on t1=x.tt1 order by t1,tt1;

kensirooo
質問者

お礼

ご丁寧な解説。誠にありがとうございます。 頭が下がります。 >>※単純なselect文では、同時にtt3列の値は得られない 素人がよく陥る場所だということが、chukenkenkou様には 分かっているようですね。 汚いソースだとは思いますが、自分なりもう一度 考えてみたので。晒します。 select t1.t1, X.tt1, X.tt2, Y.tt3 from (Test1 t1 inner join (select tt1, max(tt2) as tt2 from Test2 group by tt1) as X on (t1.t1 = X.tt1)) inner join (select tt1, tt2, tt3 from Test2 ) as Y on (X.tt1 = Y.tt1 and X.tt2 = Y.tt2) order by t1, tt1 いろんなやり方があると感じました。 誠に有難う御座いました。

その他の回答 (2)

回答No.3

>条件1.テーブル2.TT1はテーブル1.T1に存在するものに限る 失礼しました LEFT JOIN ではなく INNER JOIN ですね (ーー;

kensirooo
質問者

お礼

有難う御座います。 参考にさせていただきます。

回答No.2

kensiroooさんの方法で、間違っているわけではありませんが、難しく考え過ぎているように思ったので、書き込みます。 先頭の >select t1.t1, X.tt1, X.tt2, Y.tt3 を見る限り、「t1.t1」だけがTable1を直接指し、あとは副問い合わせによる結果を参照していますよね。 「X」「Y」は、それぞれの機能を満たしているので、それ相応の意味はあるのでそれはそれでよいと思います。 私はあちこちの会社に転々としているのですが、、、会社によっては副問い合わせを利用する場合、それらの一機能毎に仕様書反映させるところもありました。 要は、仕様書に書いたらどうなるかを考えながら構築すると、何が必要で何が不要かがわかりやすくなると思います。 それに勤めていると、極力無駄設計を行わないようになってきて、シンプルイズベストでいけるようになると思います。 前置きはこれぐらいにしておいてと、、、 私がこの機能の仕様書を書いた場合 1.テーブル1.T1とテーブル2.TT1の結合を行い表示する ただし以下に条件を要する  条件1.テーブル2.TT1はテーブル1.T1に存在するものに限る  条件2.テーブル2.TT2は同一テーブル2.TT1内においての最大の値に限る ※1、単純に「Test1」のキーに該当する「Test2」を全てを取得 SELECT Test1.t1,Test2.tt1,Test2.tt2,Test2.tt3 FROM Test1 LEFT JOIN Test2 ON Test1.t1 = Test2.tt1 ※2、ただし「Test2」で必要とする該当条件はこれ SELECT tt1,MAX(tt2) FROM Test2 GROUP BY tt1 なので単純に考えたら、EXISTSを利用して、存在チェックをかけるだけです。 私の環境にはオラクルしかないですが、オラクルじゃなくてもSQLサーバでも動くと思います。 SELECT Test1.t1,Test2.tt1,Test2.tt2,Test2.tt3 FROM Test1 LEFT JOIN Test2 ON Test1.t1 = Test2.tt1 WHERE EXISTS( SELECT tt1 FROM Test2 dmy GROUP BY tt1 HAVING dmy.tt1 = Test2.tt1 AND MAX(dmy.tt2)= Test2.tt2 )

kensirooo
質問者

お礼

本当にいろんなやり方があるもんですね。 >>それに勤めていると、極力無駄設計を行わないようになってきて、シンプルイズベストでいけるようになると思います。 自分は一箇所にずっといるので、周りの状況が 手に入るにこのような機会はすばらしいと思っている一人です。 前置きはこれぐらいにしておいてと、、、 正直な所、Test2.tt3に囚われてしまって変な書き方になってしまいました。 また、自分のソースでは、SELECTを修正する場合に、内部まで 触らなければいけなくなるので、お二方のソースがベストでしょう。 どうなんでしょうね?自分は、まだまだの人間なんで あっちこっち見渡していては、置いてけぼりになりそうなんで、 どちらかを選んで進みたいものですが・・・・

関連するQ&A

  • テーブル間の結合

    次のような操作をしたいのですが、 Table1 CD 1 2 3 Table2 ID TT 1 1 1 2--ココ 2 1 2 2--ココ 結果 Table1とTable2を関連づけて CD ID TT 1 1 2 2 2 2 Table2のTTをMAX関数を使っての参照です。 ちなみに次のようなSQL文ではエラーとなりました。 select T1.CD , T2.ID , MAX(T2.TT) from Table1 T1 INNER JOIN Table2 T2 ON(T1.CD = T2.ID) GROUP BY T2.ID アドバイス等がありましたら、宜しくお願いします。

  • GROUP BY句について

    SQL_PLUSでの質問です。 以下のSELECT句があります。 GROUP BY句の『'A' AS 区分』は必要なのでしょうか。 ----------------------------- SELECT 商品コード AS 商品コード, 商品名 AS 商品名, 'A' AS 区分, SUM(金額) AS 金額 FROM 売上トラン GROUP BY 商品コード AS 商品コード, 商品名 AS 商品名, 'A' AS 区分; ----------------------------- 何気なくプログラムを見ていたら、目に留まりました。 このままでもコンパイルは通るので問題はないのですが、 決まった値を設定しているのだから、必要ないような気がするのです。 環境はWin2000 Oracle 9i です。 ご存知の方、教えて下さい。

  • group by句

    以下のSQL文がoracle9iでOKで8iで通らないのですが、8iでも通るようになんとかできないでしょうか。 select a.val_Id, (select val_nm from tableA where val_id = a.val_id) as val_nm from tableA a group by a.val_id テーブルの内容 tableA( val_id number(1,0), val_code number(2,0), val_nm varchar(10) ) val_idとval_codeで一意となっています。 val_nmはval_idと一対一になっています。 要するにval_idに対応するval_nmも一緒に取得したいのですが、select句のサブクエリで8iの場合"group byの式ではありません"とおこられてしまいます。 ちなみに、今ここでは簡略化しているのですが本来は色なテーブルを結合しているので、単にgroup by val_id,val_nmとするのは無しでお願いいたします。 わかりにくいかとは思いますがお知恵をお貸しください。宜しくお願いいたします。

  • SQLPLUSのGROUP BY句について

    Oracle9iのSQLPLUSにて、GROUP BY句で指定した列以外の列をSELECT文の選択結果に表示させたいだけなのですがうまくいきません。 SELECT 列A,列B,列C FROM テーブル1 A INNER JOIN ( SELECT 列A,COUNT(*) FROM テーブル1 GROUP BY 列A HAVING COUNT(*) >= 2 ) B ON A.列A = B.列A 「"B.列A"が無効識別子です」エラーが発生します。 何卒宜しくお願い致します。

  • group by句について

    すいません。教えてください。 emp表からJobのデータが何種類あるか出力したいとき、 ・ select count(distinct job) from emp; はいいのに、 ・ select count(job) from emp group by job; がエラーになる理由を知っている方、教えてください。

  • WITH句を使用したSQLの結果

    WITH句を使用して総件数と1~20件までのデータを同時に取得するSQLを組んでみたところ、 WITH TMP AS (SELECT ROW_NUMBER() OVER (ORDER BY NO) AS CHECKROWNUM,NAME FROM TEST_TBL ORDER BY NO) SELECT T1.ALLCNT, T2.* FROM (SELECT COUNT(*) ALLCNT FROM TMP) T1, TMP T2 WHERE T2.CHECKROWNUM BETWEEN 1 AND 20; Oracle10.2.0.3.0のバージョンで ALLCNTが21になってしまう現象が発生してしまいました。 Oracle10.2.0.4.0や9iでは発生せず正しい総件数が取得できるのですが、 バージョンによる不具合は考えられますでしょうか。 それともSQL自体なにか悪い部分があるのでしょうか。 ちなみに T2.CHECKROWNUM BETWEEN 1 AND 100; と帰るとALLCNTが101と帰ってきます。 また、WITH句を使わず下記のようにTMPの部分をWITH句で使用したSQLに 置き換えると正しくALLCNTが取れます。 SELECT T1.ALLCNT, T2.* FROM (SELECT COUNT(*) ALLCNT FROM (SELECT ROW_NUMBER() OVER (ORDER BY NO) AS CHECKROWNUM,NAME FROM TEST_TBL ORDER BY NO)) T1, (SELECT ROW_NUMBER() OVER (ORDER BY NO) AS CHECKROWNUM,NAME FROM TEST_TBL ORDER BY NO) T2 WHERE T2.CHECKROWNUM BETWEEN 1 AND 20;

  • GROUP BY句の集計について

    はじめまして。 いろいろ調べて、何度試しても思うように 結果がでなかったので、投稿させて頂きました。 グループの集計をしてるのですが、 何個のグループがあるのかカウントしたいのです。 aaa bbb 110 a 110 b 111 c 112 d というDBに select aaa, bbb, count(*) as cnt from database GROUP BY aaa ORDER BY aaa だとそのグループ内の該当レコード数がカウントされてしまいます。 上記の例だとグループ数が“3”と結果を返すようにしたいのです。 では。宜しくお願いします。

    • ベストアンサー
    • MySQL
  • group by したものをsumしたのですが方法がわかりません。

    ある情報をgroup byしその数をcountし、そのcountした数をsumしたのですがどのようにすればよろしいでしょうか? 例えば DB名 test a | ------ ABA | A | AA | ABA | select a,count(*) count from test group by a; a |count| ------------- ABA | 2 | A | 1 | AA | 1 | このカウントの数字を一回でsumすることは可能でしょうか? 宜しくお願いします。

  • GROUP BY/ORDER BYの併用で期待するORDERが得られま

    GROUP BY/ORDER BYの併用で期待するORDERが得られません。 データベース初心者です。よろしくお願いいたします。 table id group_id name 1 1 冷蔵庫1 2 2 カメラ1 3 2 カメラ2 4 2 カメラ3 5 3 テレビ1 のようなテーブルを、group_idでグループ化し、idの大きい順に並べた以下のようなデータ id group_id name 5 3 テレビ1 4 2 カメラ3 1 1 冷蔵庫1 を取得しようとして悩んでおります。 SELECT MAX(id) AS max_id, id, group_id, name FROM table GROUP BY group_id ORDER BY max_id DESC というクエリですと max_id id group_id name 5 5 3 テレビ1 4 x 2 y 1 1 1 冷蔵庫1 という結果が得られますが、xとyところが、期待するx=4、y=カメラ3とならないケースがあります。 いくつかのテーブルで試しましたが、期待する結果になるものとならないものがありました。 例えばこれを自己結合することも考えたのですが、WHERE句にASで命名した「max_id」が含まれると「max_idが不明」というエラーが出ます。 MySQLのバージョンは4.0.xでして、サブクエリーが使えません。 このような状況で、何か方法がございましたらご教授のほどお願い申し上げます。 「期待する結果がクエリ1回で得られない」ということを知れるだけでも構いません。 どうぞよろしくお願いいたします。

    • ベストアンサー
    • MySQL
  • SQL構文を手助けしてください

    (1)のようなテーブルデータを(2)のように表示したいと思います。 AA,BB,CC,DD,EEは列名としてください。 (1) AA BB CC DD EE __________________________ 00 01 2004/01/01 XX YY 01 00 2004/01/01 XE YD 01 00 2004/01/05 XZ YZ 02 01 2004/01/10 X2 YE 02 02 2004/01/05 XW YI 02 02 2004/01/06 XF YL (2) AA BB CC DD EE __________________________ 00 01 2004/01/01 XX YY 01 00 2004/01/05 XZ YZ 02 01 2004/01/10 X2 YE 02 02 2004/01/06 XF YL <条件> AAとBBでキーを作り、CCのMAXの該当レコードを表示したい。 SELECT AA,BB,MAX(CC),DD,EE FROM TEST_TABLE GROUP BY AA,BB というような感じかなと思ったのですが、「GROUP BY の式ではありません」と怒られてしまいます。 どなたか簡単なやり方をご存知で無いでしょうか?