【问题标题】:SQL Server Recursive Stored ProcedureSQL Server 递归存储过程
【发布时间】:2010-12-09 08:36:16
【问题描述】:

我正在尝试列出虚拟目录及其子目录中的所有文件。这可能是有下属的公司的员工,这不是文件系统。也许递归存储过程可能不是答案。

场景:

  • 目录表:DirId, ParentId
  • 文件表:FileId, DirId

ParentId 是父目录,根目录有parentId = NULL...认为这是不言自明的。

现在的问题...我想要一个目录及其子目录中存在的文件列表。

对于一个目录,我会创建一个存储过程:

SELECT * FROM Files Where DirId = ????

那么我将如何创建一个包含子目录的存储过程?目前我正在使用 C# 代码并遍历每个目录。我更喜欢使用存储过程……除非你证明我错了。

【问题讨论】:

  • 或许可以考虑使用Recursive CTE query
  • 你想通过 SQL Server 访问文件系统???这非常通过应用程序代码更容易和更好地完成。你能解释一下在 SQL 中这样做解决了什么问题吗?
  • 为什么要使用存储过程来完成显然更适合在 C# 之类的代码中执行的任务???
  • 我正在考虑创建一个存储过程供 NTiers 使用,只是认为我使用存储过程更快、更高效。如果普遍的共识是使用代码,那很好。
  • 这不是文件系统!!!更多在特定文件夹中上传的文件的数据库条目。

标签: sql-server stored-procedures recursion


【解决方案1】:

看看使用CTE

类似

DECLARE @Directory Table(
    DirId INT,
    ParentId INT
)
DECLARE @Files Table(
    FileId INT, 
    DirId INT
)

INSERT INTO @Directory SELECT 1, NULL
INSERT INTO @Directory SELECT 2, 1
INSERT INTO @Directory SELECT 3, 1
INSERT INTO @Directory SELECT 4, 2

INSERT INTO @Files SELECT 1, 1
INSERT INTO @Files SELECT 2, 1
INSERT INTO @Files SELECT 3, 2
INSERT INTO @Files SELECT 4, 2
INSERT INTO @Files SELECT 5, 3
INSERT INTO @Files SELECT 6, 3
INSERT INTO @Files SELECT 7, 4
INSERT INTO @Files SELECT 8, 4

;WITH Directories AS (
        SELECT  DirId,
                ParentID
        FROM    @Directory
        WHERE   DirId = 2 
        UNION ALL
        SELECT  d.DirId,
                d.ParentID
        FROM    @Directory d INNER JOIN
                Directories p   ON  d.ParentId = p.DirId
)
SELECT  *
FROM    Directories d INNER JOIN
        @Files f ON d.DirId = f.DirId

【讨论】:

  • 非常感谢。但是@maycil 提到的 DBA 和他们对此的回应呢?
  • 我不同意@maycil。递归很好,只要你没有循环。我同意在数据库中创建自己的目录结构确实是错误的,但这取决于你的目标是什么。
  • @astander - 我们需要记录谁有权访问上传和下载的文件,因此我们跟踪与实际文件结构匹配的所有文件的数据库条目。你质疑这个过程是对的,但这是有充分理由的:)
  • @Rob:递归 CTE 是可行的方法,也是对性能最友好的方法。其他任何手动编码的东西最有可能在性能上更加困难。
  • @marc_s - 我想听到的答案。谢谢。
【解决方案2】:

我认为您要问的不是实际访问文件系统,而是您在数据库中的表中有一个目录结构,在这种情况下,您可以使用递归 CTE,如下所示:

DECLARE @DirId INTEGER
SET @DirId = 1

;WITH CTEFolders AS
(
SELECT FileId, DirId FROM Files WHERE DirId = @DirId
UNION ALL
SELECT fi.FileId, fi.DirId
FROM CTEFolders c
    JOIN Folders fo ON c.DirId = fo.ParentId = c.DirId
    JOIN Files fi ON fo.DirId = fi.DirId
)
SELECT * FROM CTEFolders

这是一个很好的MSDN reference on recursive CTEs

【讨论】:

  • 更正文件系统.. apolgies。我已经重新措辞了主要部分。
【解决方案3】:

实际上递归并不是一个好的解决方案。 Dba 不希望我们使用递归,

您可以使用此脚本获取目录和子目录

Select d.FileName, f.* from Files f
left Join  Files fsub on fsub.DirId = f.DirId 
inner Join Directory d on d.DirId = f.DirId

子目录和目录将与此脚本一起列出

【讨论】:

  • 为什么递归不是一个好的解决方案?您的回答不会给出 OP 的要求
  • 关于 DBA 的好点子。我正在调查 CTE 的问题,
  • @AdaTheDev 7,我认为是因为性能。在行记录中循环会导致 CPU 繁忙。
  • 我很担心这个......老实说,目前正在与 DBA 一起调查这个问题。谢谢
猜你喜欢
  • 1970-01-01
  • 2011-03-09
  • 1970-01-01
  • 2015-08-08
  • 2021-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多