一種方式將涉及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