文字列カラムに対してループを回す

このQ&Aのポイント
  • 質問文章の要点は、日付@文字列カラムに対してループを回す上での効率的な方法についてです。
  • 現在の方法は、ループで日付変数を生成し、LIKE検索を行っていますが、他の方法があるか検討したいとのことです。
  • プロの方々はどのような方法を取るのか、またそれが実行速度にどのような影響を与えるのかについてアドバイスを求めています。
回答を見る
  • ベストアンサー

【意見募集】文字列カラムに対してループを回す

作る時にちゃんと考えれば良かったのですが、、、 日付@文字列カラム(yyyy/mm/dd hh:ss:mm)に対して、 集計作業をするために、PHPでループさせ、 SQL文を発行し結果を取得しています。 ループ内の処理が軽いうちや、 ループ回数が少ないうちは、実行結果表示までの速度が、 気にならないのですが、出来ればもっと簡潔に書き、 処理が増えた時でも遅くならないようにしておきたいと思いまして・・・。 調べた限りでは、出来ないようですが、 IN句を使って、LIKE検索のようなことが出来れば、 ループを無くして、より早く結果が取得出来るかと思うのですが、 このような場合、プロの方はどのようなコードを書かれるのでしょうか? 環境は、 ----------- mysql:5.0.77 php :5.1.6 ----------- 現状は、 -------------------------------- SELECT * FROM `order` WHERE `time` LIKE '[日付変数]%' -------------------------------- というようなSQL文をループを回して発行し、 都度返り値を配列に入れ、表示しています。 サンプルコードは以下、 -------------------------------- //日付の取得処理 $start_day = $_REQUEST['start_day']; $end_day = $_REQUEST['end_day']; //日付の間隔取得 $day_span = ( (strtotime($start_day)-strtotime($end_day) ) / 86400 ) +1; //集計値配列セット $counts = array(); //集計値取得 for($a = 0; $a < $day_span ; $a++) {   //日付変数   $days = date( "Y/m/d",strtotime($start_day) + (86400 * $a) );   //SQL文生成   $GET_Query = "     SELECT count(*)     FROM `order`     WHERE time = LIKE '$days%'   ";   //SQL文実行   $res = mysql_fetch_row($GET_Query);   $counts[] = $res[0];   $res = array(); } echo '<pre>'; var_dump($counts); echo '</pre>'; exit(); -------------------------------- 意見をいただきたいのが、 WHERE句に日付@文字列カラム(yyyy/mm/dd hh:ss:mm)の条件を 指定する場合、 -------------------------------- SELECT * FROM `order` WHERE `time` LIKE '[日付変数]%' OR `time` LIKE '[日付変数]%' OR `time` LIKE '[日付変数]%' OR … -------------------------------- -------------------------------- SELECT * FROM `order` WHERE `time` LIKE '[日付変数]%' をループで回す -------------------------------- などとする以外の方法があるか。 また、それは上記より実行速度が早いのかどうか。 についてご意見いただければ幸いです。

  • MySQL
  • 回答数2
  • ありがとう数2

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

  • ベストアンサー
  • mtaka2
  • ベストアンサー率73% (867/1179)
回答No.1

> 処理が増えた時でも遅くならないように そういう目的だったら、 根本的な解決としては、DBを日付型で作りなおすべきです。 DBの構造を作りなおすことが出来ないとか、参照しているプログラム側の改変に手間がかかりすぎる場合、 書き込み(新規レコードの作成)があまり多くなく、読み込み(レコード参照)がメインなら、 「現在の文字列型のとは別に日付型のカラムを追加して、DBに追加両方の形式でデータを入れるようにする」 という方法もあります。 最初に書き込み部は両方のカラムに書き込むよう修正する必要がありますが、参照している部分に関してはとりあえず現状維持でも動きますので、性能が必要な部分については日付型カラムを参照するようにプログラを修正するように、順次対応できます。 そのどちらもできない場合ですが、 文字列型のままでも、「yyyy/mm/dd hh:mm:ss」(各数値は二桁固定)の形式なら、文字列比較で検索可能です。 たとえば、「where time>="2011/01/10 00:00:00" AND time<="2011/01/17 23:59:59"」とすれば、 1月10日~1月17日に該当するレコードが抽出できます。

yuko8320
質問者

お礼

>根本的な解決としては、DBを日付型で作りなおすべきです。 知識が薄いながら大元から直さないとダメだよね。。。 と思ってましたが、やはりそうですよね・・・。 また、難しい場合の対応方法を記載いただきありがとうございました。 >たとえば、「where time>="2011/01/10 00:00:00" AND time<="2011/01/17 23:59:59"」とすれば、 勝手な思い込みでBETWEENは数字のみのカラムしか使えないと思ってました・・・。 テストデータを作って実行速度を比べてみて、 「日付型のカラムを追加」「BETWEENに変更」どのぐらいの差があるのか、 また、差が許容値かどうかを確認してから 教えていただいた方法を実行してみたいと思います。 ありがとうございました!

