2012-05-22 43 views
5

說,我有一些SELECT聲明:查找行號,然後找到其鄰居

SELECT id, name FROM people 
    ORDER BY name ASC; 

我在people表中的幾百萬行和ORDER BY子句可以是多比我在這裏顯示的更復雜(可能在十幾列上操作)。

我只檢索行的一小部分(比如行1..11),以便在UI中顯示它們。現在,我想解決以下問題:

  1. 找到給定id的行數。
  2. 顯示之前的5個項目以及連續給定的id後的5個項目。

一旦我解決了問題1,問題2很容易解決,因爲如果我知道我正在查找的項目在排序結果集中有行號1000(這是火鳥SQL方言):

SELECT id, name FROM people 
    ORDER BY name ASC 
    ROWS 995 TO 1005; 

我也知道,我可以通過計算所有一個我找前哪來行發現一排rank,但是這可能會導致很長的WHERE條款與噸的ORAND在條件。我必須反覆這樣做。使用我的測試數據,這需要幾百毫秒,即使使用正確索引的列,速度太慢。

是否有通過使用某些SQL:2003功能(例如Firebird 3.0支持的row_number)來實現此目的的方法?我不是一個SQL大師,我需要一些指針。我可以創建一個緩存視圖,其結果將包括排名/密集排名/行索引?

+0

太難以回答沒有關於UI類型的信息。網?桌面?命令行?語音UI ;-) – rstrelba

+0

我正在顯示桌面應用程序中的人員列表;由於集合非常龐大,我只能獲取適合列表視口的人員的行。用戶有一個滾動條,允許她移動到列表中的任何一點,並使其刷新其內容,就好像它真的充滿了數百萬行。 –

+0

視口過濾器中有多少附加參數? – rstrelba

回答

3

Firebird似乎支持窗口函數(在Oracle中稱爲分析函數)。所以,你可以做到以下幾點:

要找到一行具有給定ID的「行」數:

select id, row_number() over (partition by NULL order by name, id) 
from t 
where id = <id> 

這是假設的ID是唯一的。

要解決的第二個問題:

select t.* 
from (select id, row_number() over (partition by NULL order by name, id) as rownum 
     from t 
    ) t join 
    (select id, row_number() over (partition by NULL order by name, id) as rownum 
     from t 
     where id = <id> 
    ) tid 
    on t.rownum between tid.rownum - 5 and tid.rownum + 5 

我可能會建議別的東西,不過,如果你可以修改表結構。大多數數據庫提供了在插入行時添加自動增量列的功能。如果你的記錄從不刪除,這可以作爲你的櫃檯服務器,簡化你的查詢。

+0

感謝您的建議。我希望沿着你在第一個解決方案中提出的建議。是的,我的'id'列包含唯一值。 –

+0

我不明白你的意思是通過修改表結構;基本上,'id'已經是一個自動增量列。麻煩的是,行的順序取決於'SELECT'語句中的順序。一個額外的柱子如何幫助我?我錯過了什麼? –

+0

如果您不從表中刪除行,則可以使用「 - 5和 + 5之間的哪個ID」。這將消除row_number()計算。換句話說,解決您的問題只是一種自我加入。 –