PHP×MYSQLでselect文がわからないためご教授願います。


SELECT * FROM tableA WHERE code = 7
というSQLで以下のように表示されるのですが、
例)
id , code , name , date , 売上
1 , 7 , りんご , 2010-01-12 , 350
1 , 7 , りんご , 2010-01-07 , 250
2 , 7 , みかん , 2010-01-12 , 450
2 , 7 , みかん , 2009-05-05 , 550

それを、売上があった日の1営業日後と3営業日後のそれぞれのidの価格も取得したいと考えております。
例)
id , code , name , date , 売上 , 1営業日後売上 , 3営業日後売上
1 , 7 , りんご , 2010-01-12 , 350 , 200 , 500
1 , 7 , りんご , 2010-01-07 , 250 , 200 , 250
2 , 7 , みかん , 2010-01-10 , 450 , 500 , 300
2 , 7 , みかん , 2009-05-05 , 550 , 220 , 350

ちなみにdateはUNIXTIMEにてintでMYSQLに格納してあります。
1営業日後にしているのは、休日の関係で1日後とできないからです。

回答の条件
  • 1人3回まで
  • 登録:
  • 終了:2010/01/27 05:21:01
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:kn1967 No.3

回答回数2915ベストアンサー獲得回数301

ポイント43pt

SQLの組み方は他のテーブルとの絡みがあるので、これが適しているとまでは申せませんが、

サブクエリを使った簡素な例を投稿させていただきます。

http://dev.mysql.com/doc/refman/5.1/ja/scalar-subqueries.html

SELECT T1.id, T1.code, T1.name, T1.date, T1.売上
  ,(SELECT 売上 FROM tableA T2
    WHERE T2.id = T1.id AND T2.code = T1.code AND T2.date > T1.date
    ORDER BY date LIMIT 1,1
  ) AS 1営業日後売上
  ,(SELECT 売上 FROM tableA T3
    WHERE T2.id = T1.id AND T2.code = T1.code AND T2.date > T1.date
    ORDER BY date LIMIT 3,1
  ) AS 3営業日後売上
FROM tableA T1
WHERE T1.code = 7
;

※ id + code + dateでレコードがユニーク(レコードを特定できる)だと仮定。

※ スミマセンが動作確認はせず、いきなり書いてます。

はてなに対する熱意が無くなって久しいのですが、久方ぶりに覗いて見ると、

あいも変わらず私の使ったフレーズを使いまわして、回答を含まないどころか、

勝手に休日に拘った頓珍漢な投稿を繰り返しているコマッたちゃんが

出張っているようなので、ちょっと懲らしめたくなり一時的に復帰してきました(爆!)

id:dekapurio

返信どうも有り難うございます。

うまくいきました!

拙い文章にもかかわらず理解して頂き感謝しています。

2010/01/26 02:42:03

その他の回答3件)

id:km1967 No.1

回答回数541ベストアンサー獲得回数40

ポイント5pt

まずはお願いなのですが、

「営業日」の定義が土日以外ではなく定休日や祝祭日も含むかどうか

わらないと回答することは難しくなりますので、必須だとご記憶ください。

不適当な回答が集まっても混乱をきたしますから、私への返信欄か、

あるいは、コメント欄を開く設定に変更してコメント欄)に、

書き加えておくことを勧めます。

id:dekapurio

情報不足で申し訳ないです。

>>「営業日」の定義が土日以外ではなく定休日や祝祭日も含むかどうか

実際のデータは株式市場を前提としているため、「土日と祝祭日以外」ということになります。

また、MYSQL 5.1 PHP 5.2という環境です。

2010/01/24 19:56:34
id:km1967 No.2

回答回数541ベストアンサー獲得回数40

ポイント2pt

>実際のデータは株式市場を前提としているため

それだと、12月31日や1月2・3日も除く必要があるのではないですか?


いずれにしても休日テーブルを別途設ける必要がありますが、MySQL側のデータ型を変更できないのでは、どうにもなりませんね。

id:dekapurio

