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

时间:2016-01-14 20:43:24

标签: sql sql-server replace user-defined-functions udf

我需要做的是更改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\Data\2016\1\13\ACBD13420160111185621001i100.avi

并将其更改为:

C:\Videos\Archive 1\2016\1\14\ACBD13420160111185621001i100.avi

对于db中的数百或数千个条目,当然,几乎所有文件实际名称之前的内容都会发生变化。

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

我认为我可以跑:

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

并且将结果返回到包含所有内容的表或索引,在我的情况下(将在我的测试环境之外更改),在第8个'之后。被截断并删除重复的列表,其中每一行将是第一个单独的条目进入第一个' ' REPLACE声明。 REPLACE语句的第二部分需要复制原始路径的日期部分+ 1天(因此31 + 1需要更改月份+1以保持日期的工作方式)。这将获得运行REPLACE语句所需的信息,该语句将循环回到开头并重复,直到该表或索引中的所有行都已完成然后停止。我根本不知道如何实现这一目标或从何处开始。

编辑:

因此,不再使用 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

与...一起使用时返回新路径:

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

与以下项一起使用时返回旧路径:

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

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

现在我正在尝试利用一个新函数将两个udf组合在一个带有WHERE循环的replace语句中。问题是我得到了#34;找不到任何一列" 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]

我做错了什么?

2 个答案:

答案 0 :(得分:0)

我写了一个函数,似乎有效。也许不完美......

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\Data\2016\1\13\ACBD13420160111185621001i100.avi')

您可以在选择或视图中使用该功能

答案 1 :(得分:0)

好的,我明白了!

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匹配的路径的每个条目,每个传递都必须更新每个临时表。这就是我想出来的目标:

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

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

以下是完整查询:

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为我帮忙解决第一个功能!