2

我在mysql数据库中有一个学生出勤视图,如下所示

id    date         grade
239   01/09/2012   1
239   02/09/2012   0
239   04/09/2012   0
239   05/09/2012   1
239   07/09/2012   0
239   25/09/2012   0
239   26/09/2012   0

而且我在数据库中也有一个请假申请表,如下所示。其中批准 = 1,拒绝 = 0。

id  uid    from            to           status
 1   239    04/09/2012    07/09/2012  approved
 2   239    26/09/2012    26/09/2012  rejected

现在我想创建一个查询来显示批准的休假和学生的最终成绩,如下所示

id    date       grade    leave   Fgrade
239   01/09/2012   1                 1
239   02/09/2012   0                 0
239   04/09/2012   0       1         1
239   05/09/2012   1       1         1    
239   07/09/2012   0       1         1
239   25/09/2012   0                 0
239   26/09/2012   0                 0

请告诉我怎样才能得到这个结果。

4

2 回答 2

4

修改的

(根据后面评论中提供的说明进行修改:)

SELECT a.id
     , a.date
     , a.grade
     , NULLIF(MAX(l.id) IS NOT NULL,0) AS leave
     , IF(MAX(l.id) IS NULL,a.grade,1) AS fgrade
  FROM student_attendance a
  LEFT
  JOIN leave_application l 
    ON l.uid = a.id
   AND l.from <= a.date
   AND l.to + INTERVAL 1 DAY > a.date
   AND l.status = 'Approved'
 GROUP BY a.id, a.date, a.grade

为了性能,您可能需要索引

... ON `student_attendance` (`id`, `date`, `grade`) 
... ON `leave_application` (`uid`, `status`, `from`, `to`, `uid`)

您可以使用 EXPLAIN SELECT ... 来获取有关访问计划的信息。

8.8.1 使用解释优化查询 http://dev.mysql.com/doc/refman/5.5/en/using-explain.html


早些时候:

我认为这会返回指定的结果集。

SELECT a.id
     , a.date
     , a.grade
     , l.id AS leave
     , IF(l.id IS NULL,a.grade,1) AS fgrade
  FROM student_attendance a
  LEFT
  JOIN leave_application l 
    ON l.uid = a.id
   AND l.from <= a.date
   AND l.to >= a.date
   AND l.status = 1 /* approved */

JOIN 谓词匹配学生 ID,以及休假期间出勤日期的范围检查,以及批准的休假。

如果没有匹配(重叠)的休假行,则为 fgrade 分配来自等级列的值。否则,我们为 fgrade 分配 1。

根据对您的问题留下的评论,可以将作为 IF 函数中第三个参数的文字 1 替换为对来自 leave_application 的状态列的引用。如果学生获得休假但也获得了成绩,则添加成绩和休假状态可能会导致比您想要的值更高的值。1+1=2。

IF(l.id IS NULL,a.grade,l.status) AS fgrade

student_attendance 中的一行可能会匹配 leave_application 表中的多行。我们可以使用 GROUP BY 和聚合来解决这个问题......

SELECT a.id
     , a.date
     , a.grade
     , MAX(l.id) AS leave
     , IF(MAX(l.id) IS NULL,a.grade,1) AS fgrade
  FROM student_attendance a
  LEFT
  JOIN leave_application l 
    ON l.uid = a.id
   AND l.from <= a.date
   AND l.to >= a.date
   AND l.status = 1 /* approved */
 GROUP BY a.id, a.date, a.grade

如果status实际上是一个包含 的字符串'Approved',则可以调整查询。离开列的值可能不是 id。从示例数据中无法判断,因为 leave 的值与 id 和状态“已批准”的值 1 匹配。因此,该值实际上可能来自

 l.status AS leave
 NULLIF(l.id IS NOT NULL,0) AS leave
 IF(l.id IS NOT NULL,1,NULL) AS leave
 (l.id/l.id) AS leave

这些表达式中的任何一个都将给出示例数据中显示的结果。


同样,根据对您问题的评论中提供的其他信息...

SELECT a.id
     , a.date
     , a.grade
     , NULLIF(MAX(l.id) IS NOT NULL,0) AS leave
     , IF(MAX(l.id) IS NULL,a.grade,1) AS fgrade
  FROM student_attendance a
  LEFT
  JOIN leave_application l 
    ON l.uid = a.id
   AND l.from <= a.date
   AND l.to >= a.date
   AND l.status = 'Approved'
 GROUP BY a.id, a.date, a.grade
于 2013-07-13T05:01:57.677 回答
3

尝试

SELECT a.id, a.date, a.grade,
       CASE WHEN l.status = 'approved' THEN 1 END `leave`,
       CASE WHEN l.status = 'approved' THEN 1 ELSE a.grade END fgrade
  FROM attendance a LEFT JOIN `leave` l
    ON a.id = l.uid 
   AND a.date BETWEEN l.from AND l.to

输出:

| 身份证 | 日期 | 等级 | 离开 | FGRADE |
----------------------------------------------
| 239 | 2012-09-01 | 1 | (空) | 1 |
| 239 | 2012-09-02 | 0 | (空) | 0 |
| 239 | 2012-09-04 | 0 | 1 | 1 |
| 239 | 2012-09-05 | 1 | 1 | 1 |
| 239 | 2012-09-07 | 0 | 1 | 1 |
| 239 | 2012-09-25 | 0 | (空) | 0 |
| 239 | 2012-09-26 | 0 | (空) | 0 |

这是SQLFiddle演示

于 2013-07-13T05:12:05.703 回答