有没有办法在 SQL 服务器中循环字符串?
Is there any way to loop a string in SQL Server?
我正在尝试在 SQL 服务器中循环一个 varchar,其中一列的格式为
"F1 100 F2 400 F3 600"
我需要的是取数字除以 10:“F1 10 F2 40 F3 60”,目前我有一个调用此函数的存储过程:
ALTER FUNCTION [name_offunction]
(@Chain varchar(120))
RETURNS varchar(120
AS
BEGIN
DECLARE @Result varchar(120), @Pos int, @Concat varchar(120)
WHILE LEN(@Chain) > 0
BEGIN
SET @Pos = CHARINDEX(' ', @Chain)
SET @Result = CASE
WHEN SUBSTRING(@Chain, 1, @Pos-1) LIKE '%[^A-Z]%'
THEN SUBSTRING(@Chain, 1, @Pos-1)
WHEN SUBSTRING(@Chain, 1, @Pos-1) NOT LIKE '%[^A-Z]%'
THEN CAST(CAST(SUBSTRING(@Chain, 1, @Pos-1) / 10 AS INT)AS CHAR)
END
SET @Chain = REPLACE(@Chain, SUBSTRING(@Chain, 1, @Pos), '')
SET @Concat += @Result + ' '
END
RETURN @Concat
我们这里似乎有两个问题。首先,您想在 SQL 中循环,但是 SQL 是一种基于集合的语言。这意味着它在基于集合的操作方面表现出色,但在迭代操作方面表现不佳,例如循环。
接下来是您拥有看似分隔的数据,并且您希望以某种方式影响该分隔的数据,并将数据重建为分隔的字符串。在数据库中存储带分隔符的数据始终是一个设计缺陷,您真的应该修复上述设计。
因此,我建议您在标量函数上移动到内联 table 值函数。
首先,由于值的顺序位置很重要,我们不能使用SQL服务器内置的STRING_SPLIT
,因为它记录为不保证值的顺序相同。因此,我将使用 DelimitedSplit8K_LEAD
给出序数位置。
然后我们可以使用 TRY_CONVERT
来检查该值是否是 int
(我假设这是正确的数据类型),如果它被 10
除.最后我们可以使用 STRING_AGG
.
重建数据
在函数之外看起来像这样:
DECLARE @Chain varchar(120) = 'F1 100 F2 400 F3 600';
SELECT STRING_AGG(COALESCE(CONVERT(varchar(10),TRY_CONVERT(int,DS.item)/10),DS.item),' ') WITHIN GROUP (ORDER BY DS.Item)
FROM dbo.DelimitedSplit8K_LEAD(@Chain,' ') DS;
作为一个函数,您可以这样做:
CREATE FUNCTION dbo.YourFunction (@Chain varchar(120))
RETURNS TABLE AS
RETURN
SELECT STRING_AGG(COALESCE(CONVERT(varchar(10),TRY_CONVERT(int,DS.item)/10),DS.item),' ') WITHIN GROUP (ORDER BY DS.Item) AS NewChain
FROM dbo.DelimitedSplit8K_LEAD(@Chain,' ') DS;
GO
调用是这样的:
SELECT YF.NewChain
FROM dbo.YourTable YT
CROSS APPLY dbo.YourFunction (YT.Chain) YF;
请注意,STRING_AGG
是在 SQL Server 2017 中引入的;如果您使用的是旧版本(您没有注意到这是问题所在),则需要使用“旧”FOR XML PATH
解决方案,如 .
所示
我正在尝试在 SQL 服务器中循环一个 varchar,其中一列的格式为
"F1 100 F2 400 F3 600"
我需要的是取数字除以 10:“F1 10 F2 40 F3 60”,目前我有一个调用此函数的存储过程:
ALTER FUNCTION [name_offunction]
(@Chain varchar(120))
RETURNS varchar(120
AS
BEGIN
DECLARE @Result varchar(120), @Pos int, @Concat varchar(120)
WHILE LEN(@Chain) > 0
BEGIN
SET @Pos = CHARINDEX(' ', @Chain)
SET @Result = CASE
WHEN SUBSTRING(@Chain, 1, @Pos-1) LIKE '%[^A-Z]%'
THEN SUBSTRING(@Chain, 1, @Pos-1)
WHEN SUBSTRING(@Chain, 1, @Pos-1) NOT LIKE '%[^A-Z]%'
THEN CAST(CAST(SUBSTRING(@Chain, 1, @Pos-1) / 10 AS INT)AS CHAR)
END
SET @Chain = REPLACE(@Chain, SUBSTRING(@Chain, 1, @Pos), '')
SET @Concat += @Result + ' '
END
RETURN @Concat
我们这里似乎有两个问题。首先,您想在 SQL 中循环,但是 SQL 是一种基于集合的语言。这意味着它在基于集合的操作方面表现出色,但在迭代操作方面表现不佳,例如循环。
接下来是您拥有看似分隔的数据,并且您希望以某种方式影响该分隔的数据,并将数据重建为分隔的字符串。在数据库中存储带分隔符的数据始终是一个设计缺陷,您真的应该修复上述设计。
因此,我建议您在标量函数上移动到内联 table 值函数。
首先,由于值的顺序位置很重要,我们不能使用SQL服务器内置的STRING_SPLIT
,因为它记录为不保证值的顺序相同。因此,我将使用 DelimitedSplit8K_LEAD
给出序数位置。
然后我们可以使用 TRY_CONVERT
来检查该值是否是 int
(我假设这是正确的数据类型),如果它被 10
除.最后我们可以使用 STRING_AGG
.
在函数之外看起来像这样:
DECLARE @Chain varchar(120) = 'F1 100 F2 400 F3 600';
SELECT STRING_AGG(COALESCE(CONVERT(varchar(10),TRY_CONVERT(int,DS.item)/10),DS.item),' ') WITHIN GROUP (ORDER BY DS.Item)
FROM dbo.DelimitedSplit8K_LEAD(@Chain,' ') DS;
作为一个函数,您可以这样做:
CREATE FUNCTION dbo.YourFunction (@Chain varchar(120))
RETURNS TABLE AS
RETURN
SELECT STRING_AGG(COALESCE(CONVERT(varchar(10),TRY_CONVERT(int,DS.item)/10),DS.item),' ') WITHIN GROUP (ORDER BY DS.Item) AS NewChain
FROM dbo.DelimitedSplit8K_LEAD(@Chain,' ') DS;
GO
调用是这样的:
SELECT YF.NewChain
FROM dbo.YourTable YT
CROSS APPLY dbo.YourFunction (YT.Chain) YF;
请注意,STRING_AGG
是在 SQL Server 2017 中引入的;如果您使用的是旧版本(您没有注意到这是问题所在),则需要使用“旧”FOR XML PATH
解决方案,如