使用用户定义的函数动态更新临时 tables 和数据库 table 条目

Using user-defined functions to dynamically update temp tables and database table entries

我需要做的是更改 SQL 中的一个 ActivePath 条目,该条目的值和长度都会更改为不同值和长度的不同路径,然后 运行 一遍又一遍,直到有没有更多与要更改的 ActivePath 匹配的条目。

这是我目前所拥有的,它适用于我已经知道当前文件路径、新文件路径和文件名的单个文件:

UPDATE [AuroraFileServer].[dbo].[File]
SET ActivePath = REPLACE(ActivePath, 'C:\ProgramData\MyData\FileServer\Data', 'C:\Videos\Archive 1')
WHERE ActivePath IN (SELECT ActivePath FROM [AuroraCore].[dbo].[DeviceEventFile] AS DEF
    JOIN [AuroraCore].[dbo].[DeviceEvent] AS DE
    ON DE.Id = DEF.DeviceEventId 
    JOIN [AuroraFileServer].[dbo].[File] AS F
    ON DEF.FilePath = F.ActivePath
    WHERE DE.Name LIKE 'ACBD13420160111185621001%')

所以概念证明有效,但我需要它更加动态,因为 运行针对数百或可能数千个视频进行此验证是不切实际的。

旧的 ActivePath 位置根据视频上传到系统的日期在 yyyy/mm/dd 基础上发生变化,其中月份和日期可以是一位或两位数字值,具体取决于月份或日期 (1/ 1 对 12/12,分别为 1 月 1 日和 12 月 12 日)。新的 ActivePath 需要在不同的位置,但旧的 ActivePath yyyy/mm/dd + 1 天作为文件存档从主要位置到存档后只需 24 小时。

所以流程需要这样:

C:\ProgramData\MyData\FileServer\Data16\ACBD13420160111185621001i100.avi

并将其更改为:

C:\Videos\Archive 116\ACBD13420160111185621001i100.avi

对于数据库中成百上千的条目,当然,几乎所有文件实际名称之前的内容都发生了变化。

有没有办法让它工作,比如创建一个 table 或索引,在其中可以将所有 ActivePath 条目转储到匹配 C:\ProgramData... 路径并进行查询运行 使用替换语句针对该文件,该语句使用索引中的一行作为要替换的部分,替换它,然后一遍又一遍地重复列表直到所有条目都被替换?我见过其他遵循这个想法的替换语句,但所有旧变量和新变量都是已知的,这不是我的情况。

我认为我可以 运行:

SELECT ActivePath
FROM AuroraFileServer.dbo.[File]
WHERE ActivePath LIKE 'C:\ProgramData\MyData\FileServer%'

并且 return 结果到 table 或索引所有内容,在我的例子中(这将在我的测试环境之外改变),在第 8 个 '\' 之后是 t运行关闭并删除列表中的重复项,其中每一行都是 REPLACE 语句的第一个 ' ' 中的单独条目。 REPLACE 语句的第二部分需要复制原始路径的日期部分 + 1 天(因此 31 +1 需要更改月份 +1 以与日期的工作方式保持一致)。这获取了我们需要的信息 运行 REPLACE 语句,该语句将循环回到开头并重复,直到 table 或索引中的所有行都已完成,然后停止。我只是不知道如何做到这一点或从哪里开始。

编辑:

因此,通过使用 bdn02 中的功能,我已经更接近我需要的东西了。这是我目前所拥有的:

