據MySQL文檔從最後一行中減去值:使用變量賦值MySQL中
作爲一般規則,你不應該賦值給一個用戶變量和相同的語句中讀出的值。您可能會得到您期望的結果 ,但這並不能保證。
然而,在這本書性能比較高的MySQL有一對夫婦使用這種戰術反正來提高查詢性能的例子。
下面是反模式,如果有的話,是否有更好的方式來編寫查詢,同時保持良好的性能?
set @last = null;
select tick, [email protected] as delta, @last:=count from measurement;
爲了澄清,我的目標是找到這一行和最後一行之間的區別。我的表格上有一個主鍵,它是一個日期時間列。
更新:
試圖施洛米的建議後,我恢復到我原來的查詢。事實證明,使用具有集合函數的case語句會產生意想不到的行爲。參見例如:
case when (@delta := (max(measurement.count) - @lastCount)) AND 0 then null
when (@lastCount := measurement.count) AND 0 then null
else @delta end
似乎MySQL的評估不通過的結果包含在第一次通過聚合函數的表達式,然後評估在第二(分組)道次的聚合表達式。它似乎評估第二遍期間或之後的案例表達式,並使用該評估中第一遍的預先計算的值。結果是第三行@delta始終是@delta的初始值(因爲直到分組過程才發生分配)。我試圖將一個組函數與@delta合併到一行中,但無法使其按照預期行事。所以我最終回到我的原始查詢時沒有這個問題。
我仍然希望聽到更多關於如何更好地處理這樣的查詢的建議。
更新2:
對不起,我沒有在這個問題上的反應,我沒有機會進一步調查直到現在。
使用Shlomi的解決方案,它看起來像我有一個問題,因爲當我閱讀我的@last變量時,我正在使用按功能分組,但不是當我設置它時。我的代碼看起來是這樣的:
CASE
WHEN (@delta := count - @last) IS NULL THEN NULL
WHEN (@last:= count) IS NULL THEN NULL
ELSE (CASE WHEN cumulative THEN @delta ELSE avg(count) END)
END AS delta
的MySQL似乎處理不包含在第一遍和那些在第二遍做聚合函數表達式。上面代碼中的奇怪之處在於,即使cumulative
的計算結果爲true,MySQL必須在ELSE
子句中看到AVG
聚合函數,並決定在第二遍中評估整個內部CASE
表達式。由於@delta
被設置爲一個沒有聚合函數的表達式,因此它似乎在第一次傳遞時被設置,並且在第二次傳遞發生時MySQL正在對設置了@delta
和@last
的行進行求值。
最終,我似乎通過在第一個表達式中包含聚合函數找到了一個修復程序。事情是這樣的:
CASE
WHEN (@delta := max(count) - @last) IS NULL THEN NULL
WHEN (@last:= max(count)) IS NULL THEN NULL
ELSE (CASE WHEN cumulative THEN @delta ELSE avg(count) END)
END AS delta
我的純粹是基於測試和猜想,因爲我沒看過的源代碼,但希望這將幫助其他人誰可能會遇到類似的問題是什麼MySQL是幹什麼的理解。
我會接受Shlomi的回答,因爲它確實是一個很好的解決方案。只要小心你如何使用聚合函數。
這是一個很好的答案。感謝您的建議。 我已經提前實施了一個類似於你的解決方案,但爲了保持我的初始值爲空,我使用瞭如下子句: 'WHEN(@delta:= count- @ last)AND 0 THEN NULL' – 2012-07-23 23:32:26
'AND 0' - 太簡單了!大! – 2012-07-24 04:42:46
嘗試您的解決方案後,我無法使其與聚合函數一起工作。你提到這個解決方案適用於複雜的子句,比如'GROUP BY',但是我沒有任何運氣。我在上面添加了更多細節。我正在使用MySQL 5.5.20。 – 2012-08-03 17:56:22