• ベストアンサー
  • 暇なときにでも

LEFT JOINを多用するのはよくないですか?

PHP4+MySQL4.0 http://oshiete1.goo.ne.jp/kotaeru.php3?q=2085277 の続きなのですが、同質問にご回答下さったsaintandreさんのSQL例文を 拡張して、下記のように2年分(24か月=24行)をLEFT JOINしようとしたら、 phpMyAdmin上でSQL文を発行しても結果がなかなか返ってこなかったり PHP4で簡単なHTMLリストを書き出すプログラムをIE6上で実行しても 途中で「ページがみつかりません」になったりで、結果が得られないことの方が 多いです。SQL文1本で強引に解決することはあきらめたほうがよいでしょうか。 画期的な解決策がもしあればご教示ください。 SELECT `社員マスター`.`社員ID` AS `名前ID` ,`社員マスター`.`名前` AS `名前` ,`社員マスター`.`性別` AS `性別` ,`出席日数200601`.`出席日数` AS `出席日数200601` ,`出席日数200602`.`出席日数` AS `出席日数200602`    :  (…途中20か月分・略…)    : ,`出席日数200611`.`出席日数` AS `出席日数200611` ,`出席日数200712`.`出席日数` AS `出席日数200712` FROM `社員マスター` LEFT JOIN `出席テーブル` AS `出席日数200601` ON `社員マスター`.`社員ID` = `出席日数200601`.`社員ID` AND `出席日数200601`.`年月` = '200601' LEFT JOIN `出席テーブル` AS `出席日数200602` ON `社員マスター`.`社員ID` = `出席日数200602`.`社員ID` AND `出席日数200602`.`年月` = '200602'    :  (…途中20か月分・略…)    : LEFT JOIN `出席テーブル` AS `出席日数200711` ON `社員マスター`.`社員ID` = `出席日数200711`.`社員ID` AND `出席日数200711`.`年月` = '200711' LEFT JOIN `出席テーブル` AS `出席日数200712` ON `社員マスター`.`社員ID` = `出席日数200712`.`社員ID` AND `出席日数200712`.`年月` = '200712'

共感・応援の気持ちを伝えよう!

  • 回答数3
  • 閲覧数401
  • ありがとう数4

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

  • ベストアンサー
  • 回答No.3
  • yambejp
  • ベストアンサー率51% (3827/7415)

こんな感じでわかりますか? <?PHP $link=mysql_connect('host','user','pass'); mysql_select_db('db',$link); $max=24; for($i=0;$i<$max;$i++){ $m[]=date("Ym",mktime(0,0,0,1+$i,1,2006)); } $sql="CREATE TEMPORARY TABLE `TEMP_PIVOD` (`年月` VARCHAR(6),"; foreach ($m as $key=>$val){ $sql.=($key==0?"":",")."`$val` INT"; } $sql.=");"; $res=mysql_query($sql,$link); $sql="INSERT INTO `TEMP_PIVOD` VALUES"; foreach ($m as $key=>$val){ $sql.=($key==0)?"":","; $sql.="('$val'"; for($i=0;$i<$max;$i++){ $sql.=",".($key==$i?"1":"0"); } $sql.=")"; } $res=mysql_query($sql,$link); $sql=<<<eof SELECT `社員マスター`.`社員ID` AS `名前ID` ,`社員マスター`.`名前` AS `名前` ,`社員マスター`.`性別` AS `性別` eof; foreach ($m as $key=>$val){ $sql.=",SUM(`$val`*`出席日数`) AS `出席日数{$val}`"; } $sql.=<<<eof FROM `社員マスター` INNER JOIN `出席テーブル` ON `社員マスター`.`社員ID`=`出席テーブル`.`社員ID` INNER JOIN `TEMP_PIVOD` ON `TEMP_PIVOD`.`年月`=`出席テーブル`.`年月` GROUP BY `名前` ORDER BY `名前ID` eof; $res=mysql_query($sql,$link); print "<table border>"; while($rows = mysql_fetch_array($res,MYSQL_ASSOC)){ print "<tr>"; foreach ($rows as $key=>$val){ print "<td>$val</td>"; } print "</tr>"; } print "</table>"; ?>

共感・感謝の気持ちを伝えよう!

質問者からのお礼

