mysql:14826
From: "Kaname Kuji\(Y7\)" <"Kaname Kuji\(Y7\)" <kkuji@xxxxxxxxxx>>
Date: Thu, 7 May 2009 01:18:52 +0900
Subject: [mysql 14826] 【蛇足】Re: 【御礼】 Re: 【初歩的質問】 テーブルを結合するSQL文
KK@IB です。 大変妥当に解決したので、この投稿は蛇足なのですが、 ちょうど似たようなことをしているときに、このやり取りがあったので 興味深く読ませていただきました。 さらに、気分に乗って、一言、余計なことを... 下記で、ちょっと気になるのは、asの後が、日本語になっていることで、 通るのか、ちょっと怖い気もしますが、実際にやってみたらうまく動作しました。 で、何が言いたいかといえば、以下のようなことをちょっと付け足したいのです。 (以下、私がちょうどやっていたことです。) 下記で、user_infoが中心的なテーブルで、他は、それにぶら下がっている 属性のテーブルです。 uidは各テーブルのprimary keyになっています。 SQL-A) select i.*,n.value as nickname,g.single as gender,d.single as district,b.date as birthday from user_info i,user_attr_text_00000001 n,user_attr_single_00000003 g,user_attr_single_00000004 d,user_attr_date_00000006 b where i.uid=xxxxx(実際は番号が入っています) and i.uid=n.uid and i.uid=g.uid and i.uid=d.uid and i.uid=b.uid これと、以下のSQLの比較です。 SQL-B) select i.*,n.value as nickname,g.single as gender,d.single as district,b.date as birthday from user_info i right join user_attr_text_00000001 n using(uid) right join user_attr_single_00000003 g using(uid) right join user_attr_single_00000004 d using(uid) right join user_attr_date_00000006 b using(uid) where i.uid=xxxxx これは、結合してから、ひとつ取り出すSQL-Bのほうが圧倒的に時間がかかります。 出てくる結果データ自体は、この実例では同じでした。 なお、ここでやり取りのあったケースのように、 特定の番号でuidを縛らない場合は、所要時間は同じです。 下記をご参照ください。 (SQLの意味合いは、相手のあるなしを配慮するしないがあるので、 厳密には違うでしょうが、ここで、属性のテーブルは、対応が無いものが 無かったので、結果は同じになりました。 もとの話題でも、NULLを「なし」に変えれば 似た形になるかも。(下のexplainの下を見てください。)) explain select i.*,n.value as nickname,g.single as gender,d.single as district,b.date as birthday from user_info i,user_attr_text_00000001 n,user_attr_single_00000003 g,user_attr_single_00000004 d,user_attr_date_00000006 b where i.uid=n.uid and i.uid=g.uid and i.uid=d.uid and i.uid=b.uid table type possible_keys key key_len ref rows Extra b ALL PRIMARY NULL NULL NULL 224085 i eq_ref PRIMARY PRIMARY 4 b.uid 1 g eq_ref PRIMARY PRIMARY 4 i.uid 1 d eq_ref PRIMARY PRIMARY 4 i.uid 1 n eq_ref PRIMARY PRIMARY 4 i.uid 1 explain select i.*,n.value as nickname,g.single as gender,d.single as district,b.date as birthday from user_info i right join user_attr_text_00000001 n using(uid) right join user_attr_single_00000003 g using(uid) right join user_attr_single_00000004 d using(uid) right join user_attr_date_00000006 b using(uid) table type possible_keys key key_len ref rows Extra b ALL NULL NULL NULL NULL 224085 d eq_ref PRIMARY PRIMARY 4 b.uid 1 g eq_ref PRIMARY PRIMARY 4 d.uid 1 n eq_ref PRIMARY PRIMARY 4 g.uid 1 i eq_ref PRIMARY PRIMARY 4 n.uid 1 (投稿にあたって、確認した結果も報告します。 もとの話のNullを「NA」に変えたもの:) 表示中の列 0 - 4 (5 合計, クエリの実行時間 0.0011 秒) 実行した SQL: SELECT c.classname, m.yname, f1.fruitname, f2.fruitname, f3.fruitname FROM `main` m, `classnm` c, `fruitnm` f1, `fruitnm` f2, `fruitnm` f3 WHERE m.`classno` = c.classno AND m.favour1 = f1.fruitno AND m.favour2 = f2.fruitno AND m.favour3 = f3.fruitno LIMIT 0 , 30 [ 編集 ] [ EXPLAIN で確認 ] [ PHP コードの作成 ] [ 再描画 ] 結果: classname yname fruitname fruitname fruitname Hana Taro StrawB Grape Orange Hana Jiro Grape Apple Orange Niji Sabu Orange NA NA Niji Shiro Apple Orange NA Sora Goro NA NA NA Explain: id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE m ALL NULL NULL NULL NULL 5 1 SIMPLE c ALL PRIMARY NULL NULL NULL 3 Using where =>ここはちょっと気に入りませんが、数が少ないせいかな? 1 SIMPLE f1 eq_ref PRIMARY PRIMARY 4 test.m.favour1 1 1 SIMPLE f2 eq_ref PRIMARY PRIMARY 4 test.m.favour2 1 1 SIMPLE f3 eq_ref PRIMARY PRIMARY 4 test.m.favour3 1 (selectの内容が、元の質問に近い(?)形:) 表示中の列 0 - 4 (5 合計, クエリの実行時間 0.0010 秒)=>多少早くなっているのはデータがメモリに乗っているせい? 実行した SQL: SELECT * FROM `main` m, `classnm` c, `fruitnm` f1, `fruitnm` f2, `fruitnm` f3 WHERE m.`classno` = c.classno AND m.favour1 = f1.fruitno AND m.favour2 = f2.fruitno AND m.favour3 = f3.fruitno classno yname favour1 favour2 favour3 classno classname fruitno fruitname fruitno fruitname fruitno fruitname 1 Taro 1 2 4 1 Hana 1 StrawB 2 Grape 4 Orange 1 Jiro 2 3 4 1 Hana 2 Grape 3 Apple 4 Orange 2 Sabu 4 0 0 2 Niji 4 Orange 0 NA 0 NA 2 Shiro 3 4 0 2 Niji 3 Apple 4 Orange 0 NA 3 Goro 0 0 0 3 Sora 0 NA 0 NA 0 NA Explain: 実行した SQL: EXPLAIN SELECT * FROM `main` m, `classnm` c, `fruitnm` f1, `fruitnm` f2, `fruitnm` f3 WHERE m.`classno` = c.classno AND m.favour1 = f1.fruitno AND m.favour2 = f2.fruitno AND m.favour3 = f3.fruitno [ 編集 ] [ SQL の EXPLAIN 解析をスキップ ] [ PHP コードの作成 ] id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE m ALL NULL NULL NULL NULL 5 1 SIMPLE c ALL PRIMARY NULL NULL NULL 3 Using where 1 SIMPLE f1 eq_ref PRIMARY PRIMARY 4 test.m.favour1 1 1 SIMPLE f2 eq_ref PRIMARY PRIMARY 4 test.m.favour2 1 1 SIMPLE f3 eq_ref PRIMARY PRIMARY 4 test.m.favour3 1 selectを*で手抜きしても良いということですかねぇ。 経験上、*にするのはちょっと怖いですね。 *にすると、余分な組み合わせも考えてくれちゃうことが多いですね。 なお、今までは私もあまりjoinを使ったことが無く、 補助テーブルやプログラムのループ、判断などで 逃げていました。 Oracleならcursorを使いたいところ? 上記でも、mainのレコードの「そのレコードになっているという組み合わせの縛り」 (うまい表現ではないですが、お許しを)をSQLに表現するのが 難しかったです。 最近は、joinも、Web検索しながら、多少使っていますが... 以上、蛇足でした。 > 結論からいいますと、ご提示のとおりで解決しました。 > >> #ちゃんと考えると、結構難しいですよ、これ。 > > そうとは知らず、失礼しました。 > 解法は「LEFT OUTER JOIN」でしたか・・・ > 入門本でも、理解しきれなかった部分です。 > > >> ということだと思うので、考え方としては園児テーブルの四角を >> 真ん中に書いて、組みのカラムから組みマスターの四角へ線。 > > 考え方、非常に勉強になりました。 > >> SQL、あまり感覚で覚えられるものでもないので、まずは適当なデータ >> ベース関連(SQLについてたくさん書かれている本)を3,4冊腰を据えて >> 読まれると、かなりいろいろ分かってくると思いますよ^^ > > > 入門本に掲載されているSELECT文だけで割りと何とかなっ > てきたので、もう少し勉強してみなければなりませんね。 > > >> #カラム名がたまたまみんな「name」になってしまったので、 >> #必要に応じて適宜別名をつけてください^^; > > こんな↓感じでよろしかったでしょうか。 > > SELECT kumi.name AS "組名", enji.name AS "氏名", kuda1.name AS "好きな果物1", > kuda2.name AS "好きな果物2", kuda3.name AS "好きな果物3" > FROM kumi > LEFT OUTER JOIN enji ON ( enji.kumi = kumi.no ) > LEFT OUTER JOIN kuda kuda1 ON ( enji.kuda1 = kuda1.no ) > LEFT OUTER JOIN kuda kuda2 ON ( enji.kuda2 = kuda2.no ) > LEFT OUTER JOIN kuda kuda3 ON ( enji.kuda3 = kuda3.no ) > > ほぼこのまま、本番環境に適用させていただきます。 > 丁寧な解説、大変ありがとうございました。
14819 2009-05-06 13:16 [naya <SNA02388@xxxxx] 【初歩的質問】 テーブルを結合するSQL文 14820 2009-05-06 13:59 ┣[SAKAI Kei <sak2@xxxx] 14823 2009-05-06 14:59 ┃┗[SAKAI Kei <sak2@xxxx] 14824 2009-05-06 20:26 ┃ ┗[naya <SNA02388@xxxxx] 【御礼】 Re: 【初歩的質問】 テーブルを結合するSQL文 -> 14826 2009-05-07 01:18 ┃ ┗["Kaname Kuji\(Y7\)" ] 【蛇足】Re: 【御礼】 Re: 【初歩的質問】 テーブルを結合するSQL文 14825 2009-05-07 00:55 ┗["F.Yamazaki" <fumihi] SQL文、お知恵を拝借させてください 14827 2009-05-07 02:07 ┣[あきら <akirainfoml@] 14829 2009-05-07 02:48 ┃┗["F.Yamazaki" <fumihi] 14830 2009-05-07 11:07 ┃ ┗["Kaname Kuji\(Y7\)" ] 14834 2009-05-07 20:09 ┃ ┗[あきら <akirainfoml@] 14828 2009-05-07 02:12 ┗[とみたまさひろ <tomm]