【问题标题】:separate comma separated values and store in table in sql server单独的逗号分隔值并存储在 sql server 的表中
【发布时间】:2013-02-11 11:56:45
【问题描述】:

我有一个存储过程,它将逗号分隔值作为输入。我需要将其分开并需要将其作为单独的行存储在表中。

让 SP 的输入为:

Rule_ID  ListType_ID  Values
1        2            319,400,521,8465,2013

我需要将它存储在一个名为DistributionRule_x_ListType 的表中,格式如下:

Rule_ID  ListType_ID  Value
1        2            319
1        2            400
1        2            521
1        2            8465
1        2            2013

我的 SP 如下所示:

ALTER PROCEDURE [dbo].[spInsertDistributionRuleListType]
(@Rule_ID int,
@ListType_ID int,
@Values VARCHAR(MAX)=NULL
)
AS
BEGIN

    INSERT INTO DistributionRule_x_ListType (Rule_ID,ListType_ID,Value)
    VALUES (@Rule_ID,@ListType_ID,@Values)

END

【问题讨论】:

标签: sql sql-server sql-server-2005


【解决方案1】:

您将需要创建一个类似于此的拆分函数:

create FUNCTION [dbo].[Split](@String varchar(MAX), @Delimiter char(1))       
returns @temptable TABLE (items varchar(MAX))       
as       
begin      
    declare @idx int       
    declare @slice varchar(8000)       

    select @idx = 1       
        if len(@String)<1 or @String is null  return       

    while @idx!= 0       
    begin       
        set @idx = charindex(@Delimiter,@String)       
        if @idx!=0       
            set @slice = left(@String,@idx - 1)       
        else       
            set @slice = @String       

        if(len(@slice)>0)  
            insert into @temptable(Items) values(@slice)       

        set @String = right(@String,len(@String) - @idx)       
        if len(@String) = 0 break       
    end   
return 
end;

然后在您的存储过程中,您将调用该函数来拆分您的字符串:

ALTER PROCEDURE [dbo].[spInsertDistributionRuleListType]
(
  @Rule_ID int,
  @ListType_ID int,
  @Values VARCHAR(MAX)=NULL
)
AS
BEGIN

    INSERT INTO DistributionRule_x_ListType (Rule_ID, ListType_ID, Value)
    SELECT @Rule_ID, @ListType_ID, items
    FROM [dbo].[Split] (@Values, ',')  -- call the split function 

END

当您执行存储过程时,它将拆分值并将多行插入到您的表中:

exec spInsertDistributionRuleListType 1, 2, '319,400,521,8465,2013';

SQL Fiddle with Demo。这将插入以下结果:

| RULE_ID | LISTTYPE_ID | VALUE |
---------------------------------
|       1 |           1 |    10 |
|       1 |           2 |   319 |
|       1 |           2 |   400 |
|       1 |           2 |   521 |
|       1 |           2 |  8465 |
|       1 |           2 |  2013 |

【讨论】:

  • 如何初始化 'items'。它显示错误为 Invalid Column name 'items'
  • @prabuR 你是否包含了 from 子句? from 子句调用 split 函数
  • 在我的 SP 中,我可以将空值传递给该拆分函数...如果传递了空值,如何使其工作?
  • @prabuR 您可以使用IF 语句来使用两个单独的INSERT 语句,一个使用拆分,另一个不使用--请参阅此演示--sqlfiddle.com/#!3/4179d/1
  • 我已经试过了。有用。但我想到了在函数内部进行修改的任何其他简单有效的方法。无论如何,谢谢
【解决方案2】:

你可以用 charindex 来做到这一点

DECLARE @id VARCHAR(MAX)

SET @id = @Values          --'319,400,521,8465,2013,'

WHILE CHARINDEX(',', @id) > 0 
BEGIN

    DECLARE @tmpstr VARCHAR(50)
     SET @tmpstr = SUBSTRING(@id, 1, ( CHARINDEX(',', @id) - 1 ))

    INSERT  INTO DistributionRule_x_ListType
            ( Rule_ID ,
              ListType_ID ,
              Value
            )
    VALUES  ( @Rule_ID ,
              @ListType_ID ,
              @tmpstr)
            )
    SET @id = SUBSTRING(@id, CHARINDEX(',', @id) + 1, LEN(@id))
END

【讨论】:

    【解决方案3】:

    你可以在没有dbo.Split函数的情况下做到这一点。

    这是您的示例数据

    SELECT * INTO #TEMP
    FROM
    (
         SELECT 1  Rule_ID, 2 ListType_ID, '319,400,521,8465,2013' [Values]
         UNION ALL
         SELECT 1  , 3 , '100,200' 
    )TAB
    

    现在执行以下查询,将为每个 Rule_IDListType_ID 选择所有逗号分隔值。

    SELECT [Rule_ID],ListType_ID,
    PARSENAME(REPLACE(Split.a.value('.', 'VARCHAR(100)'),'-','.'),1) 'Values' 
    FROM  
    (
         SELECT [Rule_ID],ListType_ID,
         CAST ('<M>' + REPLACE([Values], ',', '</M><M>') + '</M>' AS XML) AS Data 
         FROM #TEMP     
    ) AS A 
    CROSS APPLY Data.nodes ('/M') AS Split(a)
    

    【讨论】:

      【解决方案4】:
      select Rule_ID ,ListType_ID,Values as value
      FROM table  
          CROSS APPLY STRING_SPLIT(Values, ',');  
      

      【讨论】:

      • 虽然此代码 sn-p 可能是解决方案,但 including an explanation 确实有助于提高您的帖子质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
      【解决方案5】:

      您可以创建一个返回 table var 的 udf 来拆分字符串。我们在MSSQL2005上成功使用了以下。

      CREATE FUNCTION [dbo].[fn_explode] (
          @str_separator NVARCHAR(255),
          @str_string VARCHAR(4000)
      )
      RETURNS @ret_string_parts TABLE (str_value varchar(4000))
      AS
      BEGIN
          DECLARE @intPos INT
          DECLARE @intLengthString INT
          DECLARE @intTempPatIndex INT
          DECLARE @intLengthSeparator INT
      
          SET @str_string = @str_string + @str_separator
      
          SET @intPos = 0
          SET @intLengthString = LEN(@str_string)
          SET @intLengthSeparator = LEN(@str_separator)
      
      
      
          IF PATINDEX ( '%' + @str_separator + '%' , @str_string ) <= 0 BEGIN
              INSERT INTO @ret_string_parts
              SELECT @str_string
              RETURN
          END
      
          IF @str_separator =  @str_string BEGIN
              INSERT INTO @ret_string_parts
              SELECT @str_string
              RETURN
          END
      
          WHILE @intPos <= @intLengthString
          BEGIN
              SET @intTempPatIndex = PATINDEX('%' + @str_separator + '%', SUBSTRING(@str_string, @intPos,@intLengthString))
              IF @intTempPatIndex = 0 BEGIN
                  INSERT INTO @ret_string_parts
                  SELECT SUBSTRING(@str_string, @intPos, @intLengthString)
                  BREAK
              END
              ELSE BEGIN
                  IF @intPos = 0 BEGIN
                      INSERT INTO @ret_string_parts
                      SELECT SUBSTRING(@str_string, @intPos, @intTempPatIndex)
                      SET @intPos = @intPos + @intTempPatIndex + @intLengthSeparator
                  END
                  ELSE BEGIN
                      INSERT INTO @ret_string_parts
                      SELECT SUBSTRING(@str_string, @intPos, @intTempPatIndex-1)
                      SET @intPos = @intPos + @intTempPatIndex + (@intLengthSeparator-1)
                  END
      
              END
          END
      
          RETURN
      END
      

      【讨论】:

        【解决方案6】:

        完成@bluefeet 回答后,您还可以使用 CSV 字符串将多个值存储在多个列中:

         --input sql text 
        declare @text_IN varchar(max) ='text1, text1.2, text1.3, 1, 2010-01-01\r\n text2, text2.2, text2.3, 2, 2016-01-01'
        

        将 csv 文件拆分为行:

        declare @temptable table (csvRow varchar(max))    
        declare @DelimiterInit varchar(4) = '\r\n'
        declare @Delimiter varchar(1) = '|'
        declare @idx int       
        declare @slice varchar(max)    
        
        set @text_IN = REPLACE(@text_IN,@DelimiterInit,@Delimiter)
        
        
        select @idx = 1       
            if len(@text_IN)<1 or @text_IN is null  return       
        
        while @idx!= 0       
        begin       
            set @idx = charindex(@Delimiter,@text_IN)       
            if @idx!=0       
                set @slice = left(@text_IN,@idx - 1)       
            else       
                set @slice = @text_IN 
        
            if(len(@slice)>0)  
                insert into @temptable(csvRow) values(@slice)       
        
            set @text_IN = right(@text_IN,len(@text_IN) - @idx)       
            if len(@text_IN) = 0 break       
        end   
        

        将行拆分为列:

        ;WITH XMLTable (xmlTag)
        AS
        (
            SELECT CONVERT(XML,'<CSV><champ>' + REPLACE(csvRow,',', '</champ><champ>') + '</champ></CSV>') AS xmlTag
            FROM @temptable
        )
        
         SELECT RTRIM(LTRIM(xmlTag.value('/CSV[1]/champ[1]','varchar(max)'))) AS Column1,    
                RTRIM(LTRIM(xmlTag.value('/CSV[1]/champ[2]','varchar(max)'))) AS Column2,
                RTRIM(LTRIM(xmlTag.value('/CSV[1]/champ[3]','varchar(max)'))) AS Column3,    
                RTRIM(LTRIM(xmlTag.value('/CSV[1]/champ[4]','int'))) AS Column4,
                RTRIM(LTRIM(xmlTag.value('/CSV[1]/champ[5]','datetime'))) AS Column5
         FROM XMLTable
        

        【讨论】:

          猜你喜欢
          • 2019-01-06
          • 1970-01-01
          • 2014-06-17
          • 1970-01-01
          • 2012-09-08
          • 2022-09-27
          • 1970-01-01
          • 2011-04-04
          • 2018-01-23
          相关资源
          最近更新 更多