繁体   English   中英

如何使用 PHP 为分数相同的用户分配相同的排名?

[英]How do I assign same rank to users with the same score with PHP?

$check_res = $con->query(
        "SELECT * 
        FROM `results` 
        WHERE school_session='$session' 
        AND Term='$term' 
        AND class='$class' 
        AND  subjectID='$subjectID' 
        ORDER BY Average DESC ");

$score_ends = array(1 => "st", 2 => "nd", 3 => "rd", 4 => "th");
$key_counter=1;
foreach ($check_res as $value) {
    $key_counters=$key_counter++;
    if($RegNum == $value['StudentReg']){
        if($key_counters < 4){
            echo $key_counters.$score_ends[$key_counters];
        }else{
            echo $key_counters.$score_ends[4];
        }
    }
}

此处的代码根据平均对用户进行排名。 它的工作正常。 但它不会为平均得分相同的用户分配相同的排名。 例如 20-1 日 20-2 日

但我想要的是这个 20-1st 20-1st 21-3rd

如果您运行的是 MySQL 8.0,则可以使用窗口函数直接在数据库中进行排名:

select r.*, rank() over(order by average desc) rn 
from results r
where 
    school_session = ?
    and term = ?
    and class = ?
    and  subjectid = ?
order by average desc

rank()为关系分配相同的数字。

请注意,我将查询更改为使用参数,而不是在查询字符串中连接 php 变量:这既安全又高效。

谈话要点

因此,您的代码中有一些不是最佳实践或有点令人困惑的地方。

  • 您真的应该在 SQL 查询中使用prepared语句。 它们在使用用户派生数据时提供更好的保护(不清楚您的搜索参数是来自用户输入还是来自其他代码)
  • 如果您在双引号字符串中使用$variables ,最好使用{curly braces}来包含它们。 它使用正确的变量解决了PHP的各种问题,也使其更易于阅读和维护
  • 正如其他人所说,您实际上并没有显示$Reg来源 - 所以我在下面的代码中忽略了它

解决方案

表格/数据

假设您的表中有以下数据...

表:结果

StudentReg | school_session | Term | class | subjectID | Average
-----------+---------------+------+-------+-----------+-------------
1          | 1022           | 3    | 37    | 66        | 121
2          | 1022           | 3    | 37    | 66        | 115
3          | 1022           | 3    | 37    | 66        | 129
4          | 1022           | 3    | 37    | 66        | 121
5          | 1022           | 3    | 37    | 66        | 121
6          | 1022           | 3    | 37    | 66        | 117
7          | 1022           | 3    | 37    | 66        | 129
8          | 1022           | 3    | 37    | 66        | 125
9          | 1022           | 3    | 37    | 66        | 120
10         | 1022           | 3    | 37    | 66        | 118
11         | 1022           | 3    | 37    | 66        | 125
12         | 1022           | 3    | 37    | 66        | 124
13         | 1022           | 3    | 37    | 66        | 125
14         | 1022           | 3    | 37    | 66        | 125

查询返回的排序数据

StudentReg | school_session | Term | class | subjectID | Average
-----------+---------------+------+-------+-----------+-------------
2          | 1022           | 3    | 37    | 66        | 115
6          | 1022           | 3    | 37    | 66        | 117
10         | 1022           | 3    | 37    | 66        | 118
9          | 1022           | 3    | 37    | 66        | 120
1          | 1022           | 3    | 37    | 66        | 121
5          | 1022           | 3    | 37    | 66        | 121
4          | 1022           | 3    | 37    | 66        | 121
8          | 1022           | 3    | 37    | 66        | 125
12         | 1022           | 3    | 37    | 66        | 124
11         | 1022           | 3    | 37    | 66        | 125
13         | 1022           | 3    | 37    | 66        | 125
14         | 1022           | 3    | 37    | 66        | 125
3          | 1022           | 3    | 37    | 66        | 129
7          | 1022           | 3    | 37    | 66        | 129

代码

我已经修改了代码以使用prepared语句。

变量

大概这些是在你的代码更远的地方声明的......

$session   = 1022;
$term      = 3;
$class     = 37;
$subjectID = 66;

mysqli

// SQL query to SELECT "Average" and "StudentReg" from "results"
// ?s are a place holder for values we'll bind later
$sql   = "
    SELECT StudentReg, Average
    FROM `results` 
    WHERE school_session = ? 
        AND Term = ? 
        AND class = ? 
        AND subjectID = ?
    ORDER BY Average DESC
";

$query  = $mysqli->prepare();                                    // Prepare the query
$query->bind_param("iiii", $session, $term, $class, $subjectID); // Bind search values to parameters ("iiii" : one "i" for each variable, set's data type to "int")
$query->execute();                            // Run the query
$query->Store_result();                       // Store the result set
$query->bind_result($studentreg, $average);   // Bind returned rows to variables

$score_ends = array(1 => "st", 2 => "nd", 3 => "rd", 4 => "th");
$last_value = false;     // Initialise last value of result set
### $counter    = 0;     // Initialise the counter
$rank = 0;
while($query->fetch()){  // Loop through the result set
    ### $counter++;      // Increment the counter

    ### // "if" statement using ternary logic
    ### // Sets the rank as either the counter OR the previous rank if it's the same
    ### $rank = ($last_value == false || $last_value <> $average) ? $counter : $rank;

    // "if" statement using ternary logic
    // Pre-increments (++ before variable) rank if the Average is not the same as previous
    // ...or leaves as is if it is the same
    $rank = ($last_value == false || $last_value <> $average) ? ++$rank: $rank;
    $end = ($rank > 3) ? $score_ends[4] : $score_ends[$rank];  // Sets the suffix to the rank using ternary logic
    echo "{$rank}{$end} {$studentreg}<br>";                     // Prints the result; e.g. 1st 2 {2 == the StudentReg, presumably you'll update that to be a name or something}
    $last_value = $average;                                    // Sets current average as last value ready for next loop
}

PDO

// SQL query to SELECT "Average" and "StudentReg" from "results"
// ?s are a place holder for values we'll bind later
$sql   = "
    SELECT StudentReg, Average
    FROM `results` 
    WHERE school_session = ? 
        AND Term = ? 
        AND class = ? 
        AND subjectID = ?
    ORDER BY Average DESC
";

$query  = $PDO->prepare();                               // Prepare the query
$query->execute([$session, $term, $class, $subjectID]);  // Execute the query and bind variables to place holders
$score_ends = array(1 => "st", 2 => "nd", 3 => "rd", 4 => "th");
$last_value = false;     // Initialise last value of result set
### $counter    = 0;     // Initialise the counter
$rank = 0;
while($query->fetch()){  // Loop through the result set
    ### $counter++;      // Increment the counter

    ### // "if" statement using ternary logic
    ### // Sets the rank as either the counter OR the previous rank if it's the same
    ### $rank = ($last_value == false || $last_value <> $row["Average"]) ? $counter : $rank;

    // "if" statement using ternary logic
    // Pre-increments (++ before variable) rank if the Average is not the same as previous
    // ...or leaves as is if it is the same
    $rank = ($last_value == false || $last_value <> $row["Average"]) ? ++$rank: $rank;

    $end = ($rank > 3) ? $score_ends[4] : $score_ends[$rank] ; // Sets the suffix to the rank using ternary logic
    echo "{$rank}{$end} {$row["StudentReg"]}<br>";             // Prints the result; e.g. 1st 2 {2 == the StudentReg, presumably you'll update that to be a name or something}
    $last_value = $row["Average"];                             // Sets current average as last value ready for next loop
}

输出

1st     2
2nd     6
3rd     10
4th     9
5th     1
5th     5
5th     4
8th     8
9th     12
10th    11
10th    13
10th    14
13th    3
13th    7

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM