我正在寻找建立一个允许使用分层过滤查询数据的工具。我有一些想法,我将如何去做,但想知道是否有任何建议或建议可能更有效。
例如,假设用户正在搜索作业。工作领域如下。
1: Scotland
2: --- West Central
3: ------ Glasgow
4: ------ Etc
5: --- North East
6: ------ Ayrshire
7: ------ Etc
用户可以搜索特定的(即格拉斯哥)或更大的区域(即苏格兰)。
我正在考虑的两种方法是:
SELECT * FROM Jobs WHERE Category IN Areas.childrenField
查询该记录。我从两者看到的问题是:
关于最佳方法的任何想法,建议或建议?我正在使用C#ASP.NET和MSSQL 2005 DB。
答案 0 :(得分:3)
这是我见过的一种方法:
创建名为hierarchyid的varchar(max)字段。 为所有根对象生成基本ID。 对于每个子对象,生成一个id,并在父ID之前加上它。
示例表
ID(PK) HierarchyID Area
1 sl Scotland
2 slwc West Central
3 slwcgg Glasgow
示例查询
SELECT * FROM Areas Where HierarchyID LIKE 'sl%'
答案 1 :(得分:2)
您应该使用嵌套集。这是MySQL中的一个实现。 http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
答案 2 :(得分:2)
您可以使用Common Table Expressions进行递归查询。我发现这种技术非常强大,易于阅读和易于维护。
答案 3 :(得分:1)
这个怎么样?
表=>
标识 的ParentId 名称
漂亮简单的桌子?
那么一些不错的复杂片段如何与SQL一起去? (我认为CTE摇滚)
public object FetchCategoryTree()
{
var sql = @"SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
WITH AreaTree (ID, Name, ParentID, OrgLevel, SortKey) AS
(
-- Create the anchor query. This establishes the starting
-- point
SELECT
a.ID,
cast('---- ' + a.Name as varchar(255)),
a.ParentID,
cast('----' as varchar(55)),
CAST(a.ID AS VARBINARY(900))
FROM dbo.Area a
WHERE a.ParentID is null
UNION ALL
-- Create the recursive query. This query will be executed
-- until it returns no more rows
SELECT
a.ID,
cast('----' + b.OrgLevel + ' ' + a.Name as varchar(255)),
a.ParentID,
cast(b.OrgLevel+ '----' as varchar(55)),
CAST(b.SortKey + CAST (a.ID AS BINARY(4)) AS VARBINARY(900))
FROM dbo.Area a
INNER JOIN AreaTree b ON a.ParentID = b.ID
)
SELECT * FROM AreaTree
ORDER BY SortKey";
return FetchObject(sql);
}
现在这会做一些不太确定的SQL魔术。然而,在外行人的术语中,它基本上将第一部分作为根查询。然后它返回到表并使用第一部分通过连接的答案执行第二部分,并继续执行仍然无法找到更多匹配,基本上是一个大循环。它也很快。
你会得到一堆附有排序键的行。通过排序键订购查询后,您将得到如下答案:
---- parent 1
-------- child 1
-------- child 2
------------ child 2.1
---- parent 2
-------- etc
你可能正在寻找什么?
答案 4 :(得分:0)
我在我们的应用程序中使用Joe Celko的树模型作为销售税层次结构(州/县/市/ misc)并且运行良好。
您的“在此区域或以下找工作”查询看起来像这样:
SELECT * FROM Jobs WHERE Jobs.AreaID IN
(SELECT P1.AreaID
FROM Areas AS P1, Areas AS P2
WHERE P1.lft BETWEEN P2.lft AND P2.rgt
AND P2.Areas.AreaID = @selectedAreaID)