質問: お世話になります。 引き続きアンケートの機能の作成でてこずっています。 テーブル名 an an_no 自動で番号が入ります an_time 回答したタイムスタンプ an_key 親回答からの番号が入っています an_data 回答内容が文字で入っています。 下記の内容のSQL文で、同じ回答だった場合(文字が同じ)に、カウントして、後の処理で件数が表示できています。 たとえばA市3件といった感じです。 これに、日付で抽出を加えようと、 $sql='SELECT an_data ,count(an_data) FROM an group by an_data';の文を $sql='SELECT *,count(an_data) FROM an group by an_data,an_time HAVING (an_time) BETWEEN :before AND :after';のように変えたところ、 抽出内容は一見同じで日付で絞込ができたように見えますが、 A市2件であるべきところがA市1件に減ってしまいます。他の重複して件数が複数でないといけないところも全部1件になってしまいます。 このSQLの使い方はそもそも問題があるのでしょうか? 違う方法でもいいので、カウントと、日付による絞り込みができたらと思います。 分かりにくくて申し訳ないですが、お知恵をお借りしたいと思います。 よろしくお願いします。 ``` require_once( __DIR__.'/common/database.php' ); $dbh=new PDO($dsn,$dbUser,$dbPass); $dbh->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); //回答の集計をしたい部分です HAVING BETWEENの行を使うと・・・ //$sql='SELECT *,count(an_data) FROM an group by an_data,an_time HAVING (an_time) BETWEEN :before AND :after'; $sql='SELECT an_data ,count(an_data) FROM an group by an_data'; $stma=$dbh->prepare($sql); $stma->bindValue(':before',$before,PDO::PARAM_STR); $stma->bindValue(':after',$after,PDO::PARAM_STR); $stma->execute(); while(true) { $reca=$stma->fetch(PDO::FETCH_ASSOC); if($reca==false) { break; } $key=$reca['an_key']; $key2=$reca['an_data']; $count_kaitou[$key][$key2]=$reca['count(an_data)']; } //後の処理で、$count_kaitouから内容を表示したりしています。 ```
回答: 多分質問者様がしたいことをSQLに表すと、 ``` SELECT * , count(an_data) FROM an GROUP BY an_data , an_time HAVING (an_time) BETWEEN :before AND :after ``` これは誤りで下記に直す必要があるのかなと推測します。 (※コメントに注釈を書いたので意識してみてください) ``` SELECT an_data /* 下のようにGROUP BY指定してない項目を単純に指定するのはNG * どうしても取りたいなら「MAX(an_no) AS an_no」みたいに集約関数を噛ませましょう。 */ -- * , count(an_data) FROM an WHERE an_time BETWEEN :before AND :after GROUP BY an_data /* 下のように集約単位は変えちゃいけないはず・・・ */ -- , an_time /* 集約関数噛ませたものに条件指定するのでなければ、 * HAVING句は必要ないでありますよ、隊長! */ -- HAVING -- (an_time) BETWEEN :before AND :after ```