2015-06-17 42 views
1

有沒有辦法選擇行,直到滿足一些條件?即一種類型爲limit,但不限於N行,而是包含到所有行,直到第一個不匹配的行?選擇直到在postgresql中匹配行嗎?

例如,說我有表:

CREATE TABLE t (id SERIAL PRIMARY KEY, rank INTEGER, value INTEGER); 
INSERT INTO t (rank, value) VALUES (1, 1), (2, 1), (2,2),(3,1); 

那就是:

test=# SELECT * FROM t; 
id | rank | value 
----+------+------- 
    1 | 1 |  1 
    2 | 2 |  1 
    3 | 2 |  2 
    4 | 3 |  1 
(4 rows) 

我想排名訂貨,並選擇直到第一行是超過1

iee SELECT * FROM t ORDER BY rank UNTIL value>1

我想把第2排放回去?

一種解決方案是使用子查詢和bool_or

SELECT * FROM 
(SELECT id, rank, value, bool_and(value<2) OVER (order by rank, id) AS ok FROM t ORDER BY rank) t2 
WHERE ok=true 

但不會是最終通過所有的行會,就算我只想要一把? (真實世界上下文中:我在表格中有時間戳事件,我可以使用窗口查詢超前/滯後來選擇兩個事件之間的時間,我希望now的所有事件只要發生少於10次就返回除了分鐘 - 在lead/lag窗口查詢複雜的事情,這裏這麼簡單的例子)

編輯:由rank, id

回答

1

這使得窗口功能順序可能沒有比你更好的解決方案,因爲你求的問題,「贏了」最終會遍歷所有的行?「

我可以告訴你 - 解釋計劃與你的解決方案不同。我不知道PostgreSQL是如何工作的,但是如果我寫一個「max」函數,我會認爲它總是O(n)。相比之下,您有一個平均情況O(n log n),最壞情況O(n^2)的順序。

這麼說,我不能否認,這將通過所有行:

select * from sandbox.t 
where id < (select min (id) from sandbox.t where value > 1) 

有一點要澄清,不過,是,除非你掃描所有行,我不知道你怎麼能確定最小值。無論何時您在所有記錄中調用聚合概念,這是否意味着您必須讀取所有行?

+1

最小值(或最大值)可以從索引中有效地獲得。 –

+0

這是基本例子的一個巧合,即ID和Rank排序在一起(我固定了上面的查詢),但是你可以用'min(rank)'來達到同樣的效果。我的直覺是,這比我的子查詢更快。 如上所述,真實情況比較複雜,實際上計算的是「值」,並且還有一個額外的過濾器只能獲得表格的某些部分。我會嘗試一下,看看是否有這樣的作品! – gromgull

1

你想要的是一種停止條件。據我所知,SQL中沒有這種東西,至少PostgreSQL的方言。

你可以做的是使用PL/PgSQL過程從光標讀取行並返回它們,直到滿足停止條件。它不會超快,但它會沒事的。這只是一個FOR循環查詢與IF expression THEN exit; ELSE return next; END IF;。因爲PL/PgSQL將在內部使用一個遊標,因此如果你在查詢上循環,則不需要顯式遊標。

另一種選擇是在應用程序中創建一個遊標並從中讀取塊,然後在停止條件滿足時丟棄最後一個塊的一部分。

無論哪種方式,遊標將成爲你想要的。


一個停止表達式實際上並不太難在PostgreSQL中實現。你必須實現一個新的執行器節點類型,但新的CustomScan支持將在擴展中做到這一點。然後你只需評估一個表達式來決定是否繼續提取行。

0

你可以嘗試的東西,如:

select * from t, (
    select rank from t where value = 1 order by "rank" limit 1) x 
where t.rank <= x.rank order by rank; 

它將通過表(您可能能夠通過創建(等級指數削減的第一部分做兩遍,值= 1) ),但如果您有排名指數,則不應評估表格的其餘部分。

[如果您可以在where子句中使用窗口表達式,那麼您可以使用窗口表達式來確保之前的行沒有值= 1 ..但即使這是可能的,然後讓查詢計算器使用限制搜索將是另一個挑戰。]