【问题标题】:Using SQL to make calculation based on some given criteria使用 SQL 根据给定条件进行计算
【发布时间】:2016-08-18 16:09:42
【问题描述】:

在我构建的一个考试应用程序中,我还没有想出一种方法来提出一个 SQL 语句来使这项任务成为可能。我国的评分系统只要求计算7个科目。在这些科目中,所有语言都是必修的(在图片演示中标记为 lang)。计算了 2 种最好的科学(标记为 sci)。一个人类(标记为嗡嗡声)。第 7 个科目可能是技术科目(标记为 tech)、科学或人文学科,取决于哪个科目得分最高。例如,给定表中的学生将计算 MAT、ENG、KISW、PHY、CHEM、HIST 和 BST 的分数。我使用数组编写了 PHP 代码,它占用了太多的内存和时间,这让我担心它会使服务器停止运行。看看下面的代码,

function calculatePointsB($adm,$term,$class,$year,$exam){
global $db;

$points=array(
    "A"=>12,
    "A-"=>11,
    "B+"=>10,
    "B"=>9,
    "B-"=>8,
    "C+"=>7,
    "C"=>6,
    "C-"=>5,
    "D+"=>4,
    "D"=>3,
    "D-"=>2,
    "E"=>1
);
$choices=array();
$countable=array();
$monitor=array();
$grades=array();

$common_query_all=$db->prepare("SELECT marks,subject,sub_cat FROM averaged_marks WHERE adm_no=? AND sub_cat=? AND term=? AND class=? AND year=?");
$common_query_sp=$db->prepare("SELECT marks,subject,sub_cat FROM exmarks WHERE adm_no=? AND sub_cat=? AND term=? AND class=? AND year=? AND e_type=?");
//languages first
$langs=array();
if($exam=="All") {
    $getlang = $common_query_all;
    $getlang->execute(array($adm, "lang", $term, $class, $year));
}else{
    $getlang = $common_query_sp;
    $getlang->execute(array($adm, "lang", $term, $class, $year,$exam));
}
while($rst=$getlang->fetch(PDO::FETCH_ASSOC)){
    if($rst['marks']!=null) {
        $langs[$rst['subject']] = $rst['marks'];
        $grades[$rst['subject']]=$points[$rst['grade']];
        $countable[$rst['subject']] = $rst['marks'];
        array_push($monitor,$rst['sub_cat']);
    }else continue;
} unset($rst);

//sciences
$sciences=array();
if($exam=="All") {
    $getlang = $common_query_all;
    $getlang->execute(array($adm, "sci", $term, $class, $year));
}else{
    $getlang = $common_query_sp;
    $getlang->execute(array($adm, "sci", $term, $class, $year,$exam));
}
while($rst=$getlang->fetch(PDO::FETCH_ASSOC)){
    if($rst['marks']!=null) {
        $sciences[$rst['subject']] = $rst['marks'];
        array_push($monitor,$rst['sub_cat']);
    }else continue;
}unset($rst);
arsort($sciences);

//humanities
$humanities=array();
if($exam=="All") {
    $getlang = $common_query_all;
    $getlang->execute(array($adm, "hum", $term, $class, $year));
}else{
    $getlang = $common_query_sp;
    $getlang->execute(array($adm, "hum", $term, $class, $year,$exam));
}
while($rst=$getlang->fetch(PDO::FETCH_ASSOC)){
    if($rst['marks']!=null) {
        $humanities[$rst['subject']] = $rst['marks'];
        array_push($monitor,$rst['sub_cat']);
    }else continue;
}unset($rst);
arsort($humanities);

//technicals
$technic=array();
if($exam=="All") {
    $getlang = $common_query_all;
    $getlang->execute(array($adm, "tech", $term, $class, $year));
}else{
    $getlang = $common_query_sp;
    $getlang->execute(array($adm, "tech", $term, $class, $year,$exam));
}
while($rst=$getlang->fetch(PDO::FETCH_ASSOC)){
    if($rst['marks']!=null) {
        $technic[$rst['subject']] = $rst['marks'];
        $choices[$rst['subject']] = $rst['marks'];
    }else continue;
}unset($rst);
arsort($technic);

//add optional subjects to choices array
$iteration=0;
foreach($humanities as $sub => $value){
    $iteration++;
    if($iteration >1 && $iteration <= 3){
        $choices[$sub]=$value;
    }elseif($iteration==1){
        $countable[$sub]=$value;
        if($exam=="All") {
            $grades[$sub] = $points[getgradeinSub($adm, $sub, $term, $class, $year)];
        }else{
            $grades[$sub] = $points[getgradeinSpSub($adm, $sub, $term, $class, $year,$exam)];
        }
    }
}unset($humanities);

$iteration=0;
foreach($sciences as $sub => $value){
    $iteration++;
    if($iteration > 2 && $iteration <= 3){
        $choices[$sub]=$value;
    }elseif($iteration<=2){
        $countable[$sub]=$value;
        if($exam=="All") {
            $grades[$sub] = $points[getgradeinSub($adm, $sub, $term, $class, $year)];
        }else{
            $grades[$sub] = $points[getgradeinSpSub($adm, $sub, $term, $class, $year,$exam)];
        }
    }
}unset($sciences);
arsort($choices);

//get required and view the required number
//count number of keys
$count_compasory=array_count_values($monitor);
if($count_compasory['lang']==3 && $count_compasory['sci']>=2 && $count_compasory['hum']>=1){
    $remaining=7-count($countable);
    $iteration=0;
    foreach($choices as $sub => $value){
        $iteration++;
        if($iteration <= $remaining){
            $countable[$sub]=$value;
            if($exam=="All") {
                $grades[$sub] = $points[getgradeinSub($adm, $sub, $term, $class, $year)];
            }else{
                $grades[$sub] = $points[getgradeinSpSub($adm, $sub, $term, $class, $year,$exam)];
            }
        }
    }
    unset($choices);
    unset($countable);
    unset($monitor);
    unset($langs);
    unset($sciences);
    unset($humanities);
    unset($points);

    return array_sum($grades);
}
else unset($choices);
unset($countable);
unset($monitor);
unset($langs);
unset($sciences);
unset($humanities);
unset($grades);
unset($points);

return null;}

一个好的程序员会认为这是一些不好的做法。有没有办法为此编写 SQL 语句?找到问题的解决方案将是一个突破。下面附上一张桌子的图片。

【问题讨论】:

  • 为我们提供一个 sqlfiddle (sqlfiddle.com) 和一些数据(一个学生的)将大大有助于回答这个问题。在我看来,这应该可以通过一个选择查询和同一张表上的几个内部连接来解决
  • 您的 DBMS 是什么?如果它支持像ROW_NUMBER这样的分析函数,应该是一个简单的任务
  • @Jester,这里是 SQL 小提琴sqlfiddle.com/#!9/b80692
  • @dnoeth,我正在使用 mysql
  • @m69,我改了。我希望它适合。谢谢你的建议:)

标签: php sql algorithm sorting


【解决方案1】:

我能在短时间内想出最好的方法,我采取了与@GarethParker 相同的方法,除了最后一个标记你需要更多。

你可以在sqlfiddle上试试

(SELECT *
FROM averaged_marks
WHERE sub_cat='lang'
ORDER BY marks DESC)             #This select retrieves all 'lang' marks
UNION
(SELECT *
FROM averaged_marks
WHERE sub_cat='sci'
ORDER BY marks DESC
LIMIT 2)             #This select retrieves the highest 2 'sci' marks
UNION
(SELECT *
FROM averaged_marks
WHERE sub_cat='hum'
ORDER BY marks DESC
LIMIT 1)             #This select retrieves the highest 1 'hum' marks
UNION
(SELECT *            #This select retrieves the highest mark of the leftovers
FROM averaged_marks
WHERE averaged_marks.id NOT IN (     #This NOT IN contains the same select as above to get the first 6 marks and to make sure the 7th is not one of them.
    SELECT temp.id
    FROM
        ((SELECT averaged_marks.id
        FROM averaged_marks
        WHERE sub_cat='lang'
        ORDER BY marks DESC)
        UNION
        (SELECT averaged_marks.id
        FROM averaged_marks
        WHERE sub_cat='sci'
        ORDER BY marks DESC
        LIMIT 2)
        UNION
        (SELECT averaged_marks.id
        FROM averaged_marks
        WHERE sub_cat='hum'
        ORDER BY marks DESC
        LIMIT 1)
        ) AS temp)
ORDER BY marks DESC
LIMIT 1)

【讨论】:

  • 它按我的预期工作。我真的很感激你所花的时间,尤其是你获得第 7 分的部分。你完全破解了我要找的东西。干杯!
  • 很高兴我能帮上忙 :) 如果您再次需要一些 mysql 查询帮助,请随时标记我 ^^
  • 再次感谢..我有一个问题。我的 MySQL 版本可能有错误吗?我使用的是 MySQL 5.7,当我运行查询时,它会从另一个录取编号中获取第 7 个主题并选择一种语言(语言)。我的表有大约 5610 条记录。可能是什么问题?
  • 我只是在每个查询中添加了 'AND adm_no=1' 以缩小到单个学生。
  • 不,你没有;) 你需要在NOT IN 子句之后添加一个AND adm_no = 。` 在这里查看:diffchecker.com/uvk07hql 看看区别
【解决方案2】:

如果没有要运行的测试数据,也不愿意创建自己的数据,我会犹豫是否要制作可用的 SQL,但听起来你想要的可能是 UNION 运算符。您可以将多个 SQL 查询的结果与其连接在一起。因此,您可以拥有不同的条件,只需将它们合并即可。同样,下面的 SQL 只是一个示例,它可能不起作用,您可能需要自己调整它

SELECT * FROM exmarks WHERE sub_cat='lang'
UNION
SELECT * FROM exmarks WHERE sub_cat='sci' ORDER BY mark DESC LIMIT 2
UNION
SELECT * FROM exmarks WHERE sub_cat='hum' ORDER BY mark DESC LIMIT 1
UNION
SELECT * FROM exmarks WHERE sub_cat NOT IN ('lang', 'sci', 'hum') ORDER BY mark DESC LIMIT 1

【讨论】:

  • 最后一个并集不正确。它应该采用尚未采用的最高值。所以它可能来自“lang”、“sci”、“hum”。在他的例子中,情况并非如此。
猜你喜欢
  • 2014-09-20
  • 1970-01-01
  • 1970-01-01
  • 2021-08-30
  • 1970-01-01
  • 1970-01-01
  • 2018-08-07
  • 2021-08-31
  • 1970-01-01
相关资源
最近更新 更多