【问题标题】:Split comma separated varchar parameter up into temp table将逗号分隔的 varchar 参数拆分为临时表
【发布时间】:2015-04-07 20:06:50
【问题描述】:

我有以下存储过程:

CREATE PROCEDURE myProc
    @nameList varchar(500)
AS
BEGIN
    create table #names (Name varchar(20))

    -- split @nameList up into #names table
END
GO

@nameList 基本上看起来像这样:

'John, Samantha, Bob, Tom'

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

    使用转换为XMLcross apply

      DECLARE @str varchar(50)
      SET @str='John, Samantha, Bob, Tom'
    
      SELECT names = y.i.value('(./text())[1]', 'nvarchar(1000)')             
      FROM 
      ( 
        SELECT 
            n = CONVERT(XML, '<i>' 
                + REPLACE(@str, ',' , '</i><i>') 
                + '</i>')
      ) AS a 
      CROSS APPLY n.nodes('i') AS y(i)
    

    输出:

    names
    -----
    John
     Samantha
     Bob
     Tom
    

    编辑: proc 内不需要临时表,因此 proc 将是:

    CREATE PROCEDURE myProc
    
        (@nameList varchar(500))
    
    AS
    BEGIN
    
          SELECT names = y.i.value('(./text())[1]', 'nvarchar(1000)')             
          FROM 
          ( 
            SELECT 
                n = CONVERT(XML, '<i>' 
                    + REPLACE(@nameList, ',' , '</i><i>') 
                    + '</i>')
          ) AS a 
          CROSS APPLY n.nodes('i') AS y(i)
    END
    

    但是如果你想将它插入到临时表中,下面是一个示例:

    create table #names 
        (
            Name varchar(20)
        )
    
      DECLARE @str varchar(50)
      SET @str='John, Samantha, Bob, Tom'
    
      insert into #names
      SELECT names = y.i.value('(./text())[1]', 'nvarchar(1000)')             
      FROM 
      ( 
        SELECT 
            n = CONVERT(XML, '<i>' 
                + REPLACE(@str, ',' , '</i><i>') 
                + '</i>')
      ) AS a 
      CROSS APPLY n.nodes('i') AS y(i)
    
      select * from #names 
      drop table #names 
    

    编辑 2: 输入字符串可能包含一些特殊字符,例如 '&lt;' , '&gt;' , etc 这不是名称的标准,但如果给定字符串包含它们,您可以使用 replace 函数删除它们:@ 987654329@

    【讨论】:

    • 虽然,它不应该在某处说“选择 INTO #names”...?
    • @DeanGrobler,我认为那里不需要临时表,或者您想将结果插入到临时表中?
    • 我确实想插入临时表。我只是用一个非常简单的例子来回答我的问题。我想要在现实中完成的事情有点复杂
    • @Farhęg .query('.')n = CONVERT(XML, '&lt;i&gt;' + REPLACE(@str, ',' , '&lt;/i&gt;&lt;i&gt;') + '&lt;/i&gt;').query('.') 中的额外好处是什么。
    • @ughai,在这种情况下不需要.query('.'),已删除。感谢您的评论,祝您好运。
    【解决方案2】:

    使用递归 cte:

    DECLARE @nameList NVARCHAR(MAX) = 'John, Samantha, Bob, Tom'
    SET @nameList = @nameList + ',';
    
    WITH    cte
              AS ( SELECT   SUBSTRING(@nameList, 0, CHARINDEX(',', @nameList)) AS n ,
                            CHARINDEX(',', @nameList) AS i
                   UNION ALL
                   SELECT   SUBSTRING(@nameList, i + 2,CHARINDEX(',', @nameList, i + 2) - i - 2) ,
                            CHARINDEX(',', @nameList, i + 2)
                   FROM     cte
                   WHERE    CHARINDEX(',', @nameList, i + 2) > 0
                 )
        SELECT  n FROM    cte
    

    输出:

    n
    John
    Samantha
    Bob
    Tom
    

    【讨论】:

      【解决方案3】:

      你可以创建函数并从你想分割的任何地方调用这个函数:-

      create FUNCTION [dbo].[SplitStrings](@nameList varchar(MAX), @Delimiter char(1))       
      returns @temptable TABLE (names varchar(MAX))       
      as       
      begin      
          declare @id int       
          declare @x varchar(8000)       
      
          select @id = 1       
              if len(@nameList)<1 or @nameList is null  return       
      
          while @id!= 0       
          begin       
              set @id = charindex(@Delimiter,@nameList)       
              if @id!=0       
                  set @x = left(@nameList,@id - 1)       
              else       
                  set @x = @nameList
      
              if(len(@x)>0)  
                  insert into @temptable(names) values(@x)       
      
              set @String = right(@nameList,len(@nameList) - @id)       
              if len(@nameList) = 0 break       
          end   
      return 
      end;
      

      【讨论】:

        【解决方案4】:
        CREATE FUNCTION [dbo].[Split]
        (
            @RowData nvarchar(MAX),
            @SplitOn nvarchar(5)
        )  
        RETURNS @RtnValue table 
        (
            Id int identity(1,1),
            Data nvarchar(100)
        ) 
        AS  
        BEGIN 
            Declare @Cnt int
            Set @Cnt = 1
        
            While (Charindex(@SplitOn,@RowData)>0)
            Begin
                Insert Into @RtnValue (data)
                Select 
                    Data = ltrim(rtrim(Substring(@RowData,1,Charindex(@SplitOn,@RowData)-1)))
        
                Set @RowData = Substring(@RowData,Charindex(@SplitOn,@RowData)+1,len(@RowData))
                Set @Cnt = @Cnt + 1
            End
        
            Insert Into @RtnValue (data)
            Select Data = ltrim(rtrim(@RowData))
        
            Return
        END
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-08-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-04-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多