-4

我有这三个表:

学生表:

id | name
1  | Charles
2  | Peter
3  | Mary
4  | John
5  | Mike
...

周表:

id | week | year
1  | 1    | 2012
2  | 3    | 2012
3  | 6    | 2012
4  | 8    | 2012
5  | 9    | 2012
6  | 12   | 2012
...

考勤表:

id | student | week | control
1  | 1       | 1    | P (present)
1  | 2       | 1    | A (absent)
1  | 1       | 3    | P
1  | 2       | 3    | A
1  | 3       | 9    | P

我需要的是这样的 Pivot 视图,但我不知道如何在 MySQL 中获得这样的结构:

id | student | week-1 | week-3 | week-9
1  | Charles | P      | P      | A
2  | Peter   | A      | A      | P
3  | Mary    | P      | A      | P
4

1 回答 1

3

MySQL 没有数据透视函数,但您可以使用带有CASE表达式的聚合函数来复制它。您的代码将类似于以下内容:

select s.id,
  s.name,
  max(case when week=1 then control else 'A' end) Week1,
  max(case when week=3 then control else 'A' end) Week3,
  max(case when week=9 then control else 'A' end) Week9
from students s
inner join attendance a
  on s.id = a.student
group by s.id, s.name

请参阅带有演示的 SQL Fiddle

如果week要返回的值数量未知,则需要在准备好的语句中使用动态 SQL。代码将是:

SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'max(CASE WHEN week = ',
      week,
      ' THEN control else ''A'' END) AS week',
      week
    )
  ) INTO @sql
FROM weeks;

SET @sql 
  = CONCAT('SELECT s.id,
              s.name, ', @sql, ' 
            from students s
            inner join attendance a
              on s.id = a.student
            group by s.id, s.name');

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

请参阅带有演示的 SQL Fiddle

结果将是:

| ID |    NAME | WEEK1 | WEEK3 | WEEK6 | WEEK8 | WEEK9 | WEEK12 |
-----------------------------------------------------------------
|  1 | Charles |     P |     P |     A |     A |     A |      A |
|  2 |   Peter |     A |     A |     A |     A |     A |      A |
|  3 |    Mary |     A |     A |     A |     A |     P |      A |

注意:如果要返回表中的所有Students内容,而不管它们在表中是否有匹配的行attendance,那么您应该使用LEFT JOIN

select s.id,
  s.name,
  max(case when week=1 then control else 'A' end) Week1,
  max(case when week=3 then control else 'A' end) Week3,
  max(case when week=9 then control else 'A' end) Week9
from students s
left join attendance a
  on s.id = a.student
group by s.id, s.name

请参阅SQL Fiddle with Demo

于 2013-03-26T14:00:05.493 回答