一种方法是correlated subquery:
SELECT e.id AS element_id,
h.role,
SUM(h.hours_budgeted) AS total_hours_budgeted,
r.hourly_rate,
e.pm_amount,
e.revenue AS fixed_revenue,
e.revenue_extra,
SUM(h.hours_budgeted) * r.hourly_rate AS element_subtotal
FROM job j
JOIN job_element e ON e.job = j.id
JOIN job_element_role_hours h ON h.element = e.id
JOIN rate r ON r.id = (
SELECT id
FROM rate
WHERE rate.role = h.role
AND IFNULL(rate.client_company = j.client_company, TRUE)
AND IFNULL(rate.client_group = j.client_group , TRUE)
AND IFNULL(rate.client_contact = j.client_contact, TRUE)
ORDER BY rate.client_company DESC,
rate.client_group DESC,
rate.client_contact DESC,
rate.date_from DESC
LIMIT 1
)
WHERE j.id = 1
GROUP BY e.id, h.role
在sqlfiddle 上查看。
但是,相关子查询效率低下并且可能很慢。正如手册所说:
将查询重写为连接可能会提高性能。
为此,必须获得groupwise maximum:
SELECT e.id AS element_id,
h.role,
SUM(h.hours_budgeted) AS total_hours_budgeted,
r.hourly_rate,
e.pm_amount,
e.revenue AS fixed_revenue,
e.revenue_extra,
SUM(h.hours_budgeted) * r.hourly_rate AS element_subtotal
FROM job j
JOIN job_element e ON e.job = j.id
JOIN job_element_role_hours h ON h.element = e.id
JOIN rate r ON r.role = h.role
AND IFNULL(r.client_company = j.client_company, TRUE)
AND IFNULL(r.client_group = j.client_group , TRUE)
AND IFNULL(r.client_contact = j.client_contact, TRUE)
JOIN (
SELECT j.client_company, j.client_group, j.client_contact, r.role,
MAX(
IF(r.client_company <=> j.client_company, 1<<34, 0)
| IF(r.client_group <=> j.client_group , 1<<33, 0)
| IF(r.client_contact <=> j.client_contact, 1<<32, 0)
| UNIX_TIMESTAMP(r.date_from)
) AS relevance
FROM rate r JOIN job j ON
IFNULL(r.client_company = j.client_company, TRUE)
AND IFNULL(r.client_group = j.client_group , TRUE)
AND IFNULL(r.client_contact = j.client_contact, TRUE)
GROUP BY j.client_company, j.client_group, j.client_contact, r.role
) t ON t.role = r.role
AND t.client_company = j.client_company
AND t.client_group = j.client_group
AND t.client_contact = j.client_contact
AND t.relevance = IF(r.client_company <=> j.client_company, 1<<34, 0)
| IF(r.client_group <=> j.client_group , 1<<33, 0)
| IF(r.client_contact <=> j.client_contact, 1<<32, 0)
| UNIX_TIMESTAMP(r.date_from)
WHERE j.id = 1
GROUP BY e.id, h.role
在sqlfiddle 上查看。
在这里,我通过计算相关性分数找到了与您的尝试类似的分组最大值。但是,我进行了一些操作,其中 234 表示client_company 上是否有匹配项,client_group 上的 233 和 232 在client_contact 上,32 个最低位表示速率的date_from——然后取最大相关性分数将产生最佳匹配的分数,再次加入rate 表可以得到hourly_rate 根据需要。
人们甚至可以进一步改进这一点,以避免计算相关性分数,方法是嵌套以按顺序在每列上找到分组最大值;但是,除非您遇到无法以任何其他方式解决的性能问题,否则可能不值得走这条路。您可以在my answer to another question 中看到该技术。