使用mysql查询计算连续缺席总数和百分比计算
Posted
技术标签:
【中文标题】使用mysql查询计算连续缺席总数和百分比计算【英文标题】:Counting total number of consecutive absent and percentage calculation using mysql query 【发布时间】:2017-10-17 23:54:58 【问题描述】:我有两张桌子; student
和 attendance
:
学生桌:
sid name
----- --------
s1 nam1
s2 nam2
s3 nam3
s4 nam4
s5 nam5
考勤表:
sid status date sub_id
----- -------- --------- ------
s1 present 2017-05-16 ms100
s2 present 2017-05-16 ms100
s3 absent 2017-05-16 ms100
s4 present 2017-05-16 ms100
s5 present 2017-05-16 ms100
s1 present 2017-05-17 ms100
s2 present 2017-05-17 ms100
s3 absent 2017-05-17 ms100
s4 present 2017-05-17 ms100
s5 absent 2017-05-17 ms100
s1 present 2017-05-16 ms101
s2 present 2017-05-16 ms101
s3 absent 2017-05-16 ms101
s4 present 2017-05-16 ms101
s5 absent 2017-05-16 ms101
现在我想显示学生在哪一天在场或缺席,还想计算科目 id ms100 的每个学生的总上课次数、连续缺勤率和出勤率。
对于连续失踪/缺席,我只想考虑最后一次连续失踪/缺席。例如,如果 s1 在第 1、6、7 天出现 10 天,那么他的 con_missing 将是 3
而不是 5
。如果 s1 在第 9 天出现,那么他的 con_missing 将为 0,因为我只想在学生缺席超过 1 天时才考虑连续失踪。
例如,sid s1,s2,s4
的学生出现在 subject ms100
的所有 2 个班级中,因此他们的 total number of attended class
将是 2,因为出现在所有班级中,所以他们的 total number of consecutive absent
将是 0
和 @ 987654332@ 将是 (total attended class/total class)*100
在这种情况下是 100 %
。另一方面,s3
在所有课程中都缺席,因此他的total number of attended class
和percentage
将是0
和total number of consecutive absent
将是2。
对于学生 ID s5,consecutive absent
将是 0
,因为他只缺席了一天。
我希望得到类似以下模式的结果,其中主题 ms100
的每个单独上课日期将显示为列,并且在该特定日期单个学生的出勤状态(存在/缺席)将显示为该列的值:
sid name 2017-05-16 2017-05-17 consecutive_absnt total_atn %
----- ----- ---------- --------- ---------------- --------- ----
s1 nam1 present present 0 2 100
s2 nam2 present present 0 2 100
s3 nam3 absent absent 2 0 0
s4 nam4 present present 0 2 100
s5 nam5 present absent 0 1 50
我使用Angularjs
作为字体末端和php 作为后端。这是我迄今为止尝试过的
php
$query="
SELECT atn.sid
, atn.date
, atn.status
, s.name
FROM attendance atn
join student s
on atn.sid = s.sid
where atn.sub_id = 'ms100'
ORDER
BY atn.date
, atn.sid
";
$result = $mysqli->query($query) or die($mysqli->error.__LINE__);
$arr = array();
if($result->num_rows > 0)
while($row = $result->fetch_assoc())
$arr[] = $row;
# JSON-encode the response
$json_response = json_encode($arr);
// # Return the response
echo $json_response;
angularjs
<table class="table table-striped table-bordered">
<thead>
<th>sid</th>
<th>name</th>
<th ng-repeat="data in list | unique: 'date'">data.date</th>
<th>consecutive missing</th>
<th>total attended </th>
<th>%</th>
</thead>
<tbody>
<tr ng-repeat="data in filtered = (list | filter:search | orderBy : predicate :reverse) | startFrom:(currentPage-1)*entryLimit | limitTo:entryLimit">
<td>data.sid</td>
<td>data.name</td>
<td>data.status</td>
<td>data.consecutive</td>
<td>data.total_atn</td>
<td>data.percentage</td>
</tbody>
</table>
得到这样的结果
sid name 2017-05-16 2017-05-17 con_missing totl_atend %
----- -------- --------- ---------- -------- -------- ---
s1 nam1 present
s2 nam2 present
s3 nam3 absent
s4 nam4 present
s5 nam5 present
s1 nam1 present
s2 nam2 present
s3 nam3 absent
s4 nam4 present
s5 nam5 absent
那么如何通过mysql查询达到我预期的结果呢?
【问题讨论】:
我猜这应该比您指定的两个日期有效?如果是这样,它应该总是添加更多的列吗?如果您想检查多个星期,那将是大量的列。还有, con_missing 应该如何在更长的时间跨度内工作?如果您检查 10 天并且 s1 在第 1、6、7 天出现。那么前 4 天是连续的,然后是 3 天。应该如何呈现?还是应该一直只有两个日期?我们需要更多信息在这里.. 是的,这里的日期不固定。日期将取决于特定主题有多少独特的“日期”条目,例如,如果主题“ms100”总共完成了 10 个讲座,那么我们有 10 个唯一日期,如果完成更多讲座,那么我们就有更多日期,即完全不知道有多少个日期。我想在讲座完成时选择那些唯一日期,并希望在这些日期显示学生的出勤状态。对于con_missing 我只想考虑最后一次连续丢失。如果 s1 在第 1、6、7 天出现,那么他的 con_missing 将是 3 而不是 5。 【参考方案1】:好的,这需要一段时间才能聚在一起:)
首先我们在mysql数据库中设置一个函数来获取连续天数:
CREATE FUNCTION `getConsecutive`( _subid varchar(45), _sid varchar(45) ) RETURNS int(11)
BEGIN
declare ret int;
select max(consecutive) into ret from (
select q.date,
q.status,
@consecutive := CASE WHEN @stop = 1 THEN 0 WHEN q.status = 'absent' THEN @consecutive +1 ELSE 0 END as consecutive,
@started := CASE WHEN @consecutive > 0 OR @started > 0 THEN 1 ELSE 0 END as started,
@stop := CASE WHEN @consecutive = 0 AND @started > 0 THEN 1 ELSE @stop END as stop
from (
select date, status from Attendance where sub_id = _subid and sid = _sid order by date desc
) q,
(select @consecutive := 0) r,
(select @started := 0) r2,
(select @stop := 0) r3
) as z;
RETURN CASE WHEN ret = 1 THEN 0 ELSE ret END;
END
然后我们构建 sql,但硬编码以测试 2 列:
SELECT atn.sid, s.name,
MAX(IF(atn.date = '2017-05-16', atn.date, null)) `2017-05-16`,
MAX(IF(atn.date = '2017-05-17', atn.date, null)) `2017-05-17`,
getConsecutive(atn.sub_id, atn.sid) consecutive_absnt,
SUM(CASE WHEN atn.status = 'present' THEN 1 ELSE 0 END) total_atn,
ROUND(100*(SUM(CASE WHEN atn.status = 'present' THEN 1 ELSE 0 END)/count(1)), 2) '%'
FROM Attendance atn
join Student s
on atn.sid = s.sid
where atn.sub_id = 'ms100'
GROUP BY atn.sid, s.name;
然后我们知道它可以工作,但主要问题是它是动态数量的列。所以你需要做的就是将它分成几部分。
我们需要一个存储过程来构建和执行我们的动态 sql。
CREATE PROCEDURE `getData`(_subId VARCHAR(45))
BEGIN
select GROUP_CONCAT(CAST(CONCAT('MAX(IF(atn.date = \'', dd, '\', atn.date, null)) `', dd, '`\n') AS CHAR)) INTO @builtSql
from (
select distinct str_to_date(date, '%Y-%m-%d') dd from Attendance where sub_id = _subId
) q
;
SET @builtSql = CONCAT('SELECT atn.sid,
s.name,', @builtSql, ',
getConsecutive(atn.sub_id, atn.sid) consecutive_absnt,
SUM(CASE WHEN atn.status = \'present\' THEN 1 ELSE 0 END) total_atn,
ROUND(100*(SUM(CASE WHEN atn.status = \'present\' THEN 1 ELSE 0 END)/count(1)), 2) \'%\'
FROM Attendance atn
join Student s on atn.sid = s.sid
where atn.sub_id = \'', _subId,'\'
GROUP BY atn.sid, s.name');
PREPARE stmt FROM @builtSql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
构建动态sql通常是个坏主意,因为存在sql注入的风险,所以我建议你对发送到存储过程的数据做一些检查。
然后你可以调用存储过程来得到你想要的结果。
call getData('ms100')
【讨论】:
非常感谢您的辛勤工作。对不起,我从未使用过这种类型的程序,所以我不知道如何在 php 中使用此查询来实现我预期的结果表。可以你提供了一些关于这个问题的指南? 嗨。只需在服务器上运行创建查询(一个用于存储过程,一个用于函数)(直接在 mysql ide 中,例如工作台)。先运行函数,再运行存储过程。然后运行命令“call getDate('ms100');”对其进行测试。如果一切正常,那么您只需从 php 运行该命令,这里有一个示例:***.com/questions/3966747/… @query,如果您需要更多信息或有什么问题,请告诉我!以上是关于使用mysql查询计算连续缺席总数和百分比计算的主要内容,如果未能解决你的问题,请参考以下文章