yamabejpさん、いつもプログラムによるご提示、本当にありがとうございます。 また、(毎度のことながら)御礼が遅くなって大変失礼しました。 今日、ようやくじっくり取り組む時間が得られたのですが 実はforeachとか非常に苦手としているところで、 ご提示のSQLもcreate文、insert文、select文と3段構えなので 一つ一つPRINTしてようやく構造がつかめてきたところです。 #2さんのSQLも参考にしながら、yamabejpさんのものを 本番に適用している最中ですが、またわからないことがあったら是非ご教示 よろしくお願い致します。 ありがとうございました。

関連するQ&A

  • 少し複雑な left join

    まだデーターベースを独学で始めて数ヶ月の初心者です。 以下(3行目のleft join)の記述では動かないのですが、どのように 記述したらよいのでしょうか? やりたい内容は3行目にあるようにbookedというテーブルの中のdateが 2013-06-05だけ抽出した形のテーブルを、timeTplというテーブルとleft join させたいです。 1 "select * 2 from 3 timeTpl as t left join (SELECT * FROM booked where date ="2013-06-05") as b 4 on 5 t.start >= b.startTime and t.start < b.finishTime || 6 t.finish > b.startTime and t.finish <= b.finishTime 7 where 8 t.time > 9 (select start 10 from class as c left join member as m 11 on c.className = m.class 12 where m.name = '$name') 13 ) 14 "; よろしくお願いします。

  • LEFT JOINの使い方

    linkテーブルとcommentテーブルがあります。 下記のようなSQLをPHPから発行すると、 select c.id AS cid, c.pid AS cpid, c.name AS cname, l.id AS id, l.url AS url from comment AS c LEFT JOIN link AS l ON c.pid=l.id order by c.id desc LIMIT 0, 10; $rec['cid'] や $rec['cname'] にはデータがあるのですが $rec['id'] や $rec['url'] にはデータが入っておらずNULLになってしまいます。 ためしに LEFT JOINの左右を下記のように入れ替えみたところ、 select c.id AS cid, c.pid AS cpid, c.name AS cname, l.id AS id, l.url AS url from link AS l JOIN comment AS c LEFT ON c.pid=l.id order by c.id desc LIMIT 0, 10; 今度は $rec['id'] や $rec['url'] にはデータがあるのですが $rec['cid'] や $rec['cname'] にはデータが入っておらずNULLになってしまいました。 どこがおかしいのでしょうか? MYSQLは5.1.22-rcでレンタルサーバーはcoreserverを利用しています。

    • ベストアンサー
    • MySQL
  • SQL LEFT JOIN

    SQLでわからないことがあるので質問させていただきます。 例えばの話ですが在庫テーブルというテーブルがあってそこに商品マスタ をLEFT JOINする際に SELECT *  FROM 在庫テーブル LEFT JOIN 商品マスタ ON 品番 = 品番 として実行すると返ってくる結果は在庫テーブルの全レコードと 品番で結んだ商品マスタに存在するデータってことですか? 上記のSQLと SELECT * FROM 在庫テーブル で返ってくるレコード件数が違うという時はどういう可能性が考えられるでしょうか? ちなみに商品マスタの品番レコードはすべてユニークになっていて 色やサイズで品番が複数存在するものではありません。 何回やってもレコード件数が前者のほうが多くなってしまいます。 分かる方がいらしたらぜひ教えていただきたいです。

その他の回答 (2)

  • 回答No.2

ジョインするのは、社員IDから名前を変換する1回だけでいいですね。 =====以下、テスト用の表定義&データ===== create table 社員マスター (社員ID int primary key, 名前 varchar(8), 性別 tinyint); insert into 社員マスター values (1,'鈴木',1), (2,'佐藤',1), (3,'山本',2); create table 出席テーブル (社員ID int, 年月 char(6), 出席日数 smallint, primary key(社員ID,年月)); insert into 出席テーブル values (1,'200601',3), (1,'200602',4), (1,'200603',5), (2,'200601',10), (2,'200602',11), (2,'200603',12), (3,'200601',7), (3,'200602',8), (3,'200603',9); =====ここまで===== MySQL 4.1以降なら、次のように書け簡単なのですが。。。 select x.社員ID AS 名前ID, 名前, 性別, 出席日数200601, 出席日数200602, 出席日数200603 from 社員マスター as x, ( select 社員ID, ifnull(sum(case 年月 when '200601' then 出席日数 end),0) as 出席日数200601, ifnull(sum(case 年月 when '200602' then 出席日数 end),0) as 出席日数200602, ifnull(sum(case 年月 when '200603' then 出席日数 end),0) as 出席日数200603 from 出席テーブル group by 社員ID ) as y where x.社員ID=y.社員ID ; MySQL 4.0とのことなので、出席テーブルの検索結果を一時表に格納して利用する方法を示します。 create temporary table if not exists w出席テーブル (社員ID int, 出席日数200601 smallint, 出席日数200602 smallint, 出席日数200603 smallint); truncate table w出席テーブル; insert into w出席テーブル select 社員ID, ifnull(sum(case 年月 when '200601' then 出席日数 end),0), ifnull(sum(case 年月 when '200602' then 出席日数 end),0), ifnull(sum(case 年月 when '200603' then 出席日数 end),0) from 出席テーブル group by 社員ID; select x.社員ID AS 名前ID, 名前, 性別, 出席日数200601, 出席日数200602, 出席日数200603 from 社員マスター as x,w出席テーブル as y where x.社員ID=y.社員ID order by x.社員ID ;

共感・感謝の気持ちを伝えよう!

質問者からのお礼

chukenkenkouさん、整然としたSQLのご提示ありがとうございました。 別の仕事からようやく本件に戻ってきました。 とりあえず、ご提示のTEMPテーブルで解決する方法を検討しているところです。 またわからないことがあれば、是非ご教示ください。 ちなみに、わたしもMySQL 4.1以降にして欲しかったのですが、 システム開発当初にphpmyadminとの日本語の扱いの親和性などの 問題にバージョンダウンにせざるをえなかったのだそうです(開発者・談) 古いものだといろいろ不便ですね。。。

  • 回答No.1
  • yambejp
  • ベストアンサー率51% (3827/7415)

その手のケースはピボッドテーブルをご利用になると 効果があるかと思います。 あらかじめ用意しておいてもいいですし、テンポラリーで つどつど作成するのでもかまいません。 実例ですと以下の感じになります。 CREATE TABLE `社員マスター` (`社員ID` VARCHAR(4) PRIMARY KEY,`名前` VARCHAR(30),`性別` INT); INSERT INTO `社員マスター` VALUES('0001','田中一郎',1),('0002','鈴木太郎',1),('0003','佐藤花子',2); CREATE TABLE `出席テーブル`(`年月` VARCHAR(6),`社員ID` VARCHAR(4),`出席日数` INT); INSERT INTO `出席テーブル` VALUES ('200601','0001',3) ,('200602','0001',5) ,('200603','0001',2) ,('200604','0001',6) ,('200605','0001',7) ,('200606','0001',1) ,('200601','0002',2) ,('200602','0002',4) ,('200604','0002',7) ,('200606','0002',2) ,('200602','0003',3) ,('200603','0003',3) ,('200604','0003',2) ,('200605','0003',1) ,('200606','0003',1); CREATE TEMPORARY TABLE `TEMP_PIVOD` (`年月` VARCHAR(6),`200601` INT,`200602` INT,`200603` INT,`200604` INT,`200605` INT,`200606` INT); INSERT INTO `TEMP_PIVOD` VALUES ('200601',1,0,0,0,0,0) ,('200602',0,1,0,0,0,0) ,('200603',0,0,1,0,0,0) ,('200604',0,0,0,1,0,0) ,('200605',0,0,0,0,1,0) ,('200606',0,0,0,0,0,1); SELECT `社員マスター`.`社員ID` AS `名前ID` ,`社員マスター`.`名前` AS `名前` ,`社員マスター`.`性別` AS `性別` ,SUM(`200601`*`出席日数`) AS `出席日数200601` ,SUM(`200602`*`出席日数`) AS `出席日数200602` ,SUM(`200603`*`出席日数`) AS `出席日数200603` ,SUM(`200604`*`出席日数`) AS `出席日数200604` ,SUM(`200605`*`出席日数`) AS `出席日数200605` ,SUM(`200606`*`出席日数`) AS `出席日数200606` FROM `社員マスター` INNER JOIN `出席テーブル` ON `社員マスター`.`社員ID`=`出席テーブル`.`社員ID` INNER JOIN `TEMP_PIVOD` ON `TEMP_PIVOD`.`年月`=`出席テーブル`.`年月` GROUP BY `名前` ORDER BY `名前ID`

共感・感謝の気持ちを伝えよう!

質問者からのお礼

