我有两张桌子; 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
现在我想显示学生出席或缺席的日期,还要计算每个学生的主要入学分数,连续缺席和出勤率百分比ms100。
对于连续缺失/缺席我想只考虑最后连续缺失/缺席。例如,如果在第1天,第6天,第7天出现s1,那么他的结果将是3
而不是{{1 }}。如果s1在第9天出现,那么他的结果将为0,因为我想考虑连续失踪,只有当学生缺席超过1天时才会出现。
例如,5
的所有2个班级中都有sid s1,s2,s4
的学生,因此他们的subject ms100
将为2,因为所有班级都有total number of attended class
在这种情况下,total number of consecutive absent
和0
将是percentage
,{(total attended class/total class)*100}
。另一方面,所有课程中都缺少100 %
,因此他的s3
和total number of attended class
将为percentage
而0
将为2。
对于学生ID s5,total number of consecutive absent
将为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
作为字体结尾而php作为后端。这是我到目前为止所尝试的
PHP
Angularjs
angularjs
$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;
获得这样的结果
<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>
那么如何通过mysql查询实现我的预期结果呢?
答案 0 :(得分: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')