【问题标题】:Best method to search hierarchical data搜索分层数据的最佳方法
【发布时间】:2010-03-15 14:27:25
【问题描述】:

我正在考虑构建一个允许使用分层过滤查询数据的设施。我有一些想法,但我想知道是否有任何建议或建议可能更有效。

例如,假设用户正在搜索工作。工作领域如下。

1: Scotland
2: --- West Central
3: ------ Glasgow
4: ------ Etc
5: --- North East
6: ------ Ayrshire
7: ------ Etc

用户可以搜索特定的(即格拉斯哥)或更大的区域(即苏格兰)。

我正在考虑的两种方法是:

  1. 为每条记录记下数据库中的子项(即 cat 1 在其子项字段中有 2、3、4)并使用 SELECT * FROM Jobs WHERE Category IN Areas.childrenField 查询该记录。
  2. 使用递归函数查找与所选区域相关的所有结果。

我从两者中看到的问题是:

  1. 将这些数据保存在数据库中意味着必须跟踪结构的所有更改。
  2. 递归速度慢且效率低。

关于最佳方法的任何想法、建议或建议?我正在使用 C# ASP.NET 和 MSSQL 2005 DB。

【问题讨论】:

  • 如果您的表结构支持,您可以进行递归查询:msdn.microsoft.com/en-us/library/ms186243.aspx
  • 您是否考虑过在 XML 中建模您的信息并将其存储在一个 XML 属性中(在数据库表上),以便您可以使用 XQuery 对其进行查询?

标签: c# asp.net sql-server-2005 recursive-query


【解决方案1】:

这是我见过的一种方法:

创建一个名为 hierarchyid 的 varchar(max) 字段。 为所有根对象生成基本 ID。 为每个子对象生成一个 id 并在其前面加上 parent(s) id。

示例表

ID(PK) HierarchyID Area
1       sl           Scotland 
2       slwc        West Central
3       slwcgg       Glasgow 

示例查询

SELECT * FROM Areas Where HierarchyID LIKE 'sl%'

【讨论】:

  • 在 SQL Server 2008 中,他们引入了一种数据类型 HierarchyID 来处理这种方法:msdn.microsoft.com/en-us/magazine/cc794278.aspx
  • 这种方法看起来与我的选项 1 想法的实现略有不同。很好很简单,但这意味着每次更新类别时,HeiratchyID 都需要重新评估。
  • @WDuffy 是的,您需要确保您的插入和更新正确计算了 hierarchyID。我没有使用上面示例中的代码,而是使用了 ID。例如而不是“slwcgg”,我会使用“/1/2/3/”。
【解决方案2】:

您应该使用嵌套集。这是 MySQL 中的一个实现。 http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

【讨论】:

  • 这个答案是关于“嵌套集”作为一种处理分层数据的技术。他只是链接到一个很好的解释,恰好在一个 MySQL 站点上。它不涉及任何特定于 MySQL 的内容。
【解决方案3】:

您可以使用Common Table Expressions 进行递归查询。我发现这种技术非常强大,易于阅读且易于维护。

【讨论】:

    【解决方案4】:

    这个怎么样?

    表 =>

    身份证 父 ID 名称

    漂亮的简单表?

    那么用一些漂亮的复杂的 pf 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
    

    可能是您正在寻找的东西?

    【讨论】:

      【解决方案5】:

      我在我们的应用程序中使用 Joe Celko 的销售税层次结构树模型(州/县/市/杂项),它运行良好。

      您的“在该区域或以下区域寻找工作”查询将如下所示:

      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)
      

      Celko Tree in SQL article

      【讨论】:

        猜你喜欢
        • 2010-11-13
        • 1970-01-01
        • 2013-10-09
        • 2012-05-18
        • 1970-01-01
        • 2011-03-09
        • 1970-01-01
        • 1970-01-01
        • 2010-10-08
        相关资源
        最近更新 更多