yamabejpさん、いつもわかりやすい実例でご教示いただきありがとうございます。 理想(最終目的)としては、いくつかのテーブルをExcelで加工しやすいように くっつけることで(今までは各テーブル別にCSVをエクスポートして、Excel上で くっつけてていた)CSVを出力するたびに同じ加工するのに辟易して今回の計画を 思いつきました。表のサイズとしては、60列×2500行程度の大きさとなります。 で、最終目標は、 (1) 検索フォーム http://example.com/export.php を開いて (2) 検索条件を設定して(性別チェックボックスとか、社員ID○以上○以下とか) (3) 検索ボタンを押下すると、list.php(1社員=1行のHTMLリスト)を吐き出すとか、   あるいはCSV出力ボタンを押下したなら、CSV保存ダイアログが出る、   そんなイメージです。 さて、ご教授のように都合のよい順序に整列加工し、フォーマットも整えた テンポラリ・テーブルを設ければ(後は単純に「SELECT * FROM MYTABLE」だけで HTMLリストやCSVを出力できそうだし)大変効率はよいだろうと思います。 示していただいた実例のSQL文(CREATE TABLE `社員マスター`.....から ORDER BY `名前ID`  .....まで)は、list.phpに仕込んでおく、そういう意味 でしょうか?

関連するQ&A

  • LEFT JOINが2つあるSQL文でANDの意味

    ■下記SQL文の意味を教えてください SELECT a.*, b.being_name FROM alive a  LEFT JOIN being b ON a.hoge_id = b.id  LEFT JOIN call c ON c.call_id = a.hoge_id   AND f.hoge_id = 12  WHERE f.hoge_id = 12 OR b.id = 12 ※12の部分は動的に切り替わります ・LEFT JOINが2つあるので、3つのテーブルを結合しているのでしょうか? ・左テーブルは「alive a」で、この右側に2つのテーブルが結合している、という認識でよいでしょうか? >SELECT フィールド名 FROM テーブル名 WHERE 条件式1 AND 条件式2 >「AND」は2つの条件式の論理積 ・上記内容をネットで見かけたのですが、「AND」は、「WHERE」の前に来てもいいのでしょうか? それともこのSQLの「AND」は違う使い方をしているのでしょうか? 何か、LEFT JOINに関係しているのでしょうか?

    • ベストアンサー
    • MySQL
  • どちらのLEFT JOINが早いでしょうか?

    下記2つのテーブルがあったとします。 ・大テーブルA 7000万件 ・小テーブルB 2000件(※現在はWHERE句で指定すると1件) をJOINする場合、下記のどちらの方法が望ましいでしょうか? 案1)子テーブルを親とする方法 テーブルA(ON句により1件~2000件) LEFT JOIN 7000万件のテーブルB 案2)親テーブルを子とする方法 7000万件のテーブルB LEFT JOIN テーブルA(ON句により1件~2000件) 又、LEFT JOINの、ON句で条件を絞るのと、 WHERE句で条件を絞るのではどちらが好ましいでしょうか?

    • ベストアンサー
    • MySQL
  • MySQLでLEFT JOIN

    MySQL4.0.26でテーブルの左外部結合がしたいです。 左テーブルAと 右テーブルBをWHERE句で抽出したもの を結合することはできないのでしょうか? 考えた以下の式ではエラーが出てしまいます。 SELECT * FROM A LEFT JOIN ( SELECT * B WHERE id = 1 ) AS B2 ON A.id = B2.id

    • ベストアンサー
    • MySQL
  • LEFT JOINとRIGHT JOINについて

    SQL初心者です。 基本的な質問ですみません、教えてください。 LEFT JOINとRIGHT JOINについて、どちらのテーブルを左側、どちらのテーブルを右側にするのかが分かっていません。どういう基準で左側、どういう基準で右側と考えれてばいいのでしょうか? 宜しくお願いします。

  • sql(left join)の結合条件のルール

    (テーブルA)と(テーブルB)をleft joinした際の結合条件について 詳しい方に伺いたいのですが、 on以下の部分は、(テーブルAの中にあるカラム)と(テーブルBの中にあるカラム)を 比較するような文でなければいけないですか? 例えば、、、 ------------------------------------------------------------------------- SELECT * FROM  timeTpl2 AS t LEFT JOIN booked AS b ON  t.start = b.startTime AND  b.settingDay = $day ------------------------------------------------------------------------- 上記の最後の部分(b.settingDay = $day)は テーブルbにしかない要素を変数($day)と比較しています。 ◆疑問 記述としてだいじょうぶかどうかを知りたいです。 つまりon以下結合条件は必ず左右のテーブルの、存在するカラム のみしか比較する事ができないかどうかが知りたいです。 よろしくお願いします。

    • ベストアンサー
    • MySQL
  • access vba での left join について

    お世話になります。 accessで下記SQLを実行し、リストボックスにデータを 表示したいのですが、何故かデータを表示してくれ ません。 lst表.RowSource = "select A.1, A.2, B.1 from A Left Join B On A.3 = iNum And (A.4 = B.4 And A.5 = B.5)" SQLについてはあまり詳しくないのですが、 どこが間違えているのか、おわかりのかたが おられましたら、よろしくお願いいたします。

  • LEFT JOIN について

    table a ------ user_id ------ user1 user2 user3 user4 user5 ------ table b --------------- user_id role_id --------------- user1 role1 user2 role1 user3 role1 user2 role2 user4 role2 --------------- とします。 1つのSQL文で、a のすべてのユーザそれぞれが指定role_id に属しているかどうかを検索したいです。 例えば、すべてのユーザそれぞれが role1 に属しているかどうかを検索します。 欲しい結果は以下の通りです。 ------------ user1 true user2 true user3 true user4 false user5 false ------------ LEFT JOIN だと思いますが、うまくいきません。 SELECT a.user_id, b.role_id FROM a LEFT JOIN b ON a.user_id = b.user_id WHERE b.role_id='role1'; 結果は以下になります。 ------------ user1 role1 user2 role1 user3 role1 ------------ #Whereで絞って、当然の結果です SQLをどうかければよいでしょうか。 よろしくお願いします。

    • ベストアンサー
    • MySQL
  • LEFT JOINの記述の仕方について

    お世話になっております。 LEFT JOINの記述の仕方でご確認したい事があります。 ご教授頂けますようお願いいたします。 【ご質問内容】 以下のようなSQLをLEFT JOINを使用して記述する場合、 どのように記述すればよろしいのでしょうか? SELECT A.* FROM A B C WHERE A.COLUMN1 = B.COLUMN1 AND B.COLUMN2 = C.COLUMN2(+) AND B.COLUMN3 = C.COLUMN3(+) AND A.COLUMN4 = C.COLUMN4(+) ;

  • mysqlでJOIN文

    関係有りそうな部分だけ抜粋します。 mysqlで外部キーを設定して、 下記のようなSQLを実行してみましたが、 #1066 - Not unique table/alias: 'tie_up'と エラーメッセージが表示されました。 何がおかしいのでしょうか? 外部キーは「song」テーブルの「tie_up_1_ID」、同「song」テーブルの「tie_up_2_ID」、 それと「tie_up」テーブルの「tie_up」です。 SQLを触るの5年振りなんで・・・。 SELECT * FROM ((((( song left JOIN kashu ON song.kashu_ID = kashu.kashu_ID) left JOIN sakushi ON song.sakushi_ID = sakushi.sakushi_ID) left JOIN sakkyoku ON song.sakkyoku_ID = sakkyoku.sakkyoku_ID) left JOIN hennkyoku ON song.hennkyoku_ID = hennkyoku.hennkyoku_ID) left JOIN tie_up ON song.tie_up_1_ID = tie_up.tie_up_ID) left JOIN tie_up ON song.tie_up_2_ID = tie_up.tie_up_ID;

    • ベストアンサー
    • MySQL
  • MySQLのLEFT JOINについて

    LEFT JOINを使ったMySQLに挑戦しています。 テーブルとテーブルを照らしあわせ、右側のテーブルに優先的に表示する方法ですが、1つのテーブルと1つのテーブルではなく1つのテーブルに対して複数のテーブルと照合する方法とはあるのでしょうか? どうかおしえていただけないでしょうか? 下記に作成中のソースを示します。 宜しくお願いします。 $STRSQL=qq{SELECT }; $STRSQL=$STRSQL.qq{kyu_table.iput_charg_id,k_data_m_table.iput_charg_id }; $STRSQL=$STRSQL.qq{FROM k_data_m_table LEFT JOIN kyu_table ON k_data_m_table.iput_charg_id = kyu_table.iput_charg_id }; $STRSQL=$STRSQL.qq{WHERE k_data_m_table.iput_charg_id = "$KYU" };