在 MySql 中显示月度考勤报告

Nar*_*_CH 8 mysql pivot

我正在使用 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中做到这一点?任何人都可以建议/给我一个想法来实现这一目标。

对不起,我的问题有误。实际上,我想显示特定月份的出勤报告,其中数据来自两个表:

  • 第一个表由 StudentName、RollNo、Class 组成
  • 第二个表由日期、状态、滚动编号、类别组成

现在我想显示象报告这样

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_admissioncalendar表之间使用 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)