我有这样的表:
用户
+----+----------+-------------+
| id | name | other_stuff |
+----+----------+-------------+
| 1 | John Doe | x |
| 2 | Jane Doe | y |
| 3 | Burt Olm | z |
+----+----------+-------------+
地方
+----+------------+-------------+
| id | name | other_stuff |
+----+------------+-------------+
| 1 | Building A | x |
| 2 | Building B | y |
+----+------------+-------------+
主题
+----+------------+-------------+
| id | name | other_stuff |
+----+------------+-------------+
| 1 | Math | x |
| 2 | English | y |
+----+------------+-------------+
加入表:
PastLectures =发生的讲座
+----+-----------+----------+------------+---------+------------+
| id | id_users | id_place | id_subjects| length | date |
+----+-----------+----------+------------+---------+------------+
| 1 | 1 | 1 | 1 | 60 | 2015-10-25 |
| 2 | 1 | 1 | 1 | 120 | 2015-11-06 |
| 3 | 2 | 2 | 2 | 120 | 2015-11-04 |
| 4 | 2 | 2 | 1 | 60 | 2015-11-10 |
| 5 | 1 | 2 | 1 | 60 | 2015-11-10 |
| 6 | 2 | 2 | 1 | 40 | 2015-11-15 |
| 7 | 1 | 2 | 2 | 30 | 2015-11-15 |
+----+-----------+----------+------------+---------+------------+
我想在给定的月份显示每个用户的所有课程的总和。 SUM应按每个地点和主题进行分组。
最终PHP输出的结果应如下所示:
November 2015
+------------+-------------+---------------+-------------+
| Users.name | Places.name | Subjects.name | sum(length) |
+------------+-------------+---------------+-------------+
| Burt Olm | - | - | - |
| Jane Doe | Building B | Math | 100 |
| = | = | English | 120 |
| John Doe | Building A | Math | 120 |
| = | Building B | Math | 60 |
| = | = | English | 30 |
+------------+-------------+---------------+-------------+
我尝试使用多个GROUP BY(Group by - multiple conditions - MySQL)在纯SQL查询中创建完整输出,但是当我执行 GROUP BY User.id,Places.id 时,它会显示每个用户只有一次(3个结果),无论其他GROUP BY条件如何。
SQL:
SELECT PastLectures.id_users,Users.name AS user,Places.name AS places,Subjects.name AS subjects
FROM PastLectures
LEFT JOIN Users ON PastLectures.id_users = Users.id
LEFT JOIN Places ON PastLectures.id_Places = Places.id
LEFT JOIN Subjects ON PastLectures.id_Subjects = Subjects.id
WHERE date >= \''.$monthStart->format('Y-m-d H:i:s').'\' AND date <= \''.$monthEnd->format('Y-m-d H:i:s').'\'
GROUP BY Users.id,Places.id
ORDER BY Users.name,Places.name,Subjects.name
但是我不介意解决方案的一部分是用PHP完成的,我只是不知道下一步该做什么。
修改
我还有一个表格时间表,存储谁定期教授什么和哪里。它仅存储表的已使用组合(每个有效组合一次)。
Timetable = lectures that regularly take place
+----+-----------+----------+------------+-------------+
| id | id_users | id_place | id_subjects| other_stuff |
+----+-----------+----------+------------+-------------+
| 1 | 1 | 1 | 1 | x |
| 2 | 1 | 2 | 1 | y |
| 3 | 1 | 2 | 2 | z |
| 4 | 2 | 2 | 1 | a |
| 5 | 2 | 2 | 2 | b |
+----+-----------+----------+------------+-------------+
是否可以仅添加组合在此表中有一行的用户?
在这种情况下,这意味着省略 Burt Olm (时间表中没有id = 3)。但是如果Burt有一个时间表条目但仍然没有PastLectures条目,他会在这里显示样本结果(他应该在那个月进行一次演讲,因为他在时间表中,但没有进行过讲座。)
基于@ Barmar的解决方案,我通过将时间表作为主表并再添加一个LEFT JOIN
来满足这些需求,从而更新了最终的SQL。
最终SQL:
SELECT Users.name AS user,Places.name AS places,Subjects.name AS subjects, SUM(PastLectures.length)
FROM Timetable
LEFT JOIN PastLectures ON PastLectures.id_users = Timetable.id_users AND PastLectures.id_place = Timetable.id_place AND PastLectures.id_subjects = Timetable.id_subjects
AND date BETWEEN '2015-11-01 00:00:00' AND '2015-11-30 23:59:59'
LEFT JOIN Places ON Timetable.id_Place = Places.id
LEFT JOIN Subjects ON Timetable.id_Subjects = Subjects.id
LEFT JOIN Users ON Timetable.id_users = Users.id
GROUP BY Timetable.id,Timetable.id_users,Timetable.id_Place,Timetable.id_Subjects
ORDER BY Users.name,Places.name,Subjects.name
答案 0 :(得分:4)
您需要在Subjects.id
中加入GROUP BY
,以便为每个主题获得单独的结果。
此外,您不应在LEFT JOIN
列中使用GROUP BY
加入的表格中使用列。如果这样做,所有不匹配的行将组合在一起,因为它们在该列中都有NULL
。使用主表中的列。
GROUP BY PastLectures.id_users, PastLectures.id_Place, PastLectures.id_Subjects
请注意,演示输出中的Burt Olm没有行,因为他的所有行都被WHERE
子句过滤掉了。如果您希望展示所有用户,则应将Users
设为主表,而不是PastLectures
。加入date
时,ON
条件需要移入PastLectures
条款。
SELECT Users.name AS user,Places.name AS places,Subjects.name AS subjects, SUM(length)
FROM Users
LEFT JOIN PastLectures ON PastLectures.id_users = Users.id
AND date BETWEEN '2015-11-01 00:00:00' AND '2015-11-30 23:59:59'
LEFT JOIN Places ON PastLectures.id_Place = Places.id
LEFT JOIN Subjects ON PastLectures.id_Subjects = Subjects.id
GROUP BY Users.id, PastLectures.id_Place, PastLectures.id_Subjects
ORDER BY Users.name,Places.name,Subjects.name
答案 1 :(得分:0)
根据标准SQL,除了聚合字段(如sum)之外,您应该选择GROUP BY您选择的所有字段。虽然MySql允许这样做,但是当它可以遵守标准时,最好这样做(谁知道何时需要将代码移植到另一个数据库引擎)。所以写这样的SQL:
SELECT PastLectures.id_users,
Users.name AS user,
Places.name AS places,
Subjects.name AS subjects,
Sum(length)
FROM PastLectures
LEFT JOIN Users ON PastLectures.id_users = Users.id
LEFT JOIN Places ON PastLectures.id_Places = Places.id
LEFT JOIN Subjects ON PastLectures.id_Subjects = Subjects.id
WHERE date BETWEEN \''.$monthStart->format('Y-m-d H:i:s').'\'
AND \''.$monthEnd->format('Y-m-d H:i:s').'\'
GROUP BY PastLectures.id_users,
Users.name,
Places.name,
Subjects.name
ORDER BY Users.name,
Places.name,
Subjects.name