Рекурсивный запрос - обновление имени структуры рекурсивной папки с помощью T-SQL - PullRequest
1 голос
/ 14 октября 2019

У меня есть таблица, в которой хранятся файлы для общей файловой программы. В таблице «Файловая система» хранятся файлы и структура папок. Таблица 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

I 'Я пытался использовать 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 голосов
/ 14 октября 2019

Ошибка супер-новичка, но я не осознавал, что на моем ParentId не было индекса. Я оставляю вопрос на тот случай, если CTE кому-нибудь пригодится.

0 голосов
/ 14 октября 2019

Пожалуйста, попробуйте следующий код и дайте мне знать, если вам нужны какие-либо другие изменения.

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

Спасибо

0 голосов
/ 14 октября 2019

Если вы не повторяете пути в иерархии, вам не нужен рекурсивный запрос, потому что 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\%';
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...