こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

締切り済みの質問

素材を比較して共通項目数をデータベースに格納したい

PHPで素材の特徴の共通項目数を求めるシステムを作っていますが結果がデータベースに格納されずに困っています。

データベース'compare'のテーブル'answers'に既にいくつかの回答(データ)が入っている状態で質問formから受け取った質問の回答をテーブル'answers'のデータと比較し幾つ共通項目があるかをデータベース'compare'の'result'テーブルにidナンバー(idフィールド)と共通項目数(commonsフィールド)を格納することを目指いしています。

【質問form】

<html>
<head>
<meta charset="UTF-8">
<title>特徴マッチ度</title>
</head>
<body>
<form method="post" action="question_check.php">
熱に強い<br/>
<input type="radio" name="q1" value="1">Yes <input type="radio" name="q1" value="2">No<br/>

柔軟性がある<br/>
<input type="radio" name="q2" value="1">Yes <input type="radio" name="q2" value="2">No<br/>

1、手で破く事ができる2、手で破く事はできない3鋏を使えば切れる4、鋏でも切れない<br/>
<input type="radio" name="q3" value="1">1 <input type="radio" name="q3" value="2">2<input type="radio" name="q3" value="3">3 <input type="radio" name="q3" value="4">4<br/>
<br/>
<input type="button" onclick="history.back()" value="戻る">
<input type="submit" value="OK">
</form>
</body>
</html>

【回答チェックPHP(略)をし値を送る】

<form method="post" action="compare.php">';
print'<input type="hidden" name="q1" value="'.$question1.'">';
print'<input type="hidden" name="q2" value="'.$question2.'">';
print'<input type="hidden" name="q3" value="'.$question3.'">';
print'<br/>';
print'<input type="button" onclick="history.back()" value="戻る">';
print'<input type="submit" value="OK">';
print'</form>';

【試したPHP】

<html>
<head>
<meta charaset="UTF8">
<title>素材比較</title>
</head>
<body>

<?php

$question1=$_POST['q1'];
$question2=$_POST['q2'];
$question3=$_POST['q3'];

$dsn='mysql:dbname=compare;host=localhost';
$user='root';
$password='';
$dbh=new PDO($dsn, $user, $password);
$dbh->query('SET NAMES utf8');

$sql='SELECT code,r1,r2,r3 FROM answers WHERE 1';
$stmt=$dbh->prepare($sql);
$stmt->execute();

$dbh=null;

//回答が共通する計を求める。

while(true)
{
$rec=$stmt->fetch(PDO::FETCH_ASSOC);
if($rec==false)
{
break;
}

if($rec['r1']==$question1)
{
$s=$s+1;
}
else
{
$s=0;
}
if($rec['r2']==$question2)
{
$s=$s+1;
}
if($rec['r3']==$question3)
{
$s=$s+1;
}
//試した一例

$dsn='mysql:dbname=compare;host=localhost';
$user='root';
$password='';
$dbh=new PDO($dsn, $user, $password);
$dbh->query('SET NAMES utf8');

$sql = "INSERT INTO results (id, commons) VALUES (:id, :commons)";

$stmt = $dbh->prepare($sql);

$id= array($rec['code']=>$s);

// foreachで挿入する値を1つずつループ処理
foreach ($id as $key => $s) {

// 連想配列のキーを :name に、値を :commons にセットし、executeでSQLを実行
$stmt->execute(array(':id' => $key, ':commons' => $s));

}

$s=0;
}

//新規の素材の回答をテーブルanswersの最後に格納。

$dsn='mysql:dbname=kachikan;host=localhost';
$user='root';
$password='';
$dbh=new PDO($dsn, $user, $password);
$dbh->query('SET NAMES utf8');

$sql='INSERT INTO answers(r1,r2,r3) VALUES (?,?,?)';
$stmt=$dbh->prepare($sql);
$data[]=$question1;
$data[]=$question2;
$data[]=$question3;
$stmt->execute($data);
$dch=null;
?>

</body>
</html>

【得たい結果】
テーブル'answers'にすでに3つの素材の特徴の回答が下記の様に入っていたとします。

code | r1 | r2 | r3 |
1 | 2 | 1 | 4 |
2 | 1 | 2 | 3 |
3 | 2 | 3 | 1 |

新規に1つの素材(code 4)の回答(2,2,4)をformから送った場合
ccode 4とcode 1の共通項目はr1とr3で共通項目数は2。
code 4とcode 2の共通項目はr2のみで共通項目数は1。
code 4とcode 3の共通項目はr1のみで共通項目数は1。

テーブル'results'には

id | commons|
1 | 2 |
2 | 1 |
3 | 1 |

という結果が格納されてほしいのですが(codeとidの内容は同じで同一の素材です)テーブル'results'に値が格納されません。

テーブル'answers'にはcode 4の回答を最後に格納して

code | r1 | r2 | r3 |
1 | 2 | 1 | 4 |
2 | 1 | 2 | 3 |
3 | 2 | 3 | 1 |
4 | 2 | 2 | 4 |

と言う結果になることを求めています。

どなたかお助けください。

投稿日時 - 2017-07-29 15:16:39

QNo.9357176

困ってます

このQ&Aは役に立ちましたか?

1人が「このQ&Aが役に立った」と投票しています

回答(2)

ANo.2

MySQLもphpも、最新記述が使えるversionですので、データベース接続部とSQL文発行のところを以下のようにすると良いでしょう。
<?php
/* 接続DSN ここで文字コードを指定 */
$dsn='mysql:dbname=compare;host=localhost;charset=utf8';
$user='root';
$password='';
try{
$dbh=new PDO($dsn, $user, $password);
/* 例外モードに設定 */
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql='SELECT code,r1,r2,r3 FROM answers WHERE 1';
$stmt=$dbh->prepare($sql);
$stmt->execute();
$list = array();
while( $rec=$stmt->fetch(PDO::FETCH_ASSOC) ){
$s = 0;
/* $question1, $question2, $question3 には、postデータを格納済みのこと */
if($rec['r1']==$question1) $s ++;
if($rec['r2']==$question2) $s ++;
if($rec['r3']==$question3) $s ++;
$list[] = array( ':id'=>$rec['code'] , ':commons'=> $s );
}
$sql = "INSERT INTO results (id, commons) VALUES (:id, :commons)";
$stmt = $dbh->prepare($sql);
foreach ($list as $row) {
$stmt->execute($row);
}
/* 新規素材情報をテーブルanswersの最後に格納。int型の場合は個別bind必要 */
$sql='INSERT INTO answers(r1,r2,r3) VALUES (?,?,?)';
$stmt=$dbh->prepare($sql);
$stmt->bindValue(1, $question1, PDO::PARAM_INT);
$stmt->bindValue(2, $question2, PDO::PARAM_INT);
$stmt->bindValue(3, $question3, PDO::PARAM_INT);
$stmt->execute();
} catch (PDOException $e) {
echo '<div>えらー:' , e.getMessage() , "</div>\n";
}
/* 最後に接続を切る */
$stmt = null;
$dbh = null;

投稿日時 - 2017-08-19 22:43:35

ANo.1

まずは、エラーが出てないかを表示するところから始めるべき。
先頭で error_reporting(-1); としておくとよい。
$_POSTの値は、filter_input()を利用して不正なデータが入ってないかチェックすべき。
PDOの接続はSQL発行ごとに毎回つなぎ直すようなことはしない。おなじオブジェクトを使い回す方がよい。
で、データをfetchする前におおもとの $dbh を null にすると接続情報がキャンセルされて、1行もデータを得てないのでは?
あと、sql文のエラーは、PDO接続時に例外発生モードにしてtry{}catch{}しないと知ることはできない。
文字コード設定も set names 発行ではなく、接続時設定で指定するのが最もセキュリティも高いのだが、phpやmysqlはどのversion なのだろうか?

投稿日時 - 2017-08-17 14:19:10

お礼

ご回答ありがとうございます。
ご進言を基にもう一度見直し、改定をしてみます。

MySQLは5.6.20
PHPは5.5.15
です。

投稿日時 - 2017-08-19 00:16:16

あなたにオススメの質問