递归查询-使用T-SQL更新递归文件夹结构名称

时间:2019-10-13 21:41:23

标签: sql-server tsql

我有一个表,用于存储文件共享程序的文件。表“ FileSystem”存储文件和文件夹结构。 FileSystem表具有一个“ IsFolder”字段,用于指示这是文件还是文件夹。 “ ParentId”代表文件或文件夹的父文件夹。例如:

Id  ParentId    Name        RelativePath    IsFolder
----------------------------------------------------
1   NULL        \           \               1
2   1           Test        \Test           1
3   2           Folder1     \Test\Folder1   1
4   2           myFile.txt  \Test\Folder1   0

如果将“ Test”文件夹的名称更新为“ Test2”,我想更新所有适用文件夹的RelativePath文本。

Id  ParentId    Name        RelativePath    IsFolder
----------------------------------------------------
1   NULL        \           \               1
2   1           Test2       \Test2          1
3   2           Folder1     \Test2\Folder1  1
4   2           myFile.txt  \Test2\Folder1  0

我尝试使用CTE,但是性能确实很慢。我完全有可能使用错误的TSQL!

CREATE TABLE [dbo].[FileSystem]
(
    [FileSystemId] [INT] IDENTITY(1,1) NOT NULL,
    [Name] [VARCHAR](500) NULL,
    [RelativePath] [VARCHAR](1000) NULL,
    [IsFolder] [BIT] NOT NULL,
    [ParentId] [INT] NULL,
    [LastWriteTime] [DATETIME] NULL,
    [FileData] [VARBINARY](MAX) NULL,
    [UploadedBy] [VARCHAR](50) NULL,
    [IsDeleted] [BIT] NOT NULL,
    [DeletedTime] [DATETIME] NULL,
    [DeletedBy] [VARCHAR](50) NULL,
    [DocumentType] [VARCHAR](10) NULL,

    CONSTRAINT [PK_FileSystem] 
        PRIMARY KEY CLUSTERED ([FileSystemId] ASC)
                    WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

ALTER TABLE [dbo].[FileSystem] 
    ADD CONSTRAINT [DF_FileSystem_IsDeleted] DEFAULT ((0)) FOR [IsDeleted]
GO

ALTER TABLE [dbo].[FileSystem] WITH CHECK 
    ADD CONSTRAINT [FK_FileSystem_FileSystem] 
        FOREIGN KEY([ParentId]) REFERENCES [dbo].[FileSystem] ([FileSystemId])
GO

ALTER TABLE [dbo].[FileSystem] CHECK CONSTRAINT [FK_FileSystem_FileSystem]

这是我尝试过的CTE,但运行需要20秒。

WITH CTE AS
(
    SELECT
        t.FileSystemId,
        t.ParentId,
        t.Name as RootPath,
        t.RelativePath,
        t.IsFolder
    FROM
        FileSystem AS t
    WHERE  ParentId is null
    UNION ALL
    SELECT
        t.FileSystemId,
        t.ParentId,
        CAST(REPLACE(CTE.RootPath+'\'+t.Name,'\\','\')AS VARCHAR(500)) AS RootPath,          
        t.RelativePath, 
        t.IsFolder
    FROM
        FileSystem AS t
        JOIN CTE
            ON CTE.FileSystemId=t.parentId
    WHERE
        t.IsFolder=1 AND t.FileSystemId IS NOT NULL
)
SELECT 
    CTE.RootPath,  CTE.RelativePath, CTE.FileSystemId
FROM
    CTE
WHERE
   CTE.ParentId IS NOT NULL

3 个答案:

答案 0 :(得分:0)

超级菜鸟错误,但我没有意识到我的ParentId上没有索引。如果CTE对任何人都有帮助,我将保留问题。

答案 1 :(得分:0)

请尝试以下代码,如果您需要其他更改,请告诉我。

Declare @tbl as table
(id int
,ParentId int
,Name varchar(100)
,RelativePath varchar(100)
,isFolder bit
)

insert into @tbl

Values(1,null,'\','\',1)
,(2,1,'Test','\Test',1)
,(3,2,'Folder1','\Test\Folder1',1)
,(4,2,'Myfile.txt','\Test\Folder1',0)

update @tbl
set Name='Test2' where Name='Test'

update @tbl
set RelativePath=REPLACE(RelativePath,'Test','Test2')
where RelativePath like '%Test%'

select * from @tbl

谢谢

答案 2 :(得分:-1)

如果不重复层次结构中的路径,则不需要递归查询,因为relativepath具有所需的信息:

update filesystem
    set relativepath = (case when relativepath like '%\Test\%'
                             then replace(relativepath, '\Test\', '\Test2\'
                             else concat(left(relativepath, len(relativepath) - len('Test')),
                                         'Test2'
                                        )
                        end)
    where concat('%\', relativepath, '\%') like '%\Test\%';