【问题标题】:SQL: Recursive PathSQL:递归路径
【发布时间】:2010-04-29 14:10:33
【问题描述】:

是否可以在 SQL 中创建“树解析器”?

我有一张桌子:

ID Name Parent
1  a
2  b    1
3  c    1
4  d    3

现在我想要一个返回的 SQL 查询:

ID   PATH
1    /a
2    /a/b
3    /a/c
4    /a/c/d

这可以通过 SQL 实现吗?它会让我做很多事情变得更容易。任何帮助将不胜感激!

【问题讨论】:

  • 这可能是可能的,但语法会因 SQL 品牌而异,并且可能并非在所有品牌中都可能。你在用什么? MySQL?甲骨文?微软 SQL?一个好的起点是在 google 上查找“递归 SQL”或“递归 SQL 查询”,但请注意解决方案可能特定于特定品牌的 SQL。
  • 我正在使用 DB2。有趣的是没有通用的解决方案。
  • 一般的解决方案是将路径存储在数据库中。谷歌materialized path.
  • 问题是:我正在处理一个现有项目,该项目用于在 SELECT * 之后使用程序逻辑创建这些路径。我只是想:“这太可怕了。这应该由数据库处理。”不幸的是,我无法对数据库进行任何更改。

标签: sql tree


【解决方案1】:

在 sql server 2005 及更高版本中使用 CTE,这是我必须这样做的一个 sn-p:

WITH Paths([Level], [FullPath], [ID]) AS 
(
    SELECT 
        0 AS [Level], 
        Name AS FullPath, 
        ID
    FROM dbo.Entity
    WHERE (ParentEntityID IS NULL)

    UNION ALL

    SELECT 
        p.[Level] + 1 AS [Level], 
        CASE RIGHT(p.[FullPath], 1) 
        WHEN '\' THEN p.[FullPath] + c.[Name] 
        ELSE p.[FullPath] + '\' + c.[Name] 
    END AS FullPath, 
    c.ID
    FROM dbo.Entity AS c 
    INNER JOIN Paths AS p ON p.ID = c.ParentEntityID
)
SELECT [FullPath], [ID]
FROM Paths

【讨论】:

    【解决方案2】:

    根据使用的数据库服务器,可能已经为您提供了此功能。否则,您可以创建一个调用自身的函数来返回此信息,或者实现Materialized Path 解决方案。

    更新:

    对于 DB2,您可以使用 Recursive Common Table Expressions。

    【讨论】:

      【解决方案3】:

      是的,看here。您可以使用“start with”和“connect by prior”语句,我过去曾使用此语句在 Web 应用程序中创建面包屑。

      【讨论】:

      • 这是特定于 Oracle 的。有通用解决方案吗?
      • 问题是“有没有可能”。我的回答是“是的,是的”。看不出有什么问题。
      【解决方案4】:

      在 SQL 数据库中有几种不同的表示树的方法。我想我知道的不多,但我知道 Django Treebeard 使用 3 种不同的方法来做到这一点。如果您查看文档,它对每种方式都有简短的描述:

      adjacency list -- 你已经在做什么了

      materialized path -- 文章:http://www.dba-oracle.com/t_sql_patterns_trees.htm

      nested sets -- 哦,这是维基百科:http://en.wikipedia.org/wiki/Nested_set_model

      【讨论】:

        【解决方案5】:

        假设我们有一个名为 DLFolder 的简单表,其中包含以下列:

        | folderId | name | parentFolderId |
        

        在 Oracle 中,您可以使用 sys_connect_by_path 操作。

        select fo.folderId as folder_id, sys_connect_by_path(fo.name, '/') as relname
        from DLFolder fo
        start with fo.parentFolderId=0
        connect by prior fo.folderId = fo.parentFolderId
        

        将给出以下结果:

        /1020_Training_Material
        /1020_Training_Material/2000_IBBA
        /1020_Training_Material/2000_IBBA/5000_FR
        /1020_Training_Material/2000_IBBA/5050_NL
        

        见http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions164.htm

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-04-22
          • 1970-01-01
          • 2011-10-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-04-04
          • 1970-01-01
          相关资源
          最近更新 更多