在文本字段中查找服务器名称,将它们存储在一个数组中,为每个条目运行sp

时间:2013-11-13 18:35:04

标签: sql-server tsql sql-server-2012

我在Description列中包含以下内容的记录:

“发现服务器aaa-aaa-aaa已损坏,并于晚上8点被服务器bbb-bbb-bbb取代”

我想做一些看起来像这样的事情:

SET @serverArray = empty    
SELECT Description into @serverArray  
WHERE Description like '%-%-%'
FROM Operations

ForEach ROW in @serverArray
{
    sp_HardwareScan (ROW)
}

因此,我的例子将执行:

EXEC sp_HardwareScan (aaa-aaa-aaa)

EXEC sp_HardwareScan (bbb-bbb-bbb)

1 个答案:

答案 0 :(得分:2)

SQL Server中没有数组这样的东西,通常你应该在考虑循环处理事物的时候停下来思考它。也就是说,根据你在循环的每次迭代中需要做什么,它并不总是可能的。这是一种在每行调用存储过程的简单方法,而不会创建凌乱的while循环或游标结构。但是,这不会解析仅仅aaa-aaa-aaabbb-bbb-bbb的描述部分......最初并不清楚。为什么这些不是作为单独的列存储而不是在一个大字符串中拼凑在一起?你为什么要从SQL Server内部进行这种“硬件扫描”?听起来更像是PowerShell,C#等的工作。

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'EXEC sp_HardwareScan ''' + REPLACE(Description,'''','''''') + ''';
'
  FROM dbo.Operations
  WHERE Description LIKE '%-%-%';

PRINT @sql;

-- EXEC sp_executesql @sql;

由于我现在明白你每行需要多个过程调用,所以首先创建一个split函数:

CREATE FUNCTION [dbo].[SplitString]
    (
        @List NVARCHAR(MAX),
        @Delim VARCHAR(255)
    )
    RETURNS TABLE
    AS
        RETURN ( SELECT [Value] FROM 
          ( 
            SELECT 
              [Value] = LTRIM(RTRIM(SUBSTRING(@List, [Number],
              CHARINDEX(@Delim, @List + @Delim, [Number]) - [Number])))
            FROM (SELECT Number = ROW_NUMBER() OVER (ORDER BY name)
              FROM sys.all_objects) AS x
              WHERE Number <= LEN(@List)
              AND SUBSTRING(@Delim + @List, [Number], LEN(@Delim)) = @Delim
          ) AS y
        );

现在,您可以在外部应用中使用该函数来获取需要传递给存储过程的每个字符串的部分。

SET NOCOUNT ON;

DECLARE @x TABLE(Description VARCHAR(MAX));

INSERT @x VALUES('Server c-4-5h was offline & replaced with R2-D2-C3P0 at 5AM'),
('Server aaa-aaa-aaa was broken & replaced with server bbb-bbb-bbb at 8pm');

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'EXEC sp_HardwareScan ''' + REPLACE(Value, '''', '''''') + ''';
'
FROM @x AS x OUTER APPLY dbo.SplitString(REPLACE(x.Description,' ',';'), ';') AS y
WHERE y.Value LIKE '%-%-%';

PRINT @sql;

-- EXEC sp_executesql @sql;

结果:

EXEC sp_HardwareScan 'c-4-5h';
EXEC sp_HardwareScan 'R2-D2-C3P0';
EXEC sp_HardwareScan 'aaa-aaa-aaa';
EXEC sp_HardwareScan 'bbb-bbb-bbb';

只需将@x替换为dbo.Operations即可测试您的真实桌面(always specify schema)。

有关分割函数的更多信息,为什么(并证明)while循环和递归CTE不能缩放,以及更好的替代方法,如果分割来自应用程序层的字符串:

在SQL Server 2016或更高版本上,您应该查看STRING_SPLIT()STRING_AGG()

另外,STOP using the sp_ prefix for stored procedures