有几个问题... bhds_mileage和之间的部分笛卡尔积(叉积)bhds_timecard,因为一个表中的每个明细行(组内)将与另一表中的明细行“交叉连接”。发生在GROUP BY操作折叠行并计算SUM之前。这就解释了为什么您看到“膨胀的”值。
解决方法是在内联视图中计算至少一个SUM()聚合...像第一个查询中的一个一样完成SUM()/ GROUP BY()。为了清楚起见,您可以对两个原始查询执行相同的操作,然后从内联视图中合并结果。
MySQL本身不支持FULL外部联接。桌子之一将是行驶台。例如,我们可以将其_timecard用作行驶表,但这意味着我们必须从给定的一周返回一行_timecard,以便从_mileage返回相应的行。也就是说,如果没有一行_timecard,我们就无法从中获得一行_mileage。
我们注意到,与的联接bhds_teacher是外部联接。如果我们之间有外键约束ds_id在这两个_mileage和_timecard,引用_teacher,那么这也并不一定需要是外连接,我们可以使用内部联接,并用_teacher作为驱动表有两个外连接。
另一个问题是SELECT列表中的非聚合...例如 DATE_FORMAT((tm_date), '%m/%d/%y')
GROUP BY按年和周计算,因此DATE_FORMAT中的值不确定...可能来自组中的任何值 tm_date。不能保证您会获得一周的第一天,一周之内的最早日期等等。
同样,WEEK函数的第二个参数被省略,因此将默认为default_week_format系统变量。就个人而言,我会避免的YEAR,WEEK和CONCAT功能,并配有简单的去DATE_FORMAT,使用的日期格式字符串,明确包括本周的模式参数。
如果要在“周”加入,则连接谓词应为“周”值,而不是一周中的一个不确定日期。
(对于我们未知的数据,可能会有一些特定的约束。如果给定一周的某个星期的_mileage中有行,那么我们保证在同一周一有_timecard。在更一般的情况下,我们将无法保证。)
即使我们有此保证,也不能保证SELECT列表中的非聚合不会返回星期二_timecard和星期四_mileage的日期(除非有某种保证,即数据将仅包含_timecard和_mileage上具有“星期一”日期的行)。因此,对于联接谓词,非聚合表达式不是可靠的表达式。
假设ds_id是独特的_teacher,是由外键引用ds_id来自_mileage和_timecard,然后是这样的:
SELECT i.last_name
, i.first_name
, tm.dates
, tm.total_hours
, mm.total_minutes
FROM bhds_teacher i
LEFT
JOIN ( SELECT t.ds_id
, DATE_FORMAT( t.tm_date,'%Y/%U') AS week_
, DATE_FORMAT( MIN(t.tm_date) ,'%m/%d/%y') AS dates
, SUM(t.tm_hours) AS total_hours
FROM bhds_timecard t
WHERE t.tm_date BETWEEN '2016-04-11' AND '2016-04-30' -- <
AND t.ds_id = 5 -- <
GROUP
BY t.ds_id
, DATE_FORMAT( t.tm_date,'%Y/%U') -- week
) tm
ON tm.ds_id = i.ds_id
LEFT
JOIN ( SELECT m.ds_id
, DATE_FORMAT( m.mil_date,'%Y/%U') AS week_
, DATE_FORMAT( MIN(m.mil_date), '%m/%d/%y' ) AS dates
, SUM( m.drive_time ) AS total_minutes
FROM bhds_mileage m
WHERE m.mil_date BETWEEN '2016-04-11' AND '2016-04-30' -- <
AND m.ds_id = 5 -- <
GROUP
BY m.ds_id
, DATE_FORMAT( m.mil_date,'%Y/%U') -- week
) mm
ON mm.ds_id = i.ds_id
AND mm.week_ = tm.week_
WHERE i.ds_id = 5 -- <
ORDER
BY i.last_name ASC, tm.dates ASC