【问题标题】:is there a shorter way to set up queries when filtering results?过滤结果时是否有更短的方法来设置查询?
【发布时间】:2013-01-26 02:55:35
【问题描述】:

我有 2 个下拉菜单,用户可以使用下拉菜单过滤他们希望看到的学生和问题。可能的过滤器类型有:

  • 选择所有学生和所有问题
  • 选择所有学生和一个问题
  • 选择所有问题和一名学生
  • 选择一名学生和一个问题

以下是下拉菜单:

<p>
    <strong>Student:</strong>
    <select name="student" id="studentsDrop">
    <option value="All">All</option>
    <?php
    while ( $currentstudentstmt->fetch() ) {
    $stu = $dbStudentId;
    if(isset($_POST["student"]) && $stu == $_POST["student"]) 
        echo "<option selected='selected' value='$stu'>" . $dbStudentAlias . " - " . $dbStudentForename . " " . $dbStudentSurname . "</option>" . PHP_EOL;
    else
        echo "<option value='$stu'>" . $dbStudentAlias . " - " . $dbStudentForename . " " . $dbStudentSurname . "</option>" . PHP_EOL;
    }
    ?>
    </select>
    </p>

    <p>
    <strong>Question:</strong>
    <select name="question" id="questionsDrop">
    <option value="All">All</option>
    <?php
    while ( $questionsstmt->fetch() ) {
    $ques = $dbQuestionId;
    if(isset($_POST["question"]) && $ques == $_POST["question"]) 
        echo "<option selected='selected' value='$ques'>" . $dbQuestionNo . "</option>" . PHP_EOL;
    else
        echo "<option value='$ques'>" . $dbQuestionNo . "</option>" . PHP_EOL;
    }
    ?>
    </select>

</p>

现在我想设置一个 mysqli 查询来确定从下拉菜单中选择的学生和问题。

我的问题只是我需要设置 4 个查询来检查我从下拉菜单中提到的 4 种可能性还是有更短的方法?

