2/15更新 已解決
將距今時間以10為底取LOG取得不超過100的對數加上100~400的權重值
目前的解法:
換個類似的例子,班上有男有女並且成績落在1~100
依照 及格男性>未及格男性>及格女性>非及格女性排序
及格(60分)的男性以年紀從小到大排序
未及格男性以成績排序
及格女性以身高排序
未及格的女性以學號排序
case
when 及格的男性 then 100 + LOG10(age)
when 未及格的男性 then 200 + LOG10(score)
when 及格的女性 then 300 + LOG10(height)
when 未及格的女性 then 400 + LOG10(id)
end
這是我自己測試賽事排序的SQL,實際欄位已經調整但意思相同,為了方便這裡將以A-E(賽事報名前、報名開使、賽事開始、報名結束、賽事結束)當作when的條件,目前order by的部分是先將A-E的條件去做排序,再以距離目前時間做排序,最後再依據各別的欄位做排序
希望能夠改成先以A-E排序的時候再依據時間排序(同時)
我有試過將第一個case when的1、2、3、4調整到1000000~4000000 + 距離目前時間,不過這個方式只是暫時而不算長久之計
有沒有大神可以提供更好的方式
題外話,
now() 函數用這麼多次,肯定效率不彰,
萬一這個Table很大,數百千萬筆,要執行很多秒的話,
答案可能不如您的想像。
應該把now()變成變數之後,再帶進 select 中
select
(@now > xxx ) as `rrr`
from competitopn c,(select @now := now() ) n
NOW()是回傳執行時的TIMESTAMP變數,不會影響效能
https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_now
若要先依據 A-E 排序,再依據時間排序,可以將兩個排序條件都納入到同一個 CASE WHEN 子句中,例如:
SELECT
CASE
WHEN (now() > c.registration_start_at AND now() < c.registration_end_at)
THEN 1
WHEN (now() < c.registration_start_at)
THEN 2
WHEN (now() > c.competition_start_at AND c.is_completed = false)
THEN 3
WHEN (now() > c.registration_end_at)
THEN 4
END AS status_order,
CASE
WHEN (now() > c.registration_start_at AND now() < c.registration_end_at)
THEN ABS(TIMESTAMPDIFF(HOUR, c.registration_end_at, NOW()))
WHEN (now() > c.competition_start_at AND c.is_completed = false)
THEN ABS(TIMESTAMPDIFF(HOUR, c.competition_start_at, NOW()))
WHEN (c.is_completed = true)
THEN ABS(TIMESTAMPDIFF(HOUR, c.completed_at, NOW()))
ELSE ABS(TIMESTAMPDIFF(HOUR, NOW(), c.registration_start_at))
END AS time_order,
c.*
FROM competition c
ORDER BY status_order, time_order;
我能想到的方法,是另外寫個function去算分數,然後直接拿這分數去做排序(then的結果反過來)
例如 :
第一個排序條件會給分數分別加上400~100
第二個條件會加上50~10
第三個條件會加上5~1
然後拿分數做倒序,這樣就可以完成你的需求了