1

我正在研究轮班安排解决方案,需要您的帮助。数据库布局如下所示:数据库布局

我获取一个月的所有时间表的查询如下所示:

SELECT
    ca.date,
    ss.num,
    ma.name
FROM dp_dienstplan  AS dp
JOIN ma_mitarbeiter AS ma ON ma.id=dp.dp_mitarbeiter_id
JOIN ss_schienen    AS ss ON ss.id=dp.dp_schienen_id
JOIN sc_schicht     AS sc ON sc.id=ss.ss_schicht_id
RIGHT JOIN calendar AS ca ON ca.date=dp.dp_datum
WHERE
  month(ca.date)=9 AND year(ca.date)=2013

日历表是一个辅助表,其中包含未来几年的日期,以便在没有待定计划的结果中获得偶数天。

查询的结果如下所示:

date       |num        |name
----------------------------
2013-09-01  NULL        NULL
2013-09-02  2           foo
2013-09-02  3           bar
2013-09-03  2           uncle
2013-09-03  1           mac
2013-09-03  7           super
2013-09-04  NULL        NULL
2013-09-04  2           master
.
.
.
2013-09-30  NULL        NULL

我梦寐以求的结果是这样的:

date       |1num |1name |2num |2name |3num |3name. . .|7name|7num 
-----------------------------------------------------------------
2013-09-01  NULL  NULL   NULL  NULL   NULL  NULL . . . NULL  NULL
2013-09-02  NULL  NULL   2     foo    3     bar  . . . NULL  NULL
2013-09-03  1     mac    2     uncle  NULL  NULL . . . 7     super
2013-09-04  NULL  NULL   2     master NULL  NULL . . . NULL  NULL
.           .     .      .     .      .     .          .     . 
.           .     .      .     .      .     .          .     . 
.           .     .      .     .      .     .          .     . 
2013-09-30  NULL  NULL   NULL  NULL   NULL  NULL . . . NULL  NULL

每天应该有一行,名称和“num”值的顺序。我希望你明白我在说什么,对不起我的英语。

我有另一个帮助表,其中包含从 1 到 200 的值,我试图右加入,但我没有成功。

在此先感谢,抱歉,如果这是一个重复的问题,我没有在谷歌或论坛上找到任何结果,也许是因为我不知道要搜索什么。

干杯,拉尔夫。

4

1 回答 1

0

首先,不要将函数应用于用于在WHERE子句中过滤数据的列。它可以防止 MySQL 使用您在该列上可能拥有的任何索引,从而有效地导致对表进行全扫描。话虽这么说,而不是

WHERE month(ca.date)=9 AND year(ca.date)=2013

你最好做类似的事情

WHERE ca.date BETWEEN '2013-09-01' AND LAST_DAY('2013-09-01')

并确保您在calendar.date和上有索引dp_dienstplan.dp_datum


现在ss.num,如果预先知道的所有值,您可以通过在静态查询中使用条件聚合来获取您的数据透视表

SELECT ca.date,
       MAX(CASE WHEN ss.num = 1 THEN ss.num  END) `1num`,
       MAX(CASE WHEN ss.num = 1 THEN ss.name END) `1name`,
       MAX(CASE WHEN ss.num = 2 THEN ss.num  END) `2num`,
       MAX(CASE WHEN ss.num = 2 THEN ss.name END) `2name`,
       MAX(CASE WHEN ss.num = 3 THEN ss.num  END) `3num`,
       MAX(CASE WHEN ss.num = 3 THEN ss.name END) `3name`,
       MAX(CASE WHEN ss.num = 4 THEN ss.num  END) `4num`,
       MAX(CASE WHEN ss.num = 4 THEN ss.name END) `4name`,
       MAX(CASE WHEN ss.num = 5 THEN ss.num  END) `5num`,
       MAX(CASE WHEN ss.num = 5 THEN ss.name END) `5name`,
       MAX(CASE WHEN ss.num = 6 THEN ss.num  END) `6num`,
       MAX(CASE WHEN ss.num = 6 THEN ss.name END) `6name`,
       MAX(CASE WHEN ss.num = 7 THEN ss.num  END) `7num`,
       MAX(CASE WHEN ss.num = 7 THEN ss.name END) `7name`
  FROM dp_dienstplan  AS dp
   JOIN ma_mitarbeiter AS ma ON ma.id=dp.dp_mitarbeiter_id
   JOIN ss_schienen    AS ss ON ss.id=dp.dp_schienen_id
   JOIN sc_schicht     AS sc ON sc.id=ss.ss_schicht_id
   RIGHT JOIN calendar AS ca ON ca.date=dp.dp_datum
WHERE ca.date BETWEEN '2013-09-01' AND LAST_DAY('2013-09-01')
GROUP BY ca.date

输出:

| 日期 | 1NUM | 1姓名| 2NUM | 2名称 | 3NUM | 3姓名 | 4NUM | 4姓名 | 5NUM | 5姓名 | 6NUM | 6名 | 7NUM | 7名 |
|------------|--------|--------|--------|--------| --------|--------|--------|--------|--------|----- ---|--------|--------|--------|--------|
| 2013-09-01 | (空) | (空) | (空) | (空) | (空) | (空) | (空) | (空) | (空) | (空) | (空) | (空) | (空) | (空) |
| 2013-09-02 | (空) | (空) | 2 | 富 | 3 | 酒吧 | (空) | (空) | (空) | (空) | (空) | (空) | (空) | (空) |
| 2013-09-03 | 1 | 麦克 | 2 | 叔叔 | (空) | (空) | (空) | (空) | (空) | (空) | (空) | (空) | 7 | 超级 |
| 2013-09-04 | (空) | (空) | 2 | 大师 | (空) | (空) | (空) | (空) | (空) | (空) | (空) | (空) | (空) | (空) |
| 2013-09-30 | (空) | (空) | (空) | (空) | (空) | (空) | (空) | (空) | (空) | (空) | (空) | (空) | (空) | (空) |

这是SQLFiddle演示在此演示中,您的所有联接表都由一个表模拟,该表包含您作为查询结果显示的示例数据

于 2013-10-01T05:47:43.233 回答