2012-10-04 67 views
6

使用用戶變量對行號進行編號

我經常在這裏找到答案,建議使用用戶變量對某些事物或其他編號進行編號。也許最清晰的例子是查詢從給定的結果集中選擇第二行。 (這個問題和查詢類似於this answer,但它是this答案,這實際上觸發了這個問題)。使用用戶變量對行號進行保證

SELECT * 
FROM (SELECT *, (@row := @row + 1) AS rownum 
     FROM (SELECT @row := 0) AS init, tablename 
     ORDER BY tablename.ordercol 
    ) sub 
WHERE rownum % 2 = 1 

這種方法似乎通常工作。

原因要小心

在另一方面,MySQ docs狀態:

作爲一般規則,你不應該賦值給一個用戶變量和相同的語句中讀出的值。您可能會得到您期望的結果,但這並不能保證。包含用戶變量的表達式的評估順序未定義,並可能根據給定語句中包含的元素進行更改;另外,這個順序不能保證在MySQL服務器的版本之間是相同的。

核心問題

所以我的問題不是如何利用現有的服務器來實現這樣的排序,但使用用戶變量建議的解決方案,而不是是否保證下的所有(合理的)情況和工作所有未來版本的MySQL。

通過「保證」我的意思是像MySQL文檔或一些標準的MySQL聲明符合的權威來源。缺乏這種權威的答案,其他來源如經常使用的教程或MySQL源代碼的一部分可能會被引用。作者「作品」我的意思是,將按順序執行作業,每行結果一次,並按ORDER BY行所引發的順序執行作業。斷路查詢

例子給你舉個例子事情是多麼容易失敗:

SELECT * 
FROM (SELECT *, (@row := @row + 1) AS rownum 
     FROM (SELECT @row := 0) AS init, tablename 
     HAVING rownum > 0 
     ORDER BY tablename.ordercol 
    ) sub 
WHERE rownum % 2 = 1 

將上的MySQL 5.5.27當前安裝在SQL Fiddle產生空的結果。原因似乎是HAVING條件導致rownum表達式被評估兩次,所以最終結果將只有偶數。我對幕後發生的事情有了一個想法,並且我並沒有聲稱對HAVING的詢問很有意義。我只是想證明在工作的代碼和看起來非常相似但中斷的代碼之間有一條細線。

+0

@hvd,感謝[ROW_NUMBER]功能請求中的[pointer](http://bugs.mysql.com/bug.php?id=35893)。 [Dems](http://stackoverflow.com/users/53341/dems)最近[告訴我](http://stackoverflow.com/a/12727443)關於這個功能。似乎相當強大,並明確啓動。太糟糕了,自2008年以來似乎沒有什麼進展。 – MvG

+0

當我看到'ROW_NUMBER'已在您的早期問題的評論和答案中提及時,我刪除了我的評論:) – hvd

+0

[您是否已閱讀此文章?]( http://www.xaprb.com/blog/2006/12/15/advanced-mysql-user-variable-techniques/)特別是'MySQL不會評估包含用戶變量的表達式,直到它們被髮送到客戶端, 「# –

回答

9

您誤解了陳述。它涉及SELECT列表中使用多個變量時表達式的順序。
如前所述,此單變量語句中的ORDER BY具有保證的順序,直到當前版本的MySQL,並且該文本中沒有任何內容表明它將改變。

但是保證未來?誰知道。


關於破查詢,你又誤解了MySQL的是如何工作的。讓我們分解您的查詢。請注意本手冊中的這一說明

在SELECT語句中,每個選擇表達式僅在 發送到客戶端時才被評估。這意味着,在一個HAVING,GROUP BY,或ORDER BY 子句,指的是在選擇 表達式列表分配一個值不按預期

可變查詢的處理的順序是大致

FROM/JOIN 
WHERE/ON 
GROUP BY/ROLLUP 
HAVING 
UNION 
SELECT 
ORDER BY 
@variable resolution 

你的「破」查詢試圖使用變量在同一水平,這只是作爲爲使用WHERE/HAVING對列別名條款有罪。這就是爲什麼您永遠不會在相同的查詢級別上看到使用該變量的基於MySQL變量的row_numbering解決方案,它總是處於子查詢中。外部查詢可以被認爲是內部查詢的client,在該階段已經呈現變量/佔位符表達式。根據你的論點,你可以直接使用包含@row的WHERE子句直接打破它(是的,它會運行!)。

+0

我並不確信,但即使我仔細審查了陳述,仍然沒有給我們任何明確的保證,我的問題依然存在。當你寫出當前版本確保訂單時,你是否有任何引用來支持它,或僅僅是個人體驗? – MvG

+0

除了個人經驗之外,還要考慮解決方案衆所周知且經常引用的事實。找到我的任何參考或反饋,它始終沒有奏效。這對我來說已經夠好了。 – RichardTheKiwi

+0

根據評論和[後續問題](http://stackoverflow.com/q/12243779)[此答案](http://stackoverflow.com/a/12171808)不適用於該問題的OP )。到目前爲止,我個人認爲這個問題是最可能的原因。 – MvG

相關問題