一种方式将涉及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。
在这里,我通过计算相关性分数找到了与您的尝试类似的徒劳分组最大值。然而,我通过一些位操作,其中,2 指示是否存在上client_company
匹配,2 上client_group
和2 32上client_contact
去,与代表率的date_from
—然后32最低阶位获取最大相关性分数将得出最佳匹配的分数,再次加入rate
表使得人们能够根据需要获得hourly_rate
。
人们甚至可以进一步提高这一点,以避免计算相关性分数,通过嵌套来按顺序查找每列上的分组最大值;然而,除非您遇到无法以其他方式解决的性能问题,否则可能不值得沿着这条路走下去。您可以在my answer to another question中查看该技术。
就我所知,在比较'rates'表和'jobs'表中的三个'client_ *'列时,有四种可能的结果:它们匹配,不匹配,一个一边是“NULL”,另一边是“NULL”。在三栏中,这是64个可能的结果。您试图对这64种可能的结果进行排序,其中'rates.date_from'列以某种方式被用于打破关系。然而,对于我来说,这个顺序应该是什么,有点不清楚:倒数第二段似乎与您的查询不一致。请澄清。 – eggyal
我猜不一致是因为子查询没有做到我想要的:)它应该最好匹配rates表中的* single *记录,但是确切地说哪一个取决于它找到的匹配。 (1)同一公司,集团和客户 (2)同一公司,集团(空客户) (2)同一公司(空集团和客户) 客户(客户) 客户匹配应始终优先于日期。因此,所有三列上匹配的旧记录应优于刚刚匹配的新记录,比如公司。 – Wintermute