SQL Server 中没有数组这样的东西,通常在考虑循环处理事物时,您应该停下来考虑一下。也就是说,这并不总是可能的,这取决于您在循环的每次迭代中需要做什么。这是每行调用一个存储过程的简单方法,而不会创建混乱的 while 循环或游标结构。然而,这并没有解析出描述中只是aaa-aaa-aaa
和bbb-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;
既然我现在明白每行需要多个过程调用,那么首先创建一个拆分函数怎么样:
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
对您的真实表进行测试(始终指定模式)。
有关拆分函数的更多信息,为什么(并证明)while 循环和递归 CTE 不能扩展,以及更好的替代方案,如果拆分来自应用程序层的字符串:
但是,在 SQL Server 2016 或更高版本上,您应该查看STRING_SPLIT()
and STRING_AGG()
:
此外,停止使用sp_
存储过程的前缀。