我正在使用 Mysql DB 在 php 中做一个学校管理系统。我被困在我的项目中。请任何人建议我做错了什么。
我的数据库中有两个表;一个是存储Students记录,另一个是attendance明智地存储他们的日常
现在我想显示当月特定班级所有学生的报告,无论他们在场还是缺席。但我只在出勤表中捕获缺席学生的详细信息。
我写了 sql 查询来显示这里的结果是:
SELECT tab.class, attend, DATE, ta.rollno, ta.StdNm
FROM tbl_absentees tab, tbl_admission ta
WHERE ta.Cls = class
AND ta.rollno = tab.rollno
AND class =22
AND attend = 'A'
AND DATE = '2013-06-07';
Run Code Online (Sandbox Code Playgroud)
结果是:
Class Attend RollNo StudentName
Run Code Online (Sandbox Code Playgroud)
但我想以 31 天的表格方式显示,如果出席=A 显示 A 表示缺席天数,否则显示“P”表示剩余天数
我怎样才能在mysql中做到这一点?任何人都可以建议/给我一个想法来实现这一目标。
对不起,我的问题有误。实际上,我想显示特定月份的出勤报告,其中数据来自两个表:
现在我想显示象报告这样。
Tar*_*ryn 18
这种从列到行的数据旋转称为 PIVOT。MySQL 没有数据透视函数,但您可以使用带有 CASE 表达式的聚合函数来获取结果。
我的第一个建议是确定您是否有一个calendar表格或一个包含您要显示的所有日期的表格。如果没有,那么我建议创建一个类似于以下内容:
CREATE TABLE calendar (`Date` datetime) ;
INSERT INTO calendar (`Date`)
VALUES
('2013-06-01 00:00:00'),
('2013-06-02 00:00:00'),
('2013-06-03 00:00:00'),
('2013-06-04 00:00:00'),
('2013-06-05 00:00:00'),
('2013-06-06 00:00:00'),
('2013-06-07 00:00:00'),
('2013-06-08 00:00:00'),
('2013-06-09 00:00:00'),
('2013-06-10 00:00:00');
Run Code Online (Sandbox Code Playgroud)
这将使您可以生成要显示的所有日期的列表。
其次,您需要生成每个学生和每个日期的列表。您可以通过在您tbl_admission和calendar表之间使用 CROSS JOIN 来做到这一点:
select c.date, a.studentname, a.rollno, a.class
from calendar c
cross join tbl_admission a;
Run Code Online (Sandbox Code Playgroud)
见演示。获得此列表后,您可以对现有tbl_absentees表使用 LEFT JOIN以获得结果:
select
ca.studentname,
ca.rollno,
ca.class,
max(case when ca.date = '2013-06-01' then coalesce(p.status, 'P') end) `2013-06-01`,
max(case when ca.date = '2013-06-02' then coalesce(p.status, 'P') end) `2013-06-02`,
max(case when ca.date = '2013-06-03' then coalesce(p.status, 'P') end) `2013-06-03`,
max(case when ca.date = '2013-06-04' then coalesce(p.status, 'P') end) `2013-06-04`,
max(case when ca.date = '2013-06-05' then coalesce(p.status, 'P') end) `2013-06-05`,
max(case when ca.date = '2013-06-06' then coalesce(p.status, 'P') end) `2013-06-06`,
max(case when ca.date = '2013-06-07' then coalesce(p.status, 'P') end) `2013-06-07`,
max(case when ca.date = '2013-06-08' then coalesce(p.status, 'P') end) `2013-06-08`,
max(case when ca.date = '2013-06-08' then coalesce(p.status, 'P') end) `2013-06-09`,
max(case when ca.date = '2013-06-10' then coalesce(p.status, 'P') end) `2013-06-10`
from
(
select c.date, a.studentname, a.rollno, a.class
from calendar c
cross join tbl_admission a
) ca
left join tbl_absentees p
on ca.rollno = p.rollno
and ca.date = p.date
group by ca.studentname, ca.rollno, ca.class
order by ca.rollno;
Run Code Online (Sandbox Code Playgroud)
请参阅SQL Fiddle with Demo。当然,对于您的请求,您很可能希望根据日期范围查询数据,因此您不想对值进行硬编码。如果是这种情况,那么您将需要考虑使用准备好的语句来生成动态 SQL:
SET @sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'max(CASE WHEN ca.date = ''',
date_format(date, '%Y-%m-%d'),
''' THEN coalesce(p.status, ''P'') END) AS `',
date_format(date, '%Y-%m-%d'), '`'
)
) INTO @sql
FROM calendar
where date>='2013-06-01'
and date <= '2013-06-05';
SET @sql
= CONCAT('SELECT ca.studentname,
ca.rollno,
ca.class, ', @sql, '
from
(
select c.date, a.studentname, a.rollno, a.class
from calendar c
cross join tbl_admission a
) ca
left join tbl_absentees p
on ca.rollno = p.rollno
and ca.date = p.date
where ca.date>=''2013-06-01''
and ca.date <= ''2013-06-05''
group by ca.studentname, ca.rollno, ca.class
order by ca.rollno');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Run Code Online (Sandbox Code Playgroud)
请参阅SQL Fiddle with Demo。这两个查询都会给出类似于以下内容的结果:
| STUDENTNAME | ROLLNO | CLASS | 2013-06-01 | 2013-06-02 | 2013-06-03 | 2013-06-04 | 2013-06-05 | 2013-06-06 | 2013-06-07 | 2013-06-08 | 2013-06-09 | 2013-06-10 |
------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Naren | 1 | 22 | A | A | A | A | P | P | P | P | P | P |
| Srinu | 2 | 22 | P | P | P | P | P | P | P | P | P | P |
| Blah | 3 | 22 | A | P | P | P | P | P | P | P | P | P |
Run Code Online (Sandbox Code Playgroud)