将逗号分隔的ID列表转换为逗号分隔的前缀列表SQL Server

时间:2016-06-22 15:06:48

标签: sql-server function delimiter

我试图将逗号分隔的ID列表转换为以逗号分隔的前缀列表。

BKR394859607,MTP293840284,SPN489620586

我的目标是将SQL Server中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)

4 个答案:

答案 0 :(得分:2)

如Sean Lange的评论所述,您需要执行三个步骤

  1. 将字符串拆分为单独的行
  2. 删除所需的字符
  3. 将行连接回CSV。
  4. 像这样的东西

    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

答案 1 :(得分:1)

试试这个:

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;

答案 2 :(得分:1)

首先,阅读以下文章,他们讨论拆分字符串(以及不这样做的理由),并比较方法的性能,如果你无法避免它。

这三篇文章的结果是(如果链接已经死亡):

  1. 尽可能避免将分隔列表作为字符串,如果需要存储列表,表格是更好的选择。
  2. 如果必须这样做,CLR是最具可扩展性(且准确的方法)。
  3. 如果您可以确定没有要拆分的特殊XML字符,那么将分隔的字符串转换为XML,然后使用XQuery来获取各个项目。
  4. 否则,使用交叉连接构建计数表是其中最好的。
  5. 最通用的方法是最后一种方法,因为不是每个人都可以使用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

    最佳解决方案可能是使用用户定义的表类型来存储字符串列表:

    CREATE TYPE dbo.StringList AS TABLE (Value VARCHAR(MAX));
    

    然后,不是建立一个分隔的字符串,而是建立一个表:

    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, '');
    

答案 3 :(得分:1)

使用以下answerregeular中实现T-SQL表达式函数。然后您可以使用以下内容:

enter image description here