(
@olddir varchar(300)
)
RETURNS  varchar(300) AS
BEGIN 
declare @tmpvar varchar(200)
declare @index int
declare @year varchar(4)
declare @month varchar(2)
declare @day varchar(2)
declare @filename varchar(200)
declare @videodate datetime
declare @newpath varchar(300)
set @tmpvar = replace(@olddir, 'C:\ProgramData\MyData\FileServer\Data\', '')
set @index = charindex('\', @tmpvar)
set @year = substring(@tmpvar, 1, @index-1)
set @tmpvar = substring(@tmpvar, @index+1, len(@tmpvar)-@index)
set @index = charindex('\', @tmpvar)
set @month = substring(@tmpvar, 1, @index-1)
set @tmpvar = substring(@tmpvar, @index+1, len(@tmpvar)-@index)
set @index = charindex('\', @tmpvar)
set @day = substring(@tmpvar, 1, @index-1)
set @filename = substring(@tmpvar, @index+1, len(@tmpvar)-@index)
set @videodate = CONVERT (datetime, @day + '.' + @month + '.' + @year, 104)
set @videodate = DATEADD (day , 1 , @videodate)
--build new path
set @newpath = 'C:\Videos\Archive 1\' + cast(year(@videodate) as varchar) + '\' + cast(month(@videodate) as varchar) + '\' + cast(day(@videodate) as varchar) + '\'
return @newpath
END

return与以下项一起使用时的新路径:

SELECT DISTINCT dbo.ConvertDir(ActivePath)
FROM AuroraFileServer.dbo.[File] 
WHERE ActivePath LIKE 'C:\ProgramData\MyData\FileServer%' 

很好,现在:

(
@olddir varchar(300)
)
RETURNS  varchar(300) AS
BEGIN 
declare @tmpvar varchar(200)
declare @index int
declare @year varchar(4)
declare @month varchar(2)
declare @day varchar(2)
declare @filename varchar(200)
declare @videodate datetime
declare @oldpath varchar(300)
set @tmpvar = replace(@olddir, 'C:\ProgramData\MyData\FileServer\Data\', '')
set @index = charindex('\', @tmpvar)
set @year = substring(@tmpvar, 1, @index-1)
set @tmpvar = substring(@tmpvar, @index+1, len(@tmpvar)-@index)
set @index = charindex('\', @tmpvar)
set @month = substring(@tmpvar, 1, @index-1)
set @tmpvar = substring(@tmpvar, @index+1, len(@tmpvar)-@index)
set @index = charindex('\', @tmpvar)
set @day = substring(@tmpvar, 1, @index-1)
set @filename = substring(@tmpvar, @index+1, len(@tmpvar)-@index)
set @videodate = CONVERT (datetime, @day + '.' + @month + '.' + @year, 104)
--build new path
set @oldpath = 'C:\ProgramData\MyData\FileServer\Data\' + cast(year(@videodate) as varchar) + '\' + cast(month(@videodate) as varchar) + '\' + cast(day(@videodate) as varchar) + '\'
return @oldpath
END

Returns 与以下项一起使用时的旧路径:

SELECT DISTINCT dbo.ConvertDir1(ActivePath)
FROM AuroraFileServer.dbo.[File] 
WHERE ActivePath LIKE 'C:\ProgramData\MyData\FileServer%'

完美,现在我的旧路径和新路径都没有重复。

现在我正在尝试利用一个新函数将两个 udf 放在一个带有 WHERE 循环的替换语句中。问题是我得到 "Cannot find either column "dbo" 或用户定义的函数或聚合 "dbo.ConvertDir",或者名称不明确。"在我的 dbo.ConvertDir 和 dbo.ConvertDir1 的新函数中。我的默认模式是 dbo。这是函数:

DECLARE @oldpath TABLE (old varchar(255))
DECLARE @newpath TABLE (new varchar(255))

INSERT INTO @oldpath (OLD)
SELECT DISTINCT dbo.ConvertDir1(oldpath);

INSERT INTO @newpath (NEW)
SELECT DISTINCT dbo.ConvertDir(newpath);

WHILE (1=1)

BEGIN
    UPDATE f
    SET    f.ActivePath = REPLACE(f.ActivePath, o.old, n.new)
    FROM   AuroraFileServer.dbo.[File] AS f,
           @oldpath AS o,
           @newpath AS n
    WHERE f.ActivePath LIKE 'C:\ProgramData\MyData\FileServer%'

    IF @@ROWCOUNT = 0
      BREAK
END

SELECT * FROM AuroraFileServer.dbo.[File]

我做错了什么?

我写了一个函数,好像可以用。可能不完美....

CREATE FUNCTION ConvertDir ( @olddir varchar(300) ) RETURNS varchar(300) AS BEGIN declare @tmpvar varchar(200) declare @index int declare @year varchar(4) declare @month varchar(2) declare @day varchar(2) declare @filename varchar(200) declare @videodate datetime declare @newpath varchar(300) set @tmpvar = replace(@olddir, 'C:\ProgramData\MyData\FileServer\Data\', '') set @index = charindex('\', @tmpvar) set @year = substring(@tmpvar, 1, @index-1) set @tmpvar = substring(@tmpvar, @index+1, len(@tmpvar)-@index) set @index = charindex('\', @tmpvar) set @month = substring(@tmpvar, 1, @index-1) set @tmpvar = substring(@tmpvar, @index+1, len(@tmpvar)-@index) set @index = charindex('\', @tmpvar) set @day = substring(@tmpvar, 1, @index-1) set @filename = substring(@tmpvar, @index+1, len(@tmpvar)-@index) set @videodate = CONVERT (datetime, @day + '.' + @month + '.' + @year, 104) set @videodate = DATEADD (day , 1 , @videodate) --build new path set @newpath = 'C:\Videos\Archive 1\' + cast(year(@videodate) as varchar) + '\' + cast(month(@videodate) as varchar) + '\' + cast(day(@videodate) as varchar) + '\' + @filename return @newpath END

称呼它: select dbo.ConvertDir('C:\ProgramData\MyData\FileServer\Data16\ACBD13420160111185621001i100.avi')

您可以在 select 或视图中使用该函数

好的,我想通了!

INSERT INTO @oldpath (OLD)
SELECT DISTINCT dbo.ConvertDir1(oldpath);

上面缺少 FROM 和 WHERE,也没有进行优化,因此 SELECT TOP 1 而不是 SELECT DISTINCT。这就是它所需要的:

INSERT INTO @oldpath (OldPath)
SELECT TOP 1 dbo.ConvertDir1(ActivePath) AS OldPath
FROM AuroraFileServer.dbo.[File]
WHERE ActivePath LIKE 'C:\ProgramData\MyData\FileServer%'

现在,UPDATE f 块很好,但是要循环并更新具有与上述 INSERT INTO 匹配的路径的每个条目,每个临时 tables 都必须更新每次通过。这就是我想出的办法:

UPDATE @oldpath
SET OldPath = (SELECT TOP 1 dbo.ConvertDir1(ActivePath) AS OldPath
FROM AuroraFileServer.dbo.[File]
WHERE ActivePath LIKE 'C:\ProgramData\MyData\FileServer%')

所以它的工作方式,也就是我的设想,是循环将用一行更新临时 tables 以查找 for/replace 的路径,更新dbo.file table,然后循环返回以使用下一条路径更新临时 tables 以查找 for/replace,然后一遍又一遍地重复,直到 UPDATE f 块不再更新任何条目。一旦我开始工作,我就把它移植过来更新一个非常相似的 table。

这是完整的查询:

DECLARE @oldpath TABLE (OldPath varchar(255))
DECLARE @newpath TABLE (NewPath varchar(255))
DECLARE @oldpath2 TABLE (OldPath2 varchar(255))
DECLARE @newpath2 TABLE (NewPath2 varchar(255))

INSERT INTO @oldpath (OldPath)
SELECT TOP 1 dbo.ConvertDir1(ActivePath) AS OldPath
FROM AuroraFileServer.dbo.[File]
WHERE ActivePath LIKE 'C:\ProgramData\MyData\FileServer%'

INSERT INTO @newpath (NewPath)
SELECT TOP 1 dbo.ConvertDir(ActivePath) AS NewPath
FROM AuroraFileServer.dbo.[File]
WHERE ActivePath LIKE 'C:\ProgramData\MyData\FileServer%'

INSERT INTO @oldpath2 (OldPath2)
SELECT TOP 1 dbo.ConvertDir1(FilePath) AS OldPath2
FROM AuroraCore.dbo.DeviceEventFile
WHERE FilePath LIKE 'C:\ProgramData\MyData\FileServer%'

INSERT INTO @newpath2 (NewPath2)
SELECT TOP 1 dbo.ConvertDir(FilePath) AS NewPath2
FROM AuroraCore.dbo.DeviceEventFile
WHERE FilePath LIKE 'C:\ProgramData\MyData\FileServer%'

WHILE (1=1)

BEGIN

UPDATE @oldpath
SET OldPath = (SELECT TOP 1 dbo.ConvertDir1(ActivePath) AS OldPath
FROM AuroraFileServer.dbo.[File]
WHERE ActivePath LIKE 'C:\ProgramData\MyData\FileServer%')

UPDATE @newpath
SET newpath = (SELECT TOP 1 dbo.ConvertDir(ActivePath) AS NewPath
FROM AuroraFileServer.dbo.[File]
WHERE ActivePath LIKE 'C:\ProgramData\MyData\FileServer%')

UPDATE @oldpath2
SET oldpath2 = (SELECT TOP 1 dbo.ConvertDir1(FilePath) AS OldPath2
FROM AuroraCore.dbo.DeviceEventFile
WHERE FilePath LIKE 'C:\ProgramData\MyData\FileServer%')

UPDATE  @newpath2
SET newpath2 = (SELECT TOP 1 dbo.ConvertDir(FilePath) AS NewPath2
FROM AuroraCore.dbo.DeviceEventFile
WHERE FilePath LIKE 'C:\ProgramData\MyData\FileServer%')

UPDATE f
    SET    f.ActivePath = REPLACE(f.ActivePath, o.OldPath, n.NewPath)
    FROM   AuroraFileServer.dbo.[File] AS f,
           @oldpath AS o,
           @newpath AS n
    WHERE f.ActivePath LIKE 'C:\ProgramData\MyData\FileServer%'

UPDATE def
    SET    def.FilePath = REPLACE(def.FilePath, o2.OldPath2, n2.NewPath2)
    FROM   AuroraCore.dbo.DeviceEventFile AS def,
           @oldpath2 AS o2,
           @newpath2 AS n2
    WHERE def.FilePath LIKE 'C:\ProgramData\MyData\FileServer%'

    IF @@ROWCOUNT = 0
      BREAK
        ELSE
          CONTINUE
END

非常感谢@bdn02 帮助我完成了第一个功能!