>>12月31日や1月2・3日も除く必要があるのではないですか?

そうですね。年末年始も市場は開いてませんでした^^;

ただ、株式市場が開いて無い日はデータ自体も無いので、

1営業日後のデータがほしい場合、

id , code , name , date , 売上

1 , 7 , りんご , 1263222000 , 350

の「1263222000」の数値より大きく、一番近いデータの売上の数値がわかればいいのですが。

同じように、該当日より大きく、一番近いデータを5件取得できれば、1営業日~5営業日までの数値も取得できるというイメージです。

厳しいですかね?

2010/01/25 02:07:02
id:kn1967 No.3

回答回数2915ベストアンサー獲得回数301ここでベストアンサー

ポイント43pt

SQLの組み方は他のテーブルとの絡みがあるので、これが適しているとまでは申せませんが、

サブクエリを使った簡素な例を投稿させていただきます。

http://dev.mysql.com/doc/refman/5.1/ja/scalar-subqueries.html

SELECT T1.id, T1.code, T1.name, T1.date, T1.売上
  ,(SELECT 売上 FROM tableA T2
    WHERE T2.id = T1.id AND T2.code = T1.code AND T2.date > T1.date
    ORDER BY date LIMIT 1,1
  ) AS 1営業日後売上
  ,(SELECT 売上 FROM tableA T3
    WHERE T2.id = T1.id AND T2.code = T1.code AND T2.date > T1.date
    ORDER BY date LIMIT 3,1
  ) AS 3営業日後売上
FROM tableA T1
WHERE T1.code = 7
;

※ id + code + dateでレコードがユニーク(レコードを特定できる)だと仮定。

※ スミマセンが動作確認はせず、いきなり書いてます。

はてなに対する熱意が無くなって久しいのですが、久方ぶりに覗いて見ると、

あいも変わらず私の使ったフレーズを使いまわして、回答を含まないどころか、

勝手に休日に拘った頓珍漢な投稿を繰り返しているコマッたちゃんが

出張っているようなので、ちょっと懲らしめたくなり一時的に復帰してきました(爆!)

id:dekapurio

返信どうも有り難うございます。

うまくいきました!

拙い文章にもかかわらず理解して頂き感謝しています。

2010/01/26 02:42:03
id:kn1967 No.4

回答回数2915ベストアンサー獲得回数301

ポイント40pt

書き方はいろいろあるけど、こんな感じ。

$sqlStr = 'SQLはここに書く';
if (!$result = mysql_query($sqlStr)) {
    echo 'SQLの実行失敗';
} else {
    $sum = array(0, 0, 0);
    echo '<table>';
    echo '<th>id</th><th>code</th><th>name</th><th>date</th><th>売上</th><th>1営業日後売上</th><th>3営業日後売上  </th>';
    while($row = mysql_fetch_row($result)){
        echo '<tr>';
        echo '<td>' . $row[0] . '</td>';
        echo '<td>' . $row[1] . '</td>';
        echo '<td>' . $row[2] . '</td>';
        echo '<td>' . $row[3] . '</td>';
        echo '<td>' . $row[4] . '</td>';
        echo '<td>' . $row[5] . '</td>';
        echo '<td>' . $row[6] . '</td>';
        echo '</tr>';
        $sum[0] += $row[4];
        $sum[1] += $row[5];
        $sum[2] += $row[6];
    }
    echo '<tr>';
    echo '<td colospan="4">トータル</td>';
    echo '<td>' . $sum[0] . '</td>';
    echo '<td>' . $sum[1] . '</td>';
    echo '<td>' . $sum[2] . '</td>';
    echo '</tr>';
    echo '</table>';
}

※PostgreSQL中心のため、MySQLのほうの実行環境が今はなく、

 今回もノーチェックで失礼します。

id:dekapurio

当方初心者ですが、すごくわかりやすく書いて頂いて感謝です。

わたしの場合、コードがぐちゃぐちゃで偶然出来てしまっただけなので、こちらに書き換えたいと思います。

  1. = とか 配列への入れ方などこれだけでも勉強になります。
