【问题标题】:Mysql Pivot table for attendance per weekdays of week每周工作日出勤的Mysql数据透视表
【发布时间】:2016-12-07 18:04:11
【问题描述】:

对于一个日期间隔,我想显示学生每个工作日的出勤记录,记录在三个表 [Attendance, Students, Person] 中。 表的架构(相关字段):

Attendance Table
--------------------- 
Attendance_Identifier 
Student_Identifier 
Classroom_Identifier 
Attendance_Datetime 
Attendance_Value 
...
Student
------------------
Student_Identifier
Person_Identifier
Classroom_Identifier
...

Person
-----------------
Person_Identifier
Frist_Name
Last_Name
Gender
...

预期报告输出:

Gender    Student     Mon     Tue     Wed     Thu     Fri     WeeklyTotal
------------------------------------------------------------------------
Male     Ab Stain     2/10    3/12    1/9     1/10    0/10    7/51
Male     Pre Senter   10/10   12/12   9/9     9/10    10/10   50/51
...
Female    Al Ways     10/10   12/12   9/9     10/10   10/10   51/51
Female    Not Often   5/10    5/12    4/9     4/10    5/10    23/51
...

我还有一个函数可以从日期间隔中获取特定星期几的计数,例如日期间隔 @s、@e 中的总星期一,只需执行以下操作:select get_weekday(@s,@e,0).

所以我对存储过程的查询是:

set @s = '2016-01-01';
set @e = '2016-12-07';
SELECT 
concat(p.Frist_Name, ' ',p.Last_Name) as Student, p.Gender
    ,GROUP_CONCAT(CASE WHEN DATE_FORMAT(Attendance_Datetime, '%a') = 'Mon' 
        THEN CONCAT(COUNT(Attendance_Value),'/',get_weekday(@s,@e,0)) ELSE NULL END) AS Mon
    ,GROUP_CONCAT(CASE WHEN DATE_FORMAT(Attendance_Datetime, '%a') = 'Tue' 
        THEN CONCAT(COUNT(Attendance_Value),'/',get_weekday(@s,@e,1)) ELSE NULL END) AS Tue
    ,GROUP_CONCAT(CASE WHEN DATE_FORMAT(Attendance_Datetime, '%a') = 'Wed' 
        THEN CONCAT(COUNT(Attendance_Value),'/',get_weekday(@s,@e,2)) ELSE NULL END) AS Wed
    ,GROUP_CONCAT(CASE WHEN DATE_FORMAT(Attendance_Datetime, '%a') = 'Thu' 
        THEN CONCAT(COUNT(Attendance_Value),'/',get_weekday(@s,@e,3)) ELSE NULL END) AS Thu
    ,GROUP_CONCAT(CASE WHEN DATE_FORMAT(Attendance_Datetime, '%a') = 'Fri' 
        THEN CONCAT(COUNT(Attendance_Value),'/',get_weekday(@s,@e,4)) ELSE NULL END) AS Fri
    , SUM(COUNT(Attendance_Value)) as WeeklyTotal
FROM Attendance a JOIN Student s ON s.Student_Identifier=a.Student_Identifier 
JOIN Person p ON p.Person_Identifier=s.Person_Identifier 
WHERE date(Attendance_Datetime) BETWEEN @s AND @e AND a.Classroom_Identifier = '363'
AND (Attendance_Value = 'Present' OR Attendance_Value = 'Late') AND (p.Gender = 'Male' OR p.Gender = 'Female') 
AND DATE_FORMAT(Attendance_Datetime, '%a') !='Sat' AND DATE_FORMAT(Attendance_Datetime, '%a')!='Sun' 
GROUP BY p.Gender, Student, WeeklyTotal ORDER BY p.Gender, Student;

即使对代码进行了多次调整,我每次都会收到以下组函数错误。

Error Code: 1111. Invalid use of group function

编辑

根据@Solarflare 的第一个建议(我不知道如何尝试第二个),我将查询改进为:

SELECT 
concat(p.Frist_Name, ' ',p.Last_Name) as Student, p.Gender
    ,CONCAT(CASE WHEN DATE_FORMAT(Attendance_Datetime, '%a') = 'Mon' 
        THEN COUNT(Attendance_Value) ELSE 0 END,'/',get_weekday(@s,@e,0) ) AS Mon
    ,CONCAT(CASE WHEN DATE_FORMAT(Attendance_Datetime, '%a') = 'Tue' 
        THEN COUNT(Attendance_Value) ELSE 0 END,'/',get_weekday(@s,@e,1) ) AS Tue
    ,CONCAT(CASE WHEN DATE_FORMAT(Attendance_Datetime, '%a') = 'Wed' 
        THEN COUNT(Attendance_Value) ELSE 0 END,'/',get_weekday(@s,@e,2) ) AS Wed
    ,CONCAT(CASE WHEN DATE_FORMAT(Attendance_Datetime, '%a') = 'Thu' 
        THEN COUNT(Attendance_Value) ELSE 0 END,'/',get_weekday(@s,@e,3) ) AS Thu
    ,CONCAT(CASE WHEN DATE_FORMAT(Attendance_Datetime, '%a') = 'Fri' 
        THEN COUNT(Attendance_Value) ELSE 0 END,'/',get_weekday(@s,@e,4) ) AS Fri
    , COUNT(Attendance_Value) as WeeklyTotal
FROM Attendance a JOIN Student s ON s.Student_Identifier=a.Student_Identifier 
JOIN Person p ON p.Person_Identifier=s.Person_Identifier 
WHERE date(Attendance_Datetime) BETWEEN @s AND @e AND a.Classroom_Identifier = '363'
AND (Attendance_Value = 'Present' OR Attendance_Value = 'Late') AND (p.Gender = 'Male' OR p.Gender = 'Female') 
AND DATE_FORMAT(Attendance_Datetime, '%a') !='Sat' AND DATE_FORMAT(Attendance_Datetime, '%a')!='Sun' 
GROUP BY Student,Gender,DATE_FORMAT(Attendance_Datetime, '%a') ORDER BY p.Gender, Student,Mon DESC;

结果如下:

【问题讨论】:

  • 您不能使用group_concat(count()),这将是一个双组。我认为您根本不需要 group_concat ;你可能可以把箱子放在count() 里面,比如concat(count(case when ... = 'Wed' ... else null end), ' /', ...) 等等。如果没有,请先为枢轴创建子查询,然后是格式化内容。
  • 感谢@Solarflare 的建议,第一个帮助使输出几乎达到预期,请参阅主要问题编辑,看看您是否提供进一步帮助:)
  • 您按工作日分组。所以你每天得到一排。你不想要那个。将整个 case...end 放在计数中。如果您提供表格创建和示例数据(例如,作为 sql fiddle),我可以对其进行测试,但我认为我在第一条评论中发布的代码应该可以工作。
  • 嗨@Solarflare,您的建议有所帮助,但仍不如预期。请看一下sql fiddle。 sqlfiddle.com/#!2/fd93f/1

标签: mysql sql pivot-table mysql-workbench


【解决方案1】:

只剩下一些小事让它工作,试试这个:

SELECT 
  concat(p.Frist_Name, ' ',p.Last_Name) as Student, p.Gender
  ,concat(cast(COUNT(CASE WHEN weekday(Attendance_Datetime) = 0
     then 1 END) as char), '/', get_weekday(@s,@e,0)) as Mon
  ,concat(cast(COUNT(CASE WHEN weekday(Attendance_Datetime) = 1
     then 1 END) as char), '/', get_weekday(@s,@e,1)) as Tue
  ,concat(cast(COUNT(CASE WHEN weekday(Attendance_Datetime) = 2
     then 1 END) as char), '/', get_weekday(@s,@e,2)) as Wed
  ,concat(cast(COUNT(CASE WHEN weekday(Attendance_Datetime) = 3
     then 1 END) as char), '/', get_weekday(@s,@e,3)) as Thu
  ,concat(cast(COUNT(CASE WHEN weekday(Attendance_Datetime) = 4
     then 1 END) as char), '/', get_weekday(@s,@e,4)) as Fri
  ,COUNT(Attendance_Value) as WeeklyTotal
FROM Attendance a 
JOIN Student s ON s.Student_Identifier=a.Student_Identifier 
JOIN Person p ON p.Person_Identifier=s.Person_Identifier 
WHERE date(Attendance_Datetime) BETWEEN @s AND @e 
  AND a.Classroom_Identifier = '363'
  AND (Attendance_Value = 'Present' OR Attendance_Value = 'Late') 
  AND (p.Gender = 'Male' OR p.Gender = 'Female') 
  AND weekday(Attendance_Datetime) not in (5,6)
GROUP BY Student, Gender ORDER BY p.Gender, Student, Mon DESC;

枢轴是用case 完成的,它在日期具有正确的工作日时计数。否则值为null(不是0),才不算数(else null不必写)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-07
    • 2016-06-10
    相关资源
    最近更新 更多