2

我有一个学生列表,显示他们是否在特定班级中。

    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')
    ;

见小提琴http://sqlfiddle.com/#!2/a2d93/5

我可以计算出谁缺席并总体呈现如下内容。

    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。

4

5 回答 5

3

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

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 的最大 id 和 presentid = 1 的最大 id。

在外部查询中,我提取并计算 id 大于 max_0 和 max_1 中的最小值且 <= 大于这两者中的最大值的所有行。不管最后一个值是什么,这些都是与最后一个具有相同值的行。

如果其中一个max_0max_1为空,则意味着所有行只有一个值,1 或 0,我们必须获取所有行。如果 max_0 或 max_1 之一为空,则整个条件也将为空。使用Coalesce( condition, 1) 在这种情况下,我将返回所有行。

请注意,我正在分组classlist.studentid并显示一些非聚合列,但这是允许的情况,因为所有非聚合列都具有相同的值。

于 2013-01-11T01:01:00.160 回答
1

你想要这个吗?:

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
于 2013-01-07T08:42:12.127 回答
1

试试这个:

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

检查这个SQL FIDDLE 演示

输出

| STUDENTID | NAME |  STATUS | PRESENTCNT |
-------------------------------------------
|       111 | John | present |          1 |
|       222 | Kate |  absent |          2 |
|       333 | Matt | present |          5 |
于 2013-01-07T09:47:06.483 回答
1

如果idfromclasslist可用于订购,那么您将获得预期的结果

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 );

SQL 小提琴演示

于 2013-01-10T22:31:17.413 回答
0

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

约翰礼物 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
于 2013-01-07T10:04:29.840 回答