2012-02-27 17 views
2

我以前的搜索結果(包含MySQL - row number in recordset?真的幫了我很大忙)並不令人滿意,因爲按其他列排序會覆蓋本機排序@RowNumber總是遞增的mysql行號實現(從1到n排序)

考慮我的簡化member見下表:

row_number | id | firstname | lastname 
-------------------------------------- 
1   | 1 | Steve  | Jobs 
2   | 2 | Bill  | Gates 
3   | 3 | Rasmus | Lerdorf 
4   | 4 | Linus  | Torvalds 

導致由以下查詢:

SELECT id, firstname, lastname, @RowNumber = @RowNumber + 1 AS row_number 
FROM member, (SELECT @RowNumber := 0) AS counter_table 

但是,當我要去基於比ROW_NUMBER或ID,其他的一些列排序row_number的排序會損壞:

SELECT id, firstname, lastname, @RowNumber = @RowNumber + 1 AS row_number 
FROM member, (SELECT @RowNumber := 0) AS counter_table 
ORDER BY firstname DESC 

結果:

row_number | id | firstname | lastname 
-------------------------------------- 
2   | 2 | Bill  | Gates 
4   | 4 | Linus  | Torvalds 
3   | 3 | Rasmus | Lerdorf 
1   | 1 | Steve  | Jobs 

注意:表,查詢和其他任何東西都不是測試示例。只有問題本身在現實世界中!

我認爲這些簡單的情況很容易理解和解決。 (如果他們有任何問題,請忘記這些小錯誤,並考慮自己的重要問題)

+1

當然它會「腐敗」。沒有規則說明記錄集中行號是什麼,因爲結果是動態創建的,但是您有一列表示行的編號。這就是人們通常在應用程序而不是數據庫中執行此功能的原因。 – 2012-02-27 14:22:35

+1

rownumber不是表中的靜態列,因此列上的任何排序都將優先。您可以嘗試創建一個將rownumber作爲其中一列的視圖,然後針對該視圖運行查詢。 – Brian 2012-02-27 14:22:54

+1

這是因爲'ORDER'在SELECT後出現。如果您在名字上添加索引,結果將按順序返回,而不是稍後排序,因此它可以工作。它仍然聞起來。 – 2012-02-27 14:27:12

回答

0

您對ROW_NUMBER實現依賴的結果在從數據庫返回已您在其中顯示的順序。

當您按名字排序時,失敗的原因是因爲結果是按主鍵的順序從數據庫返回的,所以id 1獲得row_number 1,然後它們通過firstname命令(通過filesort) 。

如果你在firstname列上添加一個索引,那麼結果將從數據庫中按firstname而不是主鍵排序,所以行號會很好。

如果你在你的查詢上做了EXPLAIN,你會注意到它可能使用主鍵作爲索引,並使用filesort命令結果,因爲它沒有名字上的索引。在從表格中獲取結果之後發生該訂單。

添加上姓名索引,你會看到,它會使用在姓名索引來從已經姓名訂購的數據庫中的結果,所以第一個名字都會有ROW_NUMBER 1.

發揮它安全的,你可能會想要強制索引。

但是,這對於解釋發生了什麼以及如何解決該問題是嚴格的學術。

最有可能的解決方案是將您的第一個查詢作爲子查詢執行,並在結果已經命令後在外部查詢中添加行號。 某些應用程序會在用戶想要更改排序順序時重新發出查詢,但是,某些應用程序會緩存結果,在應用程序中對其進行排序,並在應用程序中生成行號。

+0

非常感謝您的好解釋。所以我在我的情況下得知,用戶可能想按每個列進行排序,PHP方式看起來更安全(當然更簡單:D)。 – 2012-02-27 14:45:57

2

這應該是顯而易見的:數字行先排序,稍後再排序。

SELECT * FROM (
    SELECT id, firstname, lastname, @RowNumber = @RowNumber + 1 AS row_number 
    FROM member, (SELECT @RowNumber := 0) AS counter_table 
) AS sq 
ORDER BY firstname DESC 

哦,等等......你真的想反過來,第一順序,編號後:

SELECT sq.*, @RowNumber = @RowNumber + 1 AS row_number FROM (
    SELECT id, firstname, lastname 
    FROM member 
    ORDER BY firstname DESC 
) AS sq 
CROSS JOIN (SELECT @RowNumber := 0) AS counter_table 
+0

CodeIgniter的Active Record不是100%可執行的!我認爲我應該去PHP方row_number。不管怎樣,謝謝你。 – 2012-02-27 14:40:30

+0

如果您的原始解決方案在CI中可實現,那麼應該這樣做。它沒有引入任何新的語法。儘管在這裏猜測,但我不知道CI – Mchl 2012-02-27 14:50:57

+1

非常感謝您的解決方案。我知道我沒有提到我是一名CI人。就像我在某些地方閱讀的那樣,不幸的是,子查詢實際上是可以實現的,但有一些技巧。無論如何,你的解決方案對我來說非常專業!我應該感謝你的幫助。 +1 – 2012-02-27 14:54:11