1

我有五张表来存储设施、员工、已完成的单位、项目和班次。

我需要确定每个设施的项目的生产力(累计完成数和累计小时数),如果设施有时间记录在项目上。设施存储在员工表中。

这是我的表结构,(减少到这个问题的必要字段):

facilities
+------------+
| id         |
+------------+
| label      |
+------------+

employees
+------------+
| id         |
+------------+
| facility   |
+------------+

completes
+------------+
| id         |
+------------+
| project    |
+------------+
| completes  |
+------------+
| employee   |
+------------+

projects
+------------+
| id         |
+------------+
| title      |
+------------+

shifts
+------------+
| id         |
+------------+
| project    |
+------------+
| length     |
+------------+
| employee   |
+------------+

我遇到麻烦的地方是选择设施的生产力,当它与员工一起存储时,而不是与轮班或完成次数一起存储。也许这是一个设计缺陷?班次和完成表也应该有一个设施列吗?当员工已经确定设施时,拥有设施列似乎是多余的。

SELECT p.title, SUM(c.completes), SUM(s.length)
FROM projects as p
LEFT JOIN completes as c ON c.project = p.id
LEFT JOIN shifts as s ON s.project = p.id
GROUP BY p.id, shifts.employee.facility;

那个 GROUP BY 语句当然是无效的。但它展示了我想要完成的事情。我还想在声明中选择设施标签。我该如何处理?

提前感谢您提供的任何见解!

4

1 回答 1

1

这是我认为 CROSS JOIN 是最佳方法的少数情况之一:

SELECT p.title, f.label, SUM(c.completes), SUM(s.length)
FROM facilities as f        
CROSS JOIN projects as p
JOIN employees as e ON f.id = e.facility
LEFT JOIN completes as c ON c.employee = e.id AND c.project = p.id
LEFT JOIN shifts as s ON s.employee = e.id AND s.project = p.id
WHERE c.id IS NOT NULL OR s.id IS NOT NULL
GROUP BY p.id, p.title, f.id, f.label

这本质上并不是一个糟糕的设计,但它确实使您无法在此处使用典型的父子关系,因为您的桌子上实际上有 2 个completes父母shifts

另一种方法是使用没有 LEFT JOIN 的 UNION。这可能会返回更快的结果,具体取决于您facilitiesprojects表中当前的行数:

SELECT p.title, 
       f.label, 
       SUM(CASE aggregated.type WHEN 'completes' THEN units ELSE 0 END),
       SUM(CASE aggregated.type WHEN 'shifts' THEN units ELSE 0 END)
FROM (
    SELECT 'completes' as type, project, employee, completes as units
    FROM completes
    UNION
    SELECT 'shifts', project, employee, length
    FROM shifts ) aggregated
JOIN projects as p ON aggregated.project = p.id
JOIN employees as e ON aggregated.employee = e.id
JOIN facilities as f ON e.facility = f.id
GROUP BY p.id, p.title, f.id, f.label

从这个查询中可以看出,如果completesshifts存储在同一个表中,问题可以很容易地解决。根据您的需要,这可能对您不起作用,但可能需要考虑作为替代模式。

于 2013-04-15T19:55:10.003 回答