假設有兩列的表:From和To。示例:使用SQL查找所有可到達的節點
From To
1 2
2 3
2 4
4 5
我想知道找到所有節點的最有效方法,這些節點可以使用SQL查詢從節點訪問。示例:給定1將返回2,3,4和5.可以使用由UNION子句統一的多個查詢,但它會限制可以達到的級別數。也許一個不同的數據結構會使問題更易處理,但這是可用的。
我正在使用Firebird,但我想要一個只使用標準SQL的解決方案。
假設有兩列的表:From和To。示例:使用SQL查找所有可到達的節點
From To
1 2
2 3
2 4
4 5
我想知道找到所有節點的最有效方法,這些節點可以使用SQL查詢從節點訪問。示例:給定1將返回2,3,4和5.可以使用由UNION子句統一的多個查詢,但它會限制可以達到的級別數。也許一個不同的數據結構會使問題更易處理,但這是可用的。
我正在使用Firebird,但我想要一個只使用標準SQL的解決方案。
如果您使用大多數品牌的數據庫(除了MySQL和SQLite以及其他一些晦澀的數據庫(對不起,我認爲Firebird不明確)),則可以使用recursive common table expression。此語法是ANSI SQL標準,但Firebird
尚不支持它。
糾錯: Firebird 2.1確實支持遞歸CTE,正如@Hugues Van Landeghem所評論的那樣。
否則請參閱我的介紹Models for Hierarchical Data with SQL幾種不同的方法。
例如,您可以爲樹中的每個路徑存儲其他行,而不僅僅是直接的父路徑/子路徑。我將此設計稱爲關閉表。
From To Length
1 1 0
1 2 1
1 3 2
1 4 2
1 5 3
2 2 0
2 3 1
2 4 1
3 3 0
4 4 0
4 5 1
5 5 0
現在您可以查詢SELECT * FROM MyTable WHERE From = 1
並獲取該節點的所有後代。 PS:我會避免命名一列From
,因爲這是一個SQL保留字。
不幸的是,沒有一個好的通用解決方案可以適用於所有數據庫的所有情況。
我建議你看一下這些資源用於MySQL的解決方案:
對於PostgreSQL和SQL Server,您應該看看recursive CTEs。
如果您使用的是Oracle,您應該查看CONNECT BY,這是SQL的專有擴展,可以更輕鬆地處理樹結構。
+1順便說一句,Oracle 11g(大約2007年)支持遞歸CTE,所以沒有理由使用CONNECT BY。 – 2010-09-20 19:58:44
與Bill相同http://www.firebirdsql.org/rlsnotesh/rlsnotes210.html#rnfb210-cte – 2010-09-20 20:38:52
對於標準的SQL來說,存儲具有可接受的讀取性能的樹的唯一方法是使用諸如路徑枚舉之類的破解。請注意,這在寫入時非常重要。
ID PATH
1 1
2 1;2
3 1;2;3
4 1;2;4
SELECT * FROM tree WHERE path LIKE '%2;%'
Firebird支持直到第2版的遞歸公用表表達式。1:是時候起牀了;)http://www.firebirdsql.org/rlsnotesh/rlsnotes210.html#rnfb210-cte – 2010-09-20 20:36:55
感謝您更正@Hugues。我已經編輯了上面的答案。 – 2010-09-20 21:42:13
+1對於CTE來說,它們確實使樹木處理變得相當容易 – 2010-09-20 21:48:18