我必须使用:

 if ($_POST['question'] == 'All' && if ($_POST['student'] == 'All'){){

//NO WHERE CLAUSE

    if ($_POST['question'] == 'All' && if ($_POST['student'] != 'All'){){

//WHERE CLAUSE FOR FINDING SELECTED STUDENT

    if ($_POST['question'] != 'All' && if ($_POST['student'] == 'All'){){

//WHERE CLAUSE FOR FINDING SELECTED QUESTION 

    if ($_POST['question'] != 'All' && if ($_POST['student'] != 'All'){){

//WHERE CLAUSE FOR FINDING SELECTED QUESTION AND SELECTED STUDENT

更新:

我现在拥有的:

    function AssessmentIsSubbmitted()
{
    if(isset($_POST['answerSubmit'])) // we have subbmited the first form
    {

//QUERY 1: Student details depending on selected student(s)

if ($_POST['student'] == 'All'){

$selectedstudentqry = "
SELECT
StudentAlias, StudentForename, StudentSurname
FROM Student s
INNER JOIN Student_Session ss ON s.StudentId = ss.StudentId
WHERE SessionId = ?
ORDER BY StudentAlias
";

global $mysqli;
$selectedstudentstmt=$mysqli->prepare($selectedstudentqry);
// You only need to call bind_param once
$selectedstudentstmt->bind_param("i",$_POST["session"]);
// get result and assign variables (prefix with db)
$selectedstudentstmt->execute(); 
$selectedstudentstmt->bind_result($detailsStudentAlias,$detailsStudentForename,$detailsStudentSurname);
$selectedstudentstmt->store_result();
$selectedstudentnum = $selectedstudentstmt->num_rows();     

}else{  

$selectedstudentqry = "
SELECT
StudentAlias, StudentForename, StudentSurname
FROM
Student
WHERE
(StudentId = ?)
ORDER BY StudentAlias
";

global $mysqli;
$selectedstudentstmt=$mysqli->prepare($selectedstudentqry);
// You only need to call bind_param once
$selectedstudentstmt->bind_param("i",$_POST["student"]);
// get result and assign variables (prefix with db)
$selectedstudentstmt->execute(); 
$selectedstudentstmt->bind_result($detailsStudentAlias,$detailsStudentForename,$detailsStudentSurname);
$selectedstudentstmt->store_result();
$selectedstudentnum = $selectedstudentstmt->num_rows();    

}    


//QUERY 2: Question details depending on selected question(s)


if ($_POST['question'] == 'All'){

$selectedquestionqry = " SELECT q.QuestionNo, q.QuestionContent, o.OptionType, q.NoofAnswers, GROUP_CONCAT( DISTINCT Answer
                    ORDER BY Answer
                    SEPARATOR ',' ) AS Answer, r.ReplyType, q.QuestionMarks
                    FROM Question q
                    LEFT 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
                    WHERE SessionId = ?
                    GROUP BY q.QuestionId
                    ORDER BY q.QuestionId";
";

global $mysqli;
$selectedquestionstmt=$mysqli->prepare($selectedquestionqry);
// You only need to call bind_param once
$selectedstudentstmt->bind_param("i",$_POST["session"]);
// get result and assign variables (prefix with db)
$selectedquestionstmt->execute(); 
$selectedquestionstmt->bind_result($detailsQuestionNo,$detailsQuestionContent,$detailsOptionType,$detailsNoofAnswers,
$detailsAnswer,$detailsReplyType,$detailsQuestionMarks);
$selectedquestionstmt->store_result();
$selectedquestionnum = $selectedquestionstmt->num_rows(); 


}else{

$selectedquestionqry = "
SELECT q.QuestionNo, q.QuestionContent, o.OptionType, q.NoofAnswers, GROUP_CONCAT( DISTINCT Answer
                    ORDER BY Answer
                    SEPARATOR ',' ) AS Answer, r.ReplyType, q.QuestionMarks
                    FROM Question q
                    LEFT 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
                    WHERE QuestionId = ?
                    GROUP BY q.QuestionId
                    ORDER BY q.QuestionId
";

global $mysqli;
$selectedquestionstmt=$mysqli->prepare($selectedquestionqry);
// You only need to call bind_param once
$selectedquestionstmt->bind_param("i",$_POST["question"]);
// get result and assign variables (prefix with db)
$selectedquestionstmt->execute(); 
$selectedquestionstmt->bind_result($detailsQuestionNo,$detailsQuestionContent,$detailsOptionType,$detailsNoofAnswers,
$detailsAnswer,$detailsReplyType,$detailsQuestionMarks);
$selectedquestionstmt->store_result();
$selectedquestionnum = $selectedquestionstmt->num_rows(); 

}

//QUERY 3: Student Answers depending on selected student(s) and selected question(s)

$studentanswerqry = "
SELECT
sa.StudentId, sa.QuestionId, GROUP_CONCAT(DISTINCT StudentAnswer ORDER BY StudentAnswer SEPARATOR ',') AS StudentAnswer, ResponseTime, MouseClick, StudentMark
FROM Student_Answer sa
INNER JOIN Student_Response sr ON sa.StudentId = sr.StudentId
WHERE
(sa.StudentId = ? AND sa.QuestionId = ?)
GROUP BY sa.StudentId, sa.QuestionId
";

global $mysqli;
$studentanswerstmt=$mysqli->prepare($studentanswerqry);
// You only need to call bind_param once
$studentanswerstmt->bind_param("ii",$_POST["student"], $_POST["question"]);
// get result and assign variables (prefix with db)
$studentanswerstmt->execute(); 
$studentanswerstmt->bind_result($detailsStudentAnswer,$detailsResponseTime,$detailsMouseClick,$detailsStudentMark);
$studentanswerstmt->store_result();
$studentanswernum = $studentanswerstmt->num_rows(); 


}

?>

【问题讨论】:

    标签: php mysqli


    【解决方案1】:

    您可以迭代地构建WHERE 子句。考虑到 WHERE 子句进行显式过滤,因此对于选择“全部”某些内容的情况,您不需要添加任何过滤器。其他过滤器相互依赖,因此我们可以简单地将它们与ANDs 加入WHERE

    $query = 'SELECT ... FROM ...';
    
    // Initially empty
    $where = array();
    $parameters = array();
    
    // Check whether a specific student was selected
    if($stu !== 'All') {
        $where[] = 'stu = ?';
        $parameters[] = $stu;
    }
    
    // Check whether a specific question was selected
    // NB: This is not an else if!
    if($ques !== 'All') {
        $where[] = 'ques = ?';
        $parameters[] = $ques;
    }
    
    // If we added to $where in any of the conditionals, we need a WHERE clause in
    // our query
    if(!empty($where)) {
        $query .= ' WHERE ' . implode(' AND ', $where);
    }
    
    $result = prepare_and_execute_query($query, $parameters);
    

    好的,所以看看您的更新,您有一组相当复杂的查询,但可以将它们组合成一个语句。试试这个:

    SELECT
        s.StudentId, s.StudentAlias, s.StudentForename,         -- Student fields
        s.StudentSurname,
        q.QuestionId, q.QuestionNo, q.QuestionContent,          -- Question fields
        q.OptionType, q.NoofAnswers, q.Answer, q.ReplyType,
        q.QuestionMarks,
        GROUP_CONCAT(DISTINCT sa.StudentAnswer ORDER BY         -- Answer fields
            sa.StudentAnswer SEPARATOR ',') AS StudentAnswer,
        sr.ResponseTime, sr.MouseClick, sr.StudentMark
    FROM Student s
    INNER JOIN Student_Answer sa ON (s.StudentId = sa.StudentId)
    INNER JOIN Question q ON (sa.QuestionId = q.QuestionId)
    INNER JOIN Student_Response sr ON (sa.StudentId = sr.StudentId)
    WHERE                     -- This WHERE clause may be entirely removed, 
                              -- depending on the filters
        s.StudentId = ? AND   -- This is removed if $_POST['student'] is 'All'
        q.QuestionId = ?      -- This is removed if $_POST['question'] is 'All'
    GROUP BY sa.StudentId, q.QuestionId
    

    我认为这会做你想要的。我不太确定哪些字段是Student_Response 的一部分,哪些是Student_Answer 的一部分,因此您可能不得不摆弄SELECT 中的列。


    不幸的是,这种方法不适用于您的用例。但是我们仍然可以考虑我提出的原始逻辑如何与您给出的一个查询一起工作:

    $selectedstudentqry = "
    SELECT
    StudentAlias, StudentForename, StudentSurname
    FROM
    Student ";
    if($_POST['student'] !== 'All') { // Check here
        $selectedstudentqry .= "
        WHERE
        (StudentId = ?) ";
    }
    $selectedstudentqry .= "
    ORDER BY StudentAlias
    ";
    
    global $mysqli;
    $selectedstudentstmt=$mysqli->prepare($selectedstudentqry);
    if($_POST['student'] !== 'All') {
        // You only need to call bind_param once
        $selectedstudentstmt->bind_param("i",$_POST["student"]);
    }
    // get result and assign variables (prefix with db)
    $selectedstudentstmt->execute(); 
    $selectedstudentstmt->bind_result($detailsStudentAlias,$detailsStudentForename,$detailsStudentSurname);
    $selectedstudentstmt->store_result();
    $selectedstudentnum = $selectedstudentstmt->num_rows();
    

    请注意我们如何简单地将外部 ifs 移动到代码中更具体的位置以减少代码重复。如果你看到像你一样的重复,很有可能你正在做一些事情,比如让你的条件句太宽泛。不过,尝试简化这一点并减少冗余,您肯定走在正确的轨道上。

    【讨论】:

    • 我可以向您发布我现在得到的查询以及我过滤它们的方式,然后您可以编辑您的答案以使您的解决方案与我的查询相匹配吗?
    • 当然,虽然我觉得自己尝试解决这个问题对你更有好处。也许我们可以从这个开始:在实现这个逻辑时有什么特别的问题吗?
    • 我遇到的问题是我有三个查询。一个查询根据从下拉列表中选择的学生检索学生详细信息,第二个查询根据从下拉列表中选择的问题检索问题详细信息。最大的问题是检查学生答案的第三个查询,此查询需要知道选择了哪个学生(一个学生或所有学生)以及选择了哪个问题(一个问题或所有问题)以检查哪些问题我们希望看到一个学生的答案。
    • 让我包含并更新我目前得到的内容。如果您可以为第三个查询实现您的解决方案,那么我将能够知道为其他 2 个查询实现它。
    • 我添加了一个查询,我认为可以完成您的三个查询所做的所有事情。看看你是否可以使用它——它有点复杂,我不确定它是否正确。
    【解决方案2】:

    这是我在有 64 种用户输入排列时使用的代码。可以有来自另一个页面的乘客 ID、部分名字和/或姓氏、年份、月份或课程 ID。

    用各种 AND、IS LIKE 等构造部分 where 子句。

    $params = array();
    $types = "";
    
    
    if ( isset($_GET["riderid"]) && $_GET["riderid"] )  {
        $where = sprintf (' AND %s.id = ?', $tables["rider"]);
        $params[]= $_GET["riderid"];
        $types = $types .'i';
    
    } else {
        if ( isset($_GET["last"]) && $_GET["last"] ) {
    
            $where = sprintf(' AND %s.last like ?', $tables["rider"]);
            $params[] = $_GET["last"] . "%";
            $types = $types . "s";
        }
    
        if ( isset($_GET["first"]) && $_GET["first"] ) {
    
            $whereFirst = sprintf(' AND %s.first like ?', $tables["rider"]);
            $where = $where . $whereFirst;
            $params[] = $_GET["first"] . "%";
            $types = $types . "s";
        }
    }
    
    if ( isset($_GET["year"]) && $_GET["year"] && $_GET["year"] != -1 )  {
        $whereYear = sprintf(' AND YEAR(%s.date) = ?', $tables["race"]);
        $where = $where . $whereYear;
        $params[] = $_GET["year"];
        $types = $types . "i";
    }
    
    if ( isset($_GET["month"]) && $_GET["month"] && $_GET["month"] != -1 )  {
        $whereMonth = sprintf(' AND month(%s.date) = ?', $tables["race"]);
        $where = $where . $whereMonth;
        $params[] = $_GET["month"];
        $types = $types . "i";
    
    }  
    
    if ( isset($_GET["courseid"]) && $_GET["courseid"] && $_GET["courseid"] != -1 ) {
        $whereCourse = sprintf(' AND %s.courseid = ?', $tables["race"]);
        $where = $where . $whereCourse;
        $params[] = $_GET["courseid"];
        $types = $types . "i";
    }
    

    这是查询。

        //
        // Show selected races
        //
        $listQuery = "SELECT {$tables["race"]}.raceid, {$tables["race"]}.typeid, " .
                 "           tag,  {$tables["race"]}.date, " .
                 "           {$tables["location"]}.name, {$tables["course"]}.dist, " .
                 "           {$tables["course"]}.description,  " .
                 "           {$tables["result"]}.time, {$tables["result"]}.dnf, " .
                 "           {$tables["rider"]}.first, {$tables["rider"]}.last ".
                 "  FROM {$tables["race"]}, {$tables["sysracetype"]}, " .
                 "       {$tables["course"]}, {$tables["location"]}, " .
                 "       {$tables["result"]}, {$tables["rider"]} " .
                 " WHERE {$tables["race"]}.courseid = {$tables["course"]}.courseid " .
                 "   AND {$tables["race"]}.typeid = {$tables["sysracetype"]}.typeid " .
                 "   AND {$tables["course"]}.locid = {$tables["location"]}.locid " .
                 "   AND {$tables["race"]}.raceid = {$tables["result"]}.raceid" .
                 "   AND {$tables["result"]}.riderid = {$tables["rider"]}.id" .
                 $where .
                 $orderby;
    

    准备和绑定参数。

    $stmt = mysqli_prepare ($db_connection, $listQuery);
    // 
    // Handle the varying number of SQL parameters / place holders.
    // Push the first two parameter of mysqli_stmt_bind_param
    //
    $bindArgs = array ($stmt, $types);
    
    //
    // Change parameters to refs  (depends on PHP version)   
    //
    foreach ($params as $key => $value)  
        $bindArgs[] =& $params[$key];
    
    //
    // Use "call back" to pass all params.
    //
    call_user_func_array("mysqli_stmt_bind_param", $bindArgs);
    

    【讨论】:

      【解决方案3】:

      我通过这种方式解决了类似的问题。其中 $parmMap 是用 2 (1,2) 的幂构造的,因为我检测到每个可选的 WHERE 子句项并附加适当的 AND fieldName = ?。

      switch ($parmMap ) {
          case 0:
            break;
          case 1:
            mysqli_stmt_bind_param ($stmt, "i", $courseParm );
            break;
          case 2:
            mysqli_stmt_bind_param ($stmt, "i", $yearParm );
            break;
          case 3:
            mysqli_stmt_bind_param ($stmt, "ii", $courseParm, $yearParm );
            break;
          default:
            break;
      }
      

      我不会将它用于另一个有六个可选 where 子句条件的查询!我发现了call_user_func_array

      【讨论】:

      • 接受的答案只管理一个或零个绑定变量。我同意我的解决方案对于多个可选的where 子句参数来说变得笨拙,但是对于两个或三个代码是可读的。不仅如此,正如我所建议的,数组更好。
      猜你喜欢
      • 1970-01-01
      • 2018-09-15
      • 1970-01-01
      • 2018-04-25
      • 1970-01-01
      • 2022-10-14
      • 2017-11-22
      • 1970-01-01
      • 2012-06-28
      相关资源
      最近更新 更多