その他の回答 (1)

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

基本#1と同様ですが日付処理の定番はBETWEENです 日時フィールドをdatetime型でもち BETWEEN 日時フィールド 'XXXX-XX-XX 00:00:00' AND 'YYYY-YY-YY 23:59:59' またさらに効率化を図るのであれば 日付だけ別にもち日付フィールドをdate型にしておけば BETWEEN 日時フィールド 'XXXX-XX-XX' AND 'YYYY-YY-YY' でいけます。

関連するQ&A

  • forで無限ループになっていないかどうか

    各アイテムの最新3件だけデータベースに残したいと思い、下記のようにしてみました。 動作を確認したところ問題なかったのですが、何か(無限ループする可能性があるなど)問題があるようでしたら、ご指摘いただけないでしょうか。 よろしくお願いいたします。 for ($num = 1; $num < 21; $num++){ // アイテムが20件ある場合 $sql = "SELECT COUNT(id) AS cnt FROM item where item_id=$num ;"; $res = mysql_query($sql, $conn) or die; $row = mysql_fetch_array($res, MYSQL_ASSOC); $count = $row["cnt"]; if($count<3){ // アイテムが3件より少なかったら何もしない } else{ $delete_count=$count-3; $sql = "delete from item where item_id=$num order by date limit $delete_count;"; $res = db_query($sql, $conn); } }

    • ベストアンサー
    • PHP
  • ループの仕方

    select文で、まずデータが何件あるかカウントしたあと、 そのカウントした数の分だけ、ループしたいです。 ループに入れ込みたいSQLは以下のような感じです。 1.select 1a,1b from TABLE1 where 条件; 2.select 2a,2b from TABLE2 where 条件; カウントした数の受け渡しとかも、分からないような状態なのですが、 初心者向けに教えていただけないでしょうか。 宜しくお願いします。

  • 条件に合うデータの個数と平均の表示について

    検索条件に合うデータの個数のカウントと、平均を出したいと考えています ーーーーーーーーーーーーーーーーーーーーーーーーーーーーー $sql1 = "select avg(score) from seiseki where name = '$Name' and day like '$Day*'"; $sql2 = "select count(score) from seiseki where name = '$Name' and day like '$Day*'"; $sql3 = "select count(score) from seiseki where name = '$Name' and day like '$Day*' and score = 1"; $res1 = mysql_query($sql1); $res2 = mysql_query($sql2); $res3 = mysql_query($sql3); echo "<table border='1'>"; echo "<tr>"; echo "<td>総数</td>"; echo "<td>{$res2}回</td>"; echo "</tr>"; echo "<tr>"; echo "<td>1の数</td>"; echo "<td>{$res3}回</td>"; echo "</tr>"; echo "<tr>"; echo "<td>平均</td>"; echo "<td>{$res1}</td>"; echo "</tr>"; echo "</table>"; ーーーーーーーーーーーーーーーーーーーーーーーーーーーーー 現在このようなプログラムで検索をかけているのですが、結果が 総数 Resource id #4回 1の数 Resource id #5回 平均 Resource id #3 というような結果が表示され、正しく表示することができません しようと考えています nameは完全一致で、dayは前方一致で検索しようと考えており、両方の条件にあったものを計算します nameにはローマ字で名前が、dayには20110110といったように日付が文字形式で scoreには1~4の数字がINTで記入されています 何か間違いがあるのか、また どのような記述をすればいいのか例などがあれば書いていただきたいです

    • ベストアンサー
    • PHP
  • SELECT 文の NULL列は?

    ある人に、こんなSQLを教えてもらいました。 ----------------------------- select id,tid,NULL as "res_no",account_id,name,date from t_game_bbs as a union select id,tid,res_no,account_id,name,date from t_game_res as b where del_flg != 1'; order by date DESC limit 10; -------------------------------- 不思議に思ったのが、”NULL as "res_no"”のところです。 これについて、ググッて見たのですが、明確な説明が見つかりませんでした。 これって、SQLの隠し機能なのですか?

  • MYSQLでストアドプロシージャの引数を二つ

    MYSQL初心者で参考書にかじりついてプログラミングしています。 主にDBの内容をPHPで吐き出させるといった使い方をしています。 SQL文があまりにも長ったらしくなってきたのでストアドプロシージャを使いたいのですが、使っているSQL文が (SELECT * FROM .変数. WHERE .変数. LIKE '.変数.') UNION (SELECT * FROM .変数. WHERE .変数. LIKE '.変数.'); となっており、引数を複数使えないとスッキリさせられない状況です。 ストアドプロシージャで複数の引数を設定することはできないのでしょうか?

    • ベストアンサー
    • MySQL
  • MYSQLで全てのカラムから検索する。

    tbというテーブルのbangというカラムに4が含まれていれば表示というのは select * from tb where (bang) like '%4%' ; という形になりますが、このtbテーブルにさらにname,tukiというカラムがあったとして カラムに関係なくレコードのどこかに4が入っていれば抽出するというSQL文が書きたいです。 select * from tb where bang like '%4%' or name like '%4%' or tuki like '%4%' ; と書くことで何とか今まではやってきたのですが、カラム数が増えてきてしまったので、ものすごく長いSQL文なってしまいました。 もう少しスマートにする方法はありませんか?

    • ベストアンサー
    • MySQL
  • 1個のSQL分で2種類以上の件数値を取得する

    SQL分の記述で質問なんですが、 データベース上に日付、時間、フラグと言う項目があります。 同一の日付、時間のものは数件ずつあります。 フラグは"b"と"1"があります。 このデータの日付・時間辺りの件数と+フラグが"1"の件数を同時に取得するSQL分はかけますでしょうか? 別々ならば、 SELECT DATE,TIME,COUNT(*) AS KENSU1 FROM W_TABLE GROUP BY DATE,TIME ORDER BY DATE,TIME と SELECT DATE,TIME,COUNT(*) AS KENSU2 FROM W_TABLE WHERE FLG="1" GROUP BY DATE,TIME ORDER BY DATE,TIME でかけると思うのですが、 1個のSQL分で記述は可能でしょうか? 処理結果を 05/02/23 12:00 10 5 05/02/24 10:00 12 3 (日付・時間・件数・フラグ="1"の件数  見たいに取得したいのですが..

  • SQL サブクエリで抽出したカラムについて

    サブクエリで抽出したカラムを 本クエリでの結果と一緒に表示したいのですが どのように実現してよいかわからず困っております。 詳細としては、下記のようなことをしたいと考えております。 文中の1)と2)は文章下部にあるSQLを指しております ----------------------------------------------------------- 最初は、1)のように凄く単純なSQLでよかったのですが 仕様が変わり、TBL2で取得した新しいカラムも一緒に 本クエリでの結果として取得できれば、SQLを2回実行せずに済むなと考えたのですが、 2)のように色々と試行錯誤したのですが、実現できません。 (2)は単なる空想ですが…) そこで、わかる方にお伺いしたいのですが、 副問い合わせで取得した複数カラムの中の1つのカラム【2)でいうところのTBL2.X】 を 2)のように"select TBL1.A , TBL2.X"として、結果を得ることは可能でしょうか。 ただし、 TBL1のカラムAは、TBL2に存在しない TBL2のカラムXは、TBL1には存在しない カラムBは、TBL1、TBL2に存在する の条件となっております 環境はMysqlです テーブル結合の方法も考えたのですが、 TBL2で、日付でソートし、その上位100件だけを 持ってきたいと思ったので、副問い合わせで一気に抽出しようとこの方法を考えまし た お分かりになる方がいらっしゃいましたらよろしくお願いします 1)SQL ------------ select TBL1.A from TBL1 where TBL1.B in ( select TBL2.B from TBL2 where 条件 ) 2)想像SQL(こんな感じの事をしたい) -------------- select TBL1.A , TBL2.X from TBL1 where TBL1.B in ( select TBL2.B , TBL2.X from TBL2 where 条件 order by TBL2.日付 desc limit 100 )

    • ベストアンサー
    • MySQL
  • 「・」中点が入った文字列を条件にするとデータを抽出できないです

    「・」中点が入った文字列を条件にすると データを抽出できないです。 うまくいかない例 ------------------------------------------- $name = "春・春・春"; $Sql = "SELECT * FROM TestList"; $Sql .= " WHERE SpName = '".$name."'"; ------------------------------------------- 条件を変数に格納してSQL文に渡すと何も抽出できません。 しかし↓のようにSQLに直に「春・春・春」とすると うまくデータが抽出されます。 うまくいった例 ------------------------------------------- $Sql = "SELECT * FROM TestList"; $Sql .= " WHERE SpName = '春・春・春'"; ------------------------------------------- また「・」中点がない条件では変数で渡しても データがうまく抽出されます。 どうしたら「・」中点が入っている条件を 変数に格納してSQLに渡しても うまくデータが抽出されるでしょうか? どなたかご教示いただけますと助かります。 よろしくお願いします。

  • 複雑なSELECT

    SELECT * FROM hoge WHERE hoge LIKE '%$okweb%' ORDER BY day DESC; と、ほしい情報が入っているレコードを取得した場合、セレクトした一番最後のレコードの次を取得するにはどうしたらいいのでしょうか?又は一番初めの一つ前のレコードを取得するにはどうしたらいいのでしょうか? よろしくお願いします。

    • ベストアンサー
    • MySQL