将逗号分隔的 ID 列表转换为逗号分隔的前缀列表 SQL 服务器
Convert comma delimited ID list to Comma delimited prefix List SQL Server
我正在尝试将逗号分隔的 ID 列表转换为逗号分隔的前缀列表。
BKR394859607,MTP293840284,SPN489620586
我的目标是将 SQL 服务器中我的 IDString 中的这 3 个 ID 转换为
BKR,MTP,SPN
这个字符串可以有无限多个 ID
Declare @ActivityID as varchar(MAX) = 'BKR394859607,MTP293840284,SPN489620586'
Declare @ActivityPrefixes as varchar(MAX)
Set @ActivityPrefixes = (function to Convert to comma delimited prefix list)
正如 Sean Lange 在评论中提到的,您需要执行三个步骤
- 将字符串拆分成单独的行
- 去掉需要的字符
- 将行连接回 CSV。
像这样
DECLARE @ActivityID AS VARCHAR(max) =
'BKR394859607,MTP293840284,SPN489620586,GHY489620586'
SELECT Stuff(split_val, 1, 1, '') as Result
FROM (SELECT ','
+ LEFT(split.a.value('.', 'VARCHAR(100)'), 3)
FROM (SELECT Cast ('<M>' + Replace(@ActivityID, ',', '</M><M>')
+ '</M>' AS XML) AS Data) AS A
CROSS apply data.nodes ('/M') AS Split(a)
FOR xml path(''))a(split_val)
结果: BKR,MTP,SPN,GHY
试试这个:
DECLARE @ActivityID AS VARCHAR(MAX) = 'BKR394859607,MTP293840284,SPN489620586';
DECLARE @ActivityPrefixes AS VARCHAR(MAX);
SET @ActivityPrefixes = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
REPLACE(REPLACE(REPLACE(REPLACE(
@ActivityID,'0', ''), '1',''), '2', ''),'3', ''), '4',''), '5', ''),
'6', ''),'7', ''), '8', ''), '9', '');
SELECT @ActivityPrefixes
如果您想获取每个部分的前 3 个字符,请尝试以下操作:
DECLARE @ActivityID AS VARCHAR(MAX) = 'BKR39A859607,M3TP293840284,SP1N4896GG586,BKR394859607,MTP293840284,SPN489620586';
DECLARE @ActivityPrefixes AS VARCHAR(MAX);
SET @ActivityPrefixes = '';
WHILE 1 = 1
BEGIN
DECLARE @i INT;
IF CHARINDEX(',', @ActivityID) = 0
SET @i = 3;
ELSE
SET @i = CHARINDEX(',', @ActivityID) - 1;
IF @ActivityPrefixes = ''
SET @ActivityPrefixes = SUBSTRING(SUBSTRING(@ActivityID, 1, @i), 1,3);
ELSE
SET @ActivityPrefixes = @ActivityPrefixes + ','
+ SUBSTRING(SUBSTRING(@ActivityID, 1, @i), 1, 3);
IF CHARINDEX(',', @ActivityID) = 0
BREAK;
SET @ActivityID = SUBSTRING(@ActivityID,CHARINDEX(',', @ActivityID) + 1,LEN(@ActivityID));
END;
SELECT @ActivityPrefixes;
首先,阅读以下文章,他们讨论了拆分字符串(以及不这样做的原因),并比较了在无法避免的情况下进行拆分的方法的性能。
- Split strings the right way – or the next best way
- Splitting Strings : A Follow-Up
- Splitting Strings : Now with less T-SQL
这三篇文章的结果是(以防链接失效):
- 尽可能避免将分隔列表作为字符串,如果您需要存储列表,table 是更好的选择。
- 如果您必须这样做,CLR 是最具可扩展性(也是最准确的方法)。
- 如果您可以确定没有特殊的 XML 字符要拆分,则将分隔字符串转换为 XML 然后使用 XQuery 获取单个项目效果很好。
- 否则,使用交叉连接构建计数 table 是其他方法中最好的。
最通用的方法是最后一种,因为不是每个人都会用CLR,保证没有特殊的XML字符,所以拆分方法是:
CREATE FUNCTION [dbo].[Split]
(
@List NVARCHAR(MAX),
@Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING AS
RETURN
( WITH N1 AS (SELECT N FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1), (1)) n (N)),
N2(N) AS (SELECT 1 FROM N1 a CROSS JOIN N1 b),
N3(N) AS (SELECT 1 FROM N2 a CROSS JOIN N2 b),
N4(N) AS (SELECT 1 FROM N3 a CROSS JOIN N3 b),
cteTally(N) AS
( SELECT 0 UNION ALL
SELECT TOP (DATALENGTH(ISNULL(@List,1))) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM n4
),
cteStart(N1) AS
( SELECT t.N+1
FROM cteTally t
WHERE (SUBSTRING(@List,t.N,1) = @Delimiter OR t.N = 0)
)
SELECT Item = SUBSTRING(@List, s.N1, ISNULL(NULLIF(CHARINDEX(@Delimiter,@List,s.N1),0)-s.N1,8000)),
Position = s.N1,
ItemNumber = ROW_NUMBER() OVER(ORDER BY s.N1)
FROM cteStart s
);
现在您有了 Split 函数,您可以拆分您的第一个字符串:
DECLARE @ActivityID AS VARCHAR(MAX) = 'BKR394859607,MTP293840284,SPN489620586';
SELECT Item,
NewID = LEFT(Item, 3)
FROM dbo.Split(@ActivityID, ',');
这给你:
Item NewID
-----------------------------
BKR394859607 BKR
MTP293840284 MTP
SPN489620586 SPN
然后您可以使用 FOR XML PATH()
:
连接此备份
DECLARE @ActivityID AS VARCHAR(MAX) = 'BKR394859607,MTP293840284,SPN489620586';
SELECT STUFF(( SELECT ',' + LEFT(Item, 3)
FROM dbo.Split(@ActivityID, ',')
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '');
有关其工作原理的更多信息,请参阅 this answer。
最佳解决方案可能是让用户定义 table 类型来存储字符串列表:
CREATE TYPE dbo.StringList AS TABLE (Value VARCHAR(MAX));
然后不是构建分隔字符串,而是构建 table:
DECLARE @Activity dbo.StringList;
INSERT @Activity (Value)
VALUES ('BKR394859607'), ('MTP293840284'), ('SPN489620586');
然后你就避免了痛苦的分裂,并且可以更容易地操纵每个单独的记录。
如果你确实需要得到一个新的分隔字符串,那么你可以使用与上面相同的逻辑:
DECLARE @Activity dbo.StringList;
INSERT @Activity (Value)
VALUES ('BKR394859607'), ('MTP293840284'), ('SPN489620586');
SELECT STUFF(( SELECT ',' + LEFT(Value, 3)
FROM @Activity
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '');
使用以下answer实现T-SQL
中的regeular
表达式函数。然后您可以使用以下内容:
我正在尝试将逗号分隔的 ID 列表转换为逗号分隔的前缀列表。
BKR394859607,MTP293840284,SPN489620586
我的目标是将 SQL 服务器中我的 IDString 中的这 3 个 ID 转换为
BKR,MTP,SPN
这个字符串可以有无限多个 ID
Declare @ActivityID as varchar(MAX) = 'BKR394859607,MTP293840284,SPN489620586'
Declare @ActivityPrefixes as varchar(MAX)
Set @ActivityPrefixes = (function to Convert to comma delimited prefix list)
正如 Sean Lange 在评论中提到的,您需要执行三个步骤
- 将字符串拆分成单独的行
- 去掉需要的字符
- 将行连接回 CSV。
像这样
DECLARE @ActivityID AS VARCHAR(max) =
'BKR394859607,MTP293840284,SPN489620586,GHY489620586'
SELECT Stuff(split_val, 1, 1, '') as Result
FROM (SELECT ','
+ LEFT(split.a.value('.', 'VARCHAR(100)'), 3)
FROM (SELECT Cast ('<M>' + Replace(@ActivityID, ',', '</M><M>')
+ '</M>' AS XML) AS Data) AS A
CROSS apply data.nodes ('/M') AS Split(a)
FOR xml path(''))a(split_val)
结果: BKR,MTP,SPN,GHY
试试这个:
DECLARE @ActivityID AS VARCHAR(MAX) = 'BKR394859607,MTP293840284,SPN489620586';
DECLARE @ActivityPrefixes AS VARCHAR(MAX);
SET @ActivityPrefixes = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
REPLACE(REPLACE(REPLACE(REPLACE(
@ActivityID,'0', ''), '1',''), '2', ''),'3', ''), '4',''), '5', ''),
'6', ''),'7', ''), '8', ''), '9', '');
SELECT @ActivityPrefixes
如果您想获取每个部分的前 3 个字符,请尝试以下操作:
DECLARE @ActivityID AS VARCHAR(MAX) = 'BKR39A859607,M3TP293840284,SP1N4896GG586,BKR394859607,MTP293840284,SPN489620586';
DECLARE @ActivityPrefixes AS VARCHAR(MAX);
SET @ActivityPrefixes = '';
WHILE 1 = 1
BEGIN
DECLARE @i INT;
IF CHARINDEX(',', @ActivityID) = 0
SET @i = 3;
ELSE
SET @i = CHARINDEX(',', @ActivityID) - 1;
IF @ActivityPrefixes = ''
SET @ActivityPrefixes = SUBSTRING(SUBSTRING(@ActivityID, 1, @i), 1,3);
ELSE
SET @ActivityPrefixes = @ActivityPrefixes + ','
+ SUBSTRING(SUBSTRING(@ActivityID, 1, @i), 1, 3);
IF CHARINDEX(',', @ActivityID) = 0
BREAK;
SET @ActivityID = SUBSTRING(@ActivityID,CHARINDEX(',', @ActivityID) + 1,LEN(@ActivityID));
END;
SELECT @ActivityPrefixes;
首先,阅读以下文章,他们讨论了拆分字符串(以及不这样做的原因),并比较了在无法避免的情况下进行拆分的方法的性能。
- Split strings the right way – or the next best way
- Splitting Strings : A Follow-Up
- Splitting Strings : Now with less T-SQL
这三篇文章的结果是(以防链接失效):
- 尽可能避免将分隔列表作为字符串,如果您需要存储列表,table 是更好的选择。
- 如果您必须这样做,CLR 是最具可扩展性(也是最准确的方法)。
- 如果您可以确定没有特殊的 XML 字符要拆分,则将分隔字符串转换为 XML 然后使用 XQuery 获取单个项目效果很好。
- 否则,使用交叉连接构建计数 table 是其他方法中最好的。
最通用的方法是最后一种,因为不是每个人都会用CLR,保证没有特殊的XML字符,所以拆分方法是:
CREATE FUNCTION [dbo].[Split]
(
@List NVARCHAR(MAX),
@Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING AS
RETURN
( WITH N1 AS (SELECT N FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1), (1)) n (N)),
N2(N) AS (SELECT 1 FROM N1 a CROSS JOIN N1 b),
N3(N) AS (SELECT 1 FROM N2 a CROSS JOIN N2 b),
N4(N) AS (SELECT 1 FROM N3 a CROSS JOIN N3 b),
cteTally(N) AS
( SELECT 0 UNION ALL
SELECT TOP (DATALENGTH(ISNULL(@List,1))) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM n4
),
cteStart(N1) AS
( SELECT t.N+1
FROM cteTally t
WHERE (SUBSTRING(@List,t.N,1) = @Delimiter OR t.N = 0)
)
SELECT Item = SUBSTRING(@List, s.N1, ISNULL(NULLIF(CHARINDEX(@Delimiter,@List,s.N1),0)-s.N1,8000)),
Position = s.N1,
ItemNumber = ROW_NUMBER() OVER(ORDER BY s.N1)
FROM cteStart s
);
现在您有了 Split 函数,您可以拆分您的第一个字符串:
DECLARE @ActivityID AS VARCHAR(MAX) = 'BKR394859607,MTP293840284,SPN489620586';
SELECT Item,
NewID = LEFT(Item, 3)
FROM dbo.Split(@ActivityID, ',');
这给你:
Item NewID
-----------------------------
BKR394859607 BKR
MTP293840284 MTP
SPN489620586 SPN
然后您可以使用 FOR XML PATH()
:
DECLARE @ActivityID AS VARCHAR(MAX) = 'BKR394859607,MTP293840284,SPN489620586';
SELECT STUFF(( SELECT ',' + LEFT(Item, 3)
FROM dbo.Split(@ActivityID, ',')
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '');
有关其工作原理的更多信息,请参阅 this answer。
最佳解决方案可能是让用户定义 table 类型来存储字符串列表:
CREATE TYPE dbo.StringList AS TABLE (Value VARCHAR(MAX));
然后不是构建分隔字符串,而是构建 table:
DECLARE @Activity dbo.StringList;
INSERT @Activity (Value)
VALUES ('BKR394859607'), ('MTP293840284'), ('SPN489620586');
然后你就避免了痛苦的分裂,并且可以更容易地操纵每个单独的记录。
如果你确实需要得到一个新的分隔字符串,那么你可以使用与上面相同的逻辑:
DECLARE @Activity dbo.StringList;
INSERT @Activity (Value)
VALUES ('BKR394859607'), ('MTP293840284'), ('SPN489620586');
SELECT STUFF(( SELECT ',' + LEFT(Value, 3)
FROM @Activity
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '');
使用以下answer实现T-SQL
中的regeular
表达式函数。然后您可以使用以下内容: