计算mysql中一行中的项目数

计算mysql中一行中的项目数,mysql,select,join,group-by,Mysql,Select,Join,Group By,我有一份学生名单,显示他们是否在某个特定的班级上课 CREATE TABLE classlist (`id` int, `studentid` int, `subjectid` int, `presentid` int) ; CREATE TABLE student (`id` int, `name` varchar(4)) ; CREATE TABLE subject (`id` int, `name`

我有一份学生名单,显示他们是否在某个特定的班级上课

    CREATE TABLE classlist
        (`id` int, `studentid` int, `subjectid` int, `presentid` int)
    ;

    CREATE TABLE student
        (`id` int, `name` varchar(4))
    ;

    CREATE TABLE subject
        (`id` int, `name` varchar(4))
    ;

    CREATE TABLE classStatus
        (`id` int, `name` varchar(8))
    ;

    INSERT INTO classlist
        (`id`, `studentid`, `subjectid`, `presentid`)
    VALUES
        (1, 111, 1, 1),
        (2, 222, 3, 0),
        (3, 333, 2, 1),
        (4, 111, 4, 0),
        (5, 111, 1, 1),
        (6, 222, 3, 0),
        (7, 333, 2, 1),
        (8, 111, 4, 0),
        (9, 111, 4, 0),
        (10, 111, 4, 0),
        (11, 111, 1, 1),
        (12, 333, 3, 1),
        (13, 333, 2, 1),
        (14, 333, 3, 1)
    ;

    INSERT INTO student
        (`id`, `name`)
    VALUES
    (111, 'John'),
    (222, 'Kate'),
    (333, 'Matt')
    ;

    INSERT INTO subject
        (`id`, `name`)
    VALUES
    (1, 'MATH'),
    (2, 'ENG'),
    (3, 'SCI'),
    (4, 'GEO')
    ;

    INSERT INTO classStatus
        (`id`, `name`)
    VALUES
    (0, 'Absent'),
    (1, 'Present')
    ;
看小提琴

我可以数一数谁缺席了,并用下面这样的东西整体呈现

    SELECT
       studentid,
       students.name AS NAME,
       SUM(presentid = 1) AS present,
       SUM(presentid = 0) AS absent

    FROM classlist
    INNER JOIN student as students ON classlist.studentid=students.id

     GROUP BY studentid, NAME
但我想知道一个学生连续上了/没上多少课,因此,老师们可以很容易地看到,是否有人错过了很多时间,或者有人因为出勤率高而得到奖励等。我看到一些帖子谈论连胜,但没有一个帖子似乎与数据呈现给我的方式相匹配,所以我不确定如何做到这一点

根据我下面的样本数据,需要明确的是,条纹的输出应该是

        (1, 111, 1, 1), /* John Present 1 times in a row */
        (2, 222, 3, 0), /* Kate Absent 1 times in a row */
        (3, 333, 2, 1), /* Matt Present 1 times in a row */
        (4, 111, 4, 0), /* John Absent 1 times in a row */
        (5, 111, 1, 1), /* John Present 1 times in a row */
        (6, 222, 3, 0), /* Kate Absent 2 times in a row */
        (7, 333, 2, 1), /* Matt Present 2 times in a row */
        (8, 111, 4, 0), /* John Absent 1 times in a row */
        (9, 111, 4, 0), /* John Absent 2 times in a row */
        (10, 111, 4, 0), /* John Absent 2 times in a row */
        (11, 111, 1, 1), /* John Present 1 times in a row */
        (12, 333, 3, 1), /* Matt Present 3 times in a row */
        (13, 333, 2, 1), /* Matt Present 4 times in a row */
        (14, 333, 3, 1) /* Matt Present 5 times in a row */
        /*Showing the latest status for each user*/
        /* John Present 1 times in a row */
        /* Kate Absent 2 times in a row */
        /* Matt Present 5 times in a row */
约翰现在1

凯特2号缺席

马特现在5.你想要这个吗

SELECT
   studentid,
   name,
   SUM(present = 1) AS present,
   SUM(present = 0) AS absent,
   count(subject) as classTimes,
   subject
   FROM your_table GROUP BY studentid, name,subject
试试这个:

SELECT A.studentid, s.name, IF(presentid = 1,  'present', 'absent') STATUS, 
       ABS(SUM(IF(presentid = 1, 1, -1))) AS presentcnt
FROM classlist A 
INNER JOIN student s ON A.studentid = s.id 
LEFT JOIN (SELECT MAX(id) id, studentid 
           FROM classlist GROUP BY studentid
          ) B ON A.studentid = B.studentid AND A.id = B.id 
GROUP BY A.studentid
检查这个

输出


我不知道你的问题有什么意义。 如果你想要这个

约翰现在1

凯特2号缺席

马特现在5岁

你可以试试这个:

SELECT
   studentid,
   students.name AS NAME,
   SUM(presentid = 1) AS present,
   SUM(presentid = 0) AS absent,
   IF( SUM(presentid = 1)-SUM(presentid = 0)>=0,SUM(presentid = 1)-SUM(presentid = 0),SUM(presentid = 0)-SUM(presentid = 1)) AS aliase
FROM classlist
  INNER JOIN student as students ON classlist.studentid=students.id
GROUP BY studentid, NAME
如果类列表中的id可以用于排序,那么您将使用

SELECT 
  s.name,
  CASE t1.presentid
    WHEN 0 THEN 'absent'
    WHEN 1 THEN 'present'
  END state,
  t1.pc  
FROM (
  SELECT
    c.id,
    c.studentid,
    c.presentid,
    @pcount := IF( @pid = presentid AND @sid = studentid, @pcount + 1, 1 ) as pc,
    @pid := presentid,
    @sid := studentid
  FROM
    classlist c
  ORDER BY
    studentid, id ) t1
  JOIN student s 
    ON t1.studentid = s.id
WHERE
  ( t1.studentid, t1.id ) IN ( SELECT 
                                 studentid, 
                                 MAX( id ) 
                               FROM classlist 
                               GROUP BY studentid );

这应给出与最后一行具有相同值的连续行的计数:

select
  classlist.studentid,
  student.name,
  classStatus.name status,
  count(*) presentcnt
from
  classlist inner join student
  on classlist.studentid=student.id
  inner join classstatus
  on classlist.presentid=classstatus.id
  inner join (
    select
      studentid,
      max(case when presentid=0 then id end)  max_0,
      max(case when presentid=1 then id end)  max_1
    from classlist
    group by studentid
  ) s
  on coalesce(classlist.id>least(max_0,max_1) and
       classlist.id<=greatest(max_0,max_1),1)
  and s.studentid=classlist.studentid
group by classlist.studentid
在子查询中,我正在提取presentid=0的max id和presentid=1的max id


在外部查询中,我提取并计算id大于max_0和max_1中最小值的所有行,您能显示输出吗?请阅读有关数据库规范化的内容。@Hammerite感谢您的反馈,我对这个问题进行了编辑,以更紧密地反映我在这个问题中使用的数据明显较少,但结构是相同的。我现在和第一个问题的观点一样。谢谢,他们连续上了多少节课/没上多少节课,我现在更高兴了。我不太确定这是否会发生?这似乎很有效,除非我对它运行您的查询:John在上一节课时缺席1节课=1?您希望每个学生的最后一行都有缺席状态吗?是的,但计算该状态在一行中存在多少次?如果这有意义的话?这对于当前的数据集来说很好,谢谢,但是如果我将例如10111,'John',4,0更改为10111,'John',4,1,我希望看到John移动到2,但他仍然停留在1?因为检查你的例子,它包括3个当前条目和4个缺席条目,现在如果你将约翰的一个条目从缺席更改为当前条目,那么他的条目将变为4个当前条目和3个缺席条目。所以在这两种情况下,在场和缺席的差异都变成了1,所以你给约翰的分数是1。@SirRufo这看起来不错,唯一值得关注的是,你不能真正分辨出伯爵在场还是缺席,你可以在你的帐户中分辨出吗?@ak85你应该再次检查一下。。。我刚刚编辑了这个答案;o状态存在,但未通过SQLFiddle显示;o@SirRufo感谢您的upvote和编辑:没有别名,SQLFiddle仅在名称相同时显示第一列:@fthiella+1用于搜索赏金;快速的性能和ANSI@bonCodigo谢谢:我不确定最不重要和最伟大的是ANSI,还是使用COALESCE…,1和booleans。。。但是它只是简单的SQL,如果需要的话可以变成ansi:我可以这样写查询,因为只有两个值,存在和不存在,否则它会更复杂:
select
  classlist.studentid,
  student.name,
  classStatus.name status,
  count(*) presentcnt
from
  classlist inner join student
  on classlist.studentid=student.id
  inner join classstatus
  on classlist.presentid=classstatus.id
  inner join (
    select
      studentid,
      max(case when presentid=0 then id end)  max_0,
      max(case when presentid=1 then id end)  max_1
    from classlist
    group by studentid
  ) s
  on coalesce(classlist.id>least(max_0,max_1) and
       classlist.id<=greatest(max_0,max_1),1)
  and s.studentid=classlist.studentid
group by classlist.studentid