将逗号分隔的 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 在评论中提到的,您需要执行三个步骤

  1. 将字符串拆分成单独的行
  2. 去掉需要的字符
  3. 将行连接回 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;

首先,阅读以下文章,他们讨论了拆分字符串(以及不这样做的原因),并比较了在无法避免的情况下进行拆分的方法的性能。

这三篇文章的结果是(以防链接失效):

  1. 尽可能避免将分隔列表作为字符串,如果您需要存储列表,table 是更好的选择。
  2. 如果您必须这样做,CLR 是最具可扩展性(也是最准确的方法)。
  3. 如果您可以确定没有特殊的 XML 字符要拆分,则将分隔字符串转换为 XML 然后使用 XQuery 获取单个项目效果很好。
  4. 否则,使用交叉连接构建计数 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表达式函数。然后您可以使用以下内容: