8

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

让 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
4

6 回答 6

25

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

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 |
于 2013-02-11T12:25:59.753 回答
5

你可以用 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
于 2013-02-11T12:10:11.907 回答
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_ID和 选择所有逗号分隔值ListType_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)
于 2015-01-07T12:17:27.317 回答
2
select Rule_ID ,ListType_ID,Values as value
FROM table  
    CROSS APPLY STRING_SPLIT(Values, ',');  
于 2018-07-21T06:21:19.257 回答
0

您可以创建一个返回表 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
于 2013-02-11T12:11:18.693 回答
0

完成@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
于 2016-06-23T19:03:49.723 回答