2010/01/27 03:22:57
  • id:Mook
    テーブルの設計に関してのみなので、コメントで失礼します。
    DB を使うのであれば、DB の提供している日付・時間型を使用したほうが処理が柔軟(高速)にできますよ。
  • id:dekapurio
    外注にて全ておまかせでプログラムを作ってもらったのですが、製作者がint型で格納したほうが良い(処理が高速)という事で、
    unixtimeのint型で格納してあります。
    DBにはもう大量のデータが入ってしまっているため、もう変更出来ないんです・・・
  • id:chuken_kenkou
    どの列で、行を一意に識別できるのでしょう?

    1営業日後、3営業日後のデータが存在しなかった場合は、nullで返せばいいのですか?
  • id:dekapurio
    >>どの列で、行を一意に識別できるのでしょう?
    ごめんなさい。初心者ですのでちょっと意味がわからないです。
    >>1営業日後、3営業日後のデータが存在しなかった場合は、nullで返せばいいのですか?
    そうですね。データが存在しなかった場合は、「-----」みたいな形で表示したいです。
  • id:kn1967
    >一意に識別

    回答3でも書きましたが、
    id + code + date でユニーク(一意)であるとすれば、
    1,7, 2010-01-12 を含むレコードは常に1件(もしくはゼロ件)だけであり、
      1, 7 , りんご , 2010-01-12 , 350
    上記と平行して下記のようなものが同時に存在したりは出来ない。
      1, 7 , りんご , 2010-01-12 , 100
      1, 7 , りんご , 2010-01-12 , 200
    といったような事です。

    (訂正)
    3営業日後のほうは
    WHERE T3.id = T1.id AND T3.code = T1.code AND T3.date > T1.date
    との間違いです。

    (余談)
    既にお気づきかと思いますが回答1/2と回答3は別人です。
  • id:dekapurio
    うまくいきました。有難うございます。

    >一意に識別
    なるほど。よくわかりました。

    >訂正
    それと、limit区が0,1 と 2,1を訂正することで、わたしが理想としていたことが出来るようになりました。(感動)

    >既にお気づきかと思いますが回答1/2と回答3は別人です。
    たまたまHNが似てしまったんですかね?
    はてなをはじめて利用するのでその辺の事情はよくわかりませんが、返信くださった方々に改めて御礼を申し上げます。
  • id:dekapurio
    追加で質問なのですが、

    id , code , name , date , 売上 , 1営業日後売上 , 3営業日後売上
    1 , 7 , りんご , 2010-01-12 , 350 , 200 , 500
    1 , 7 , りんご , 2010-01-07 , 250 , 200 , 250
    2 , 7 , みかん , 2010-01-10 , 450 , 500 , 300
    2 , 7 , みかん , 2009-05-05 , 550 , 220 , 350
    トータル          1600 , 1120 , 1400

    のように一番下にトータルを表示したい場合、どうすべきでしょう?

    恐らくPHPのプログラム側でどうにかするんでしょうが、やり方がわからなかったのでご教授願います。
  • id:kn1967
    SQLだけで、集計して、連結するという方法もありますが、
    MySQLの場合は、回答3を2回実行するようなイメージになるため、
    動作コストが高くつき、集計する項目が少ない場合は、
    php側で処理するほうがよいかもしれません。

    ただし、phpからMySQLを利用する手段はいくつか用意されているため、
    コードをある程度眺めないとあまり具体的な事は言えず、
    ヒントのみとなりますが php のほうで、SQLの結果を受け取る関数
    (mysql_fetch_ で始まる関数)を探してみてください。

    php側の処理の流れとしては、
    受け取った値を順次echoで出力というような形になっているはずですから、
    集計用の変数を用意して、受け取った値を変数に加算していって、
    最後にechoすれば良いでしょう。
  • id:dekapurio
    >集計用の変数を用意して、受け取った値を変数に加算していって、
    >最後にechoすれば良いでしょう。

    このやり方が書籍やネットでだいぶ探したのですが、わからずで・・・この例を回答欄に提示して頂けないでしょうか?
  • id:dekapurio
    自己解決しました。
  • id:dekapurio
    回答のコメントがなんか勝手にリスト表示されてしまいましたが・・・

    1. とか >> += とか
  • id:kn1967
    >勝手にリスト表示
    質問者の書き込む返答欄は、回答受付中であれば、
    何度でも書き換えできたと記憶しているので、よければ試してみてください。

    >+=
    複合演算子 と言います。
    文字列として結合する場合は .= (ピリオド=)になります。

    >コードがぐちゃぐちゃ
    ある程度はしかたの無い事ですね。流れを理解できるようになってくれば、
    多少なりとも直ってきます。とことん綺麗にしたいという事であれば、
    下記のようなスタイルを参考にしても良いでしょう。(長年書いていると、
    自然と下記にあるようなスタイルになってくるものですけどね。)
    http://framework.zend.com/manual/1.10/ja/coding-standard.coding-style.html


    以下、さらに、まったくの余計なお世話ですが・・・、

    まずはphpについて、
    一度、下記の「基本的な構文」から「関数」あたりまでを
    ササッと一通り眺めてみてください。
    (理解は後からでも良いです。気になった単語があれば、
    とりあえずメモしながら、まずは一通り眺めてみてください。)
    http://www.php.net/manual/ja/langref.php

    上記がある程度理解できたら、あとはやりたい事に関係しそうな機能を、
    適宜探す事になるのですが、その際に役に立つのが書籍です。
    関数リファレンス系の本を1冊はもっておくと、
    必要な関数を調べるのに役立ちます。(ネット検索でも良いですが、
    書籍であれば、暇なときにボーっと眺めて見るなどもできて便利です。
    見易さは人によるので、書店で、自分でチョイスしてください。)
    (適当なチョイスばかり回答投稿してくる輩が多いので、ハテナで
    「お勧めを教えてください」的な質問はしないほうがいいと思う。)

    リファレンス系の書籍とあわせて、下記の search for 欄から検索して、
    最新情報を得るなども、平行して行うと、なお良いでしょう。
    http://www.php.net/manual/ja/
    さらに、公開したいようなものであれば上記のセキュリティ関連にも、
    目を通して、理解、そして対応が必要になるでしょう。

    次に、MySQLですが、入門系の書籍は沢山出てるようですが、
    MySQLの使い方に終始していて、そもそも「データベースとは何か?」
    についてはあまり触れられていないようなので、
    MySQLの入門本を読む前に「データベース概論」的なタイトルの本を、
    出来れば読んでおくことをお勧めしたいです。
    「データベースとは何か?」が理解できれば、MySQLだろうと、
    PostgreSQLだろうとORACLEだろうとSQLServerだろうとDB2・・・以下略。
    ぶっちゃけ、何が来ても怖くないです(笑)

    うだうだと書きましたが、どこまで必要になってくるかは人それぞれ、
    とりあえずphpとMySQLという二つのものを使っているのだという意識だけは、
    常に忘れないようにしてください。それぞれ年単位の時間を要しますので
    あせらず1つ1つ理解していくという姿勢もお忘れなく・・・。


    P.S.
    集計結果が出るようになったら、質問は終了しておいてくださいね。
    くれぐれもエサを与えないように・・・。
  • id:dekapurio
    集計結果、出るようになりましたよ!
    お世話になりました。

    PHP×MYSQL本を1冊買ってやってはいるものの、どうしても使わなそうなものは読み飛ばしたりで・・

    書籍のサンプルは単純な数字を使ってのものなので、実際のwhileの中で処理したり、変数や配列が関係してくると頭が混乱してしまって^^;
    この辺りは馴れですよね。

    まずは基本から復習することにします。
    どこかの記事で、掲示板を1から作ると力がつくとあったので、それを作成してみようかと思っています。

    質問から横道にそれましたが無事、集計までできるようになりましたので〆させて頂きます。
    kn1967さま、また返信くださった方々にお礼を申し上げます。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません