8

mysqliを使用して動的where句を作成しようとすると、かなりの数のエラーが発生します。

警告:mysqli_stmt :: bind_param()のパラメーター2は参照であると予想され、値は319行目の...で指定されています

警告:mysqli_stmt :: execute():(HY000 / 2031):328行目の...のプリペアドステートメントのパラメーターにデータが提供されていません

警告:mysqli_stmt :: bind_result():(HY000 / 2031):331行目の...のプリペアドステートメントのパラメーターにデータが提供されていません

警告:mysqli_stmt :: store_result():(HY000 / 2014):コマンドが同期していません。332行目の...でこのコマンドを実行することはできません。

問題を解決するために必要な変更が少しあると思いますが、2つのドロップダウンメニューのいずれかが等しくないAll場合、または両方が等しくない場合はAll、エラーが発生します。

以下は、選択したn個のオプションに応じて、ドロップダウンメニューとそれに続くクエリ(動的where句を使用)の両方を表示するコードです。

HTML:

学生ドロップダウンメニュー:

<select name="student" id="studentsDrop">
<option value="All">All</option>
<option value="11">John May</option>
<option value="23">Chris Park</option>
</select>

質問番号ドロップダウンメニュー

<select name="question" id="questionsDrop">
<option value="All">All</option>
<option value="123">1</option>
<option value="124">2</option>
<option value="125">3</option>
</select>

PHP / MYSQLI:

      function StudentAnswers()
        {


    /*BELOW IS THE QUERY WHERE I AM TRYING TO RETRIEVE DATA DEPENDING ON THE ASSESSMENT CHOSEN AND
    THEN DEPENDING ON OPTIONS CHOSEN IN STUDENT AND QUESTION NUMBER DROP DOWN MENU */

        $selectedstudentanswerqry = "
        SELECT
        StudentAlias, StudentForename, StudentSurname, q.SessionId, QuestionNo, QuestionContent, o.OptionType, q.NoofAnswers, GROUP_CONCAT( DISTINCT Answer
        ORDER BY Answer SEPARATOR ',' ) AS Answer, r.ReplyType, QuestionMarks, 
        GROUP_CONCAT(DISTINCT StudentAnswer ORDER BY StudentAnswer SEPARATOR ',') AS StudentAnswer, ResponseTime, MouseClick, StudentMark
        FROM Student s
        INNER JOIN Student_Answer sa ON (s.StudentId = sa.StudentId)
        INNER JOIN Student_Response sr ON (sa.StudentId = sr.StudentId)
        INNER JOIN Question q ON (sa.QuestionId = q.QuestionId)
        INNER JOIN Answer an ON q.QuestionId = an.QuestionId
        LEFT JOIN Reply r ON q.ReplyId = r.ReplyId
        LEFT JOIN Option_Table o ON q.OptionId = o.OptionId
        ";

        // Initially empty
        $where = array('q.SessionId = ?');
        $parameters = array($_POST["session"]);
        $parameterTypes = 'i';

        // Check whether a specific student was selected
        if($_POST["student"] !== 'All') {
            $where[] = 'sa.StudentId = ?';
            $parameters[] =& $_POST["student"];
            $parameterTypes .= 'i';
        }

        // Check whether a specific question was selected
        // NB: This is not an else if!
        if($_POST["question"] !== 'All') {
            $where[] = 'q.QuestionId = ?';
            $parameters[] =& $_POST["question"];
            $parameterTypes .= 'i';
        }

        // If we added to $where in any of the conditionals, we need a WHERE clause in
        // our query
        if(!empty($where)) {
            $selectedstudentanswerqry .= ' WHERE ' . implode(' AND ', $where);
            global $mysqli;
            $selectedstudentanswerstmt=$mysqli->prepare($selectedstudentanswerqry);
            // You only need to call bind_param once
                call_user_func_array(array($selectedstudentanswerstmt, 'bind_param'),
                array_merge(array($parameterTypes), $parameters)); //LINE 319 ERROR 1
        }

    //Add group by and order by clause to query
        $selectedstudentanswerqry .= "
          GROUP BY sa.StudentId, q.QuestionId
          ORDER BY StudentAlias, q.SessionId, QuestionNo
        ";

        // get result and assign variables (prefix with db)
        $selectedstudentanswerstmt->execute(); //LINE 328 ERROR 2

    //bind database fields 
$selectedstudentanswerstmt->bind_result($detailsStudentAlias,$detailsStudentForename,$detailsStudentSurname,$detailsSessionId,$detailsQuestionNo, 
        $detailsQuestonContent,$detailsOptionType,$detailsNoofAnswers,$detailsAnswer,$detailsReplyType,$detailsQuestionMarks,$detailsStudentAnswer,$detailsResponseTime,
        $detailsMouseClick,$detailsStudentMark); //LINE 331 ERROR 3

    //store results retrieved
        $selectedstudentanswerstmt->store_result(); //LINE 332 ERROR 4

    //count number of rows retrieved
        $selectedstudentanswernum = $selectedstudentanswerstmt->num_rows();     

    //output query
        echo "$selectedstudentanswerqry";

        }

        ?>

これがデモです: デモ

デモでは、ドロップダウンメニューから評価を選択して送信します。2つのドロップダウンメニューが表示されます。両方を設定しAllて送信すると、問題なくクエリが出力されます。ドロップダウンメニューのいずれかでいいえAll、特定の学生または質問に変更してから送信してください。これでエラーが表示されます

VARダンプ:

値、学生番号の値、質問番号の値var_dump(array_merge(array($parameterTypes), $parameters)));を使用してセッション(評価)を選択したときの結果、およびWHERE CLAUSE :314081WHERE q.SessionId = ? AND sa.StudentId = ? AND q.QuestionId = ?

私はこの出力を得ています:array(4) { [0]=> string(3) "iii" [1]=> string(2) "31" [2]=> string(2) "40" [3]=> string(2) "81" }

4

3 に答える 3

1

警告:mysqli_stmt :: bind_param()のパラメーター2は参照であると予想され、値は319行目の...で指定されています

これは自明である必要があります。bind_paramの引数は参照によって渡されるため、変数である必要があります。見落としているかもしれarray_mergeませんが、元の変数への参照を含まず、値のみを含む新しい配列を返します。

次のエラーは、パラメータがバインドされていないため、これの直後に発生します。

考えられる解決策は、配列に参照を格納することです$parameters。それらはarray_mergeによっても保持されます。

$parameters[] =& $_POST["student"];

$parameters[] =& $_POST["question"];

これで、の配列項目は$parametersPOST変数への参照になり、array_merge結果の配列項目も参照されます。

編集:これはもう不可能のようです。@ExplosionPillsを参照してください。

于 2013-01-31T00:16:49.410 に答える
1

call_user_func_arrayこれは、 PHP 5.4での動作の変更によって引き起こされる厄介な状況です(私は想定する必要があります):ドキュメント

これは醜いですが、次のbind_paramように呼び出すと機能します。

$selectedstudentanswerqry .= ' WHERE ' . implode(' AND ', $where);
global $mysqli;
$stmt =$mysqli->prepare($selectedstudentanswerqry);

if (count($where) === 1) {
    $stmt->bind_param($parameterTypes, $parameters[0]);
}
else if (count($where) === 2) {
    $stmt->bind_param($parameterTypes, $parameters[0], $parameters[1]);
}
else if (count($where) === 3) {
    $stmt->bind_param($parameterTypes, $parameters[0], $parameters[1],
       $parameters[2]);
}

私はあなたがおそらくそうするのと同じくらいこれを嫌います。変数パラメーターをより適切に処理mysqliするものから切り替えることをお勧めします(そして、私の意見では、一般的に優れた構文を持っています):PDO

$pdo = new PDO('mysql:host=localhost', 'username', 'password');
$stmt = $pdo->prepare($selectedstudentanswerqry);
$stmt->execute($parameters);
$selectedstudentanswernum = $stmt->rowCount();
于 2013-01-31T00:31:07.293 に答える
0

これは、まだmysqliをPDOから除外するのに十分な理由ではありません。特に、その時点で代わりにPDOを使用しない非常に正当な理由がある場合はなおさらです。一方、はい、mysqli_stmt :: bind_paramメソッドとbind_resultメソッドに、変数がRefによって渡されることを要求するように強制する必要はなく、配列を返すようにすることができました。しかし、ここでの本当の問題は、呼び出し時の参照渡しが不可能であるということですが、mysqliは参照渡しを必要とするため、動的パラメーターを使用している人(直感的なSQLを持っている人)が捕まりますこの号では、私も含めました。配列セットを動的に準備されたSQLステートメントに変換するカスタムmysqliラッパークラスを作成するのに何時間も費やした後、特にPDOにはバインディングの一部としてパラメーターに名前を付ける必要があるため、PDOで動作するようにすべてを書き直そうとはしていません。送信されたもののリストを作成するには、クエリの種類ごとに複数の関数を作成する必要があります。これは直感に反するものであり、mysqliで達成したことをエミュレートしようとして数え切れないほどの時間を無駄にすることはありません。

この時点での唯一の問題は、call_user_func_array()byRefで変数を渡すことができないことです。また、mysqli_stmt :: bind_ *では変数をbyRefで渡す必要があります...したがって、1)新しいcall_user_func_array()を作成するだけです。 bind_ *メソッドに対して明示的に機能するように設計された関数。渡されたパラメーターは、基本的にargsによって新しい配列または変数のセットにコピーされ、コールバックでそれらのbyRefを渡します。または2)mysqliクラスを書き直して正しい方法で実行し、渡されたものを確認してSQLを実行し、意図したとおりに結果を返します。SQLを実行するためにメソッドに渡すものが結果で破壊されなければならない理由はありません。SQLコンソールが扱われるのと同じように扱われるべきです。

目が出血しそうになるまでコーディングに疲れすぎているので、実際に問題が正しい方法で修正されるまで、PHPバージョンを5.3.10-1のままにしておくという提案されていないオプションを選択します。「そのすべての努力のために、代わりにPDOラッパーの作成に費やしてみませんか?」と主張する人のために...そして私の応答は単純です:サーバーが小さな小さなコンピューターである多くのプロジェクトでPHPとMySQLを排他的に使用しますCPU機能は言うまでもなく、部屋とリソースが非常に限られています。PDOは、使用するものだけでなく、実行できるすべてのものをロードします。そのため、使用しないもののためにリソースに予約があり、私のプロジェクトでは失うことはできません。

ありがたいことに、私のPHPバージョンを抑制したままにしておくことは、現時点では有害ではありません。これは、多くのエンタープライズレベルのサーバーファームが実際に行っていることです。これは、何かの「現在のバージョン」にするためだけにすべてを停止する必要がないようにするためです。これは、2、3年ごとにすべてをアップグレードするのにもめちゃくちゃ費用がかかります。

于 2016-04-23T08:41:33.413 に答える