我目前正在尝试将FileTable中的目录从一个位置移动到另一个位置。我似乎无法找到有关如何通过T-SQL将包含子目录和文件的目录移动到其他位置的任何信息。
我找到了如何将文件从一个位置移动到另一个位置的示例,只要该目录为空,此方法就可以在目录上运行,但是当它在其中有内容时,它会引发冲突。
我认为这是因为路径定位器需要在正在移动的目录上的任何下划线内容中重新生成,但我不知道如何实现这一点。
非常感谢任何帮助或指导
更新一个
经过对当前版本的SQL Server 2016的大量研究后,如果没有某种形式的递归逻辑,我无法看到这样做的方法。我几乎完全通过在我的开源数据库库中使用C#代码中的递归逻辑来构建解决方案,而不是在T-SQL中完成所有这些。
一旦完成,我将进一步更新该过程及其工作原理。
答案 0 :(得分:1)
今天,我设法在纯T-SQL中做到了这一点,而无需递归。您只需要一个源路径和一个目标路径。路径应为FileTableRootPath() + file_stream.GetFileNamespacePath()
的形式。
该查询应该像IO.Directory.Move命令一样工作,即
也许这对某人有帮助。我尚未进行密集测试。您可能希望在事务中执行此操作,并在发生异常的情况下回滚。删除前四行并将@src和@dest作为查询参数传递。
如果您做一些愚蠢的事情(例如,在移动时拍摄最高水平16或@src不存在),不会出现任何失败。如果@src不存在,则查询将不执行任何操作。如果您违反了FileTables的文件夹深度限制,我想您会在更新过程中遇到错误。
DECLARE @dest varchar(max)
DECLARE @src varchar(max)
SET @src = '\\MachineName\InstanceName\DBName\FileTableName\path\to\src'
SET @dest = '\\MachineName\InstanceName\DBName\FileTableName\path\to\dest'
DECLARE @srcID hierarchyid;
SELECT @srcId = GETPATHLOCATOR(@src)
DECLARE @srcParentId hierarchyid
SELECT @srcParentId = ISNULL(parent_path_locator, 0x) FROM FileTableName WHERE path_locator = @srcId
DECLARE @newName varchar(max);
DECLARE @destParentId hierarchyid;
SET @destParentId = GetPathLocator(@dest);
SET @newName = NULL
IF @destParentId IS NULL
BEGIN
SET @destParentID = GetPathLocator(left(@dest, len(@dest) - charindex('\', reverse(@dest) + '\')));
SET @newName = right(@dest, charindex('\', reverse(@dest) + '\') - 1)
END
IF @destParentId != @srcParentId
UPDATE FileTableName
SET path_locator = STUFF(path_locator.ToString(), 1, len(ISNULL(@srcParentId.ToString(), '/')), @destParentId.ToString())
WHERE path_locator.IsDescendantOf(GetPathLocator(@src)) = 1
IF @newName IS NOT NULL
UPDATE FileTableName
SET name = @newName
WHERE path_locator = STUFF(@srcId.ToString(), 1, len(ISNULL(@srcParentId.ToString(), '/')), @destParentId.ToString())
edit:我已经实现了整个System.IO.File和System.IO.Directory类,以便与T-SQL和FileTable一起使用,而不是直接通过IO。如有需要,请打我。
答案 1 :(得分:0)
虽然这不是T-SQL的答案,但我认为这可能对此有用,因为它是如何做到这一点的理论。
我通过使用C#.Net解决了这个问题,能够创建一个允许我移动目录结构的递归函数。现在,这是我的开源数据库DotNetSDB的FileTable扩展中的内置函数。
如果您想查看源代码,请随时访问该网站并查看SQL Server常规FileTable扩展更新方法。
一般理论
一般摘要
因为此函数是递归的,所以它首先创建所有文件夹结构,然后当它向后工作时,它将所有文件传输到新位置并逐个删除原始目录。在每次递归结束时,我们删除文件夹的原因是,我们可以将流ID恢复到原来的状态,因此除了物理位置之外没有发生任何变化 移动。
答案 2 :(得分:0)
您可以使用此脚本移动包含所有内容的文件夹,但这不是复制粘贴脚本,您需要创建另一个SP以在目标中创建空文件夹(在代码中有注释)。您可以检查这些步骤的工作方式。
限制:
。
DECLARE @id_movethis UNIQUEIDENTIFIER = 'dc59f988-8c75-49e9-8e42-bdee4dd85f7f'
DECLARE @id_moveto UNIQUEIDENTIFIER = '5c80ed42-0742-4f32-a1ed-78a970ba10d0'
DECLARE @searchNode_movethis HIERARCHYID;
SELECT @searchNode_movethis = [path_locator]
FROM [wp].[StorageFiles]
WHERE [stream_id] = @id_movethis
DECLARE @searchNode_moveto HIERARCHYID;
SELECT @searchNode_moveto = [path_locator]
FROM [wp].[StorageFiles]
WHERE [stream_id] = @id_moveto
-- Save the name of the folder to be moved:
DECLARE @movingFolderName NVARCHAR(255)
SELECT @movingFolderName = [name]
FROM [wp].[StorageFiles]
WHERE [path_locator].Getancestor(0) = @searchNode_movethis
-- Check folder exists in target:
DECLARE @isFolderExistsInTarget BIT = 0;
IF EXISTS (SELECT [stream_id]
FROM [wp].[StorageFiles]
WHERE [path_locator].Isdescendantof(@searchNode_moveto) = 1
AND [path_locator].Getlevel() <= 16
AND [name] = @movingFolderName
AND [is_directory] = 1)
SET @isFolderExistsInTarget = 1;
-- Declare variable to save the moved folder path:
DECLARE @movedFolderPath NVARCHAR(max)
IF ( @isFolderExistsInTarget = 1 )
BEGIN
PRINT
'The specified folder already exists in the target folder. Operation aborted!'
END
ELSE
BEGIN
DECLARE @targetPath NVARCHAR(max) = (SELECT [path_locator].Tostring()
FROM [wp].[StorageFiles]
WHERE [stream_id] = @id_moveto);
EXECUTE [wp].[Storage_additemft]
-- use your own sp here to create an empty folder
@movingFolderName,
@targetPath,
NULL,
'FOLDER',
NULL
SELECT @movedFolderPath = [path_locator].Tostring()
FROM [wp].[StorageFiles]
WHERE [path_locator].Isdescendantof(@searchNode_moveto) = 1
AND [path_locator].Getlevel() <= 16
AND [name] = @movingFolderName
AND [is_directory] = 1;
-- Generate new path for files and folders and update:
DECLARE @replaceThisPart NVARCHAR(max)
SELECT @replaceThisPart = [path_locator].Tostring()
FROM [wp].[StorageFiles]
WHERE [path_locator].Getancestor(0) = @searchNode_movethis;
WITH cte
AS (SELECT [stream_id] AS Id
FROM [wp].[StorageFiles]
WHERE [path_locator].Isdescendantof(@searchNode_movethis) = 1
AND [path_locator].Getlevel() <= 16
EXCEPT
SELECT [stream_id] AS Id
FROM [wp].[StorageFiles]
WHERE [path_locator].Getancestor(0) = @searchNode_movethis)
UPDATE [wp].[StorageFiles]
SET [path_locator] = hierarchyid::Parse(
Replace([path_locator].Tostring(),
@replaceThisPart,
@movedFolderPath))
WHERE [stream_id] IN (SELECT [Id]
FROM cte)
END