Sql server 使用SQL Server 2008 R2将逗号分隔的字符串分成列

Sql server 使用SQL Server 2008 R2将逗号分隔的字符串分成列,sql-server,sql-server-2008-r2,Sql Server,Sql Server 2008 R2,我想使用存储过程将批量值插入表中 下表名为m1,包含两个字段: create table m1 ( cola varchar(50), colb varchar(50) ); 将值插入表中的程序m1_测试: create procedure m1_test @stringCola varchar(max), @stringColb varchar(max) AS INSERT INTO m1 values(@stringCola,@stringCol

我想使用存储过程将批量值插入表中

下表名为m1,包含两个字段:

create table m1
(
    cola varchar(50),
    colb varchar(50)
);
将值插入表中的程序m1_测试:

create procedure m1_test
    @stringCola varchar(max),
    @stringColb varchar(max)

AS

    INSERT INTO m1 values(@stringCola,@stringColb);

GO
上述步骤适用于插入单个值,如下所示:

---EXECUTE SP
EXECUTE m1_test @stringCola = 'A1',@stringColb = 'Z1';
---EXECUTE SP
EXECUTE m1_test @stringCola = 'A1,A2,A3',@stringColb = 'Z1,Z2,Z3';
但如果我想在单个字符串中一次插入更多值,如下所示:

---EXECUTE SP
EXECUTE m1_test @stringCola = 'A1',@stringColb = 'Z1';
---EXECUTE SP
EXECUTE m1_test @stringCola = 'A1,A2,A3',@stringColb = 'Z1,Z2,Z3';
输出应为:

 cola   colb
 ------------
 A1     Z1
 A2     Z2
 A3     Z3

首先,您需要创建一个表值函数,该函数将以表的形式返回逗号分隔的值

为我发现的函数实现以下代码,只需稍加修改即可返回一个标识列,稍后将基于该列进行连接,以获取列a的第一个值和列B的第一个值的元组A1、Z1,依此类推,第二、第三个等:

CREATE FUNCTION Split (@InputString VARCHAR(8000), @Delimiter VARCHAR(50))

RETURNS @Items TABLE (ID INTEGER IDENTITY(1,1), Item VARCHAR(8000))

AS
BEGIN
      IF @Delimiter = ' '
      BEGIN
            SET @Delimiter = ','
            SET @InputString = REPLACE(@InputString, ' ', @Delimiter)
      END

      IF (@Delimiter IS NULL OR @Delimiter = '')
            SET @Delimiter = ','

--INSERT INTO @Items VALUES (@Delimiter) -- Diagnostic
--INSERT INTO @Items VALUES (@InputString) -- Diagnostic

      DECLARE @Item VARCHAR(8000)
      DECLARE @ItemList VARCHAR(8000)
      DECLARE @DelimIndex INT

      SET @ItemList = @InputString
      SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
      WHILE (@DelimIndex != 0)
      BEGIN
            SET @Item = SUBSTRING(@ItemList, 0, @DelimIndex)
            INSERT INTO @Items VALUES (@Item)

            -- Set @ItemList = @ItemList minus one less item
            SET @ItemList = SUBSTRING(@ItemList, @DelimIndex+1, LEN(@ItemList)-@DelimIndex)
            SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
      END -- End WHILE

      IF @Item IS NOT NULL -- At least one delimiter was encountered in @InputString
      BEGIN
            SET @Item = @ItemList
            INSERT INTO @Items VALUES (@Item)
      END

      -- No delimiters were encountered in @InputString, so just return @InputString
      ELSE INSERT INTO @Items VALUES (@InputString)

      RETURN

END -- End Function
GO

---- Set Permissions
--GRANT SELECT ON Split TO UserRole1
--GRANT SELECT ON Split TO UserRole2
--GO
现在,在创建此函数后,将存储过程修改为:

CREATE PROCEDURE m1_test @stringCola VARCHAR(max), @stringColb VARCHAR(max)
AS
INSERT INTO m1
SELECT A.Item, B.Item
FROM Split(@stringColA, ',') A
    INNER JOIN Split(@stringColB, ',') B ON A.ID = B.ID
GO

正如我在评论中所说,这是一个糟糕的设计,但你可以这样做:

INSERT INTO m1 values
SELECT  a.d ,
        b.d
FROM (SELECT Split.a.value('.', 'VARCHAR(100)') d ,
             ROW_NUMBER() OVER ( ORDER BY ( SELECT   NULL ) ) rn
      FROM (SELECT CAST('<M>' + REPLACE(@stringCola, ',', '</M><M>') + '</M>' AS XML) d) A
      CROSS APPLY d.nodes('/M') AS Split ( a )
     ) a
JOIN 
     (SELECT Split.a.value('.', 'VARCHAR(100)') d ,
             ROW_NUMBER() OVER ( ORDER BY ( SELECT NULL ) ) rn
      FROM (SELECT CAST('<M>' + REPLACE(@stringColb, ',', '</M><M>') + '</M>' AS XML) d ) A
      CROSS APPLY d.nodes('/M') AS Split ( a )
     ) b ON a.rn = b.rn

这是非常糟糕的设计。最好添加表值参数。如果我有更多的值要插入到多个列中呢?把5根弦变成5根columns@MAK如果运气不好,请更改存储过程的代码以容纳多个值,并使用多个联接生成结果集,该结果集稍后将插入m1。就像我在上面的例子中所做的。。扩展它以容纳您想要的任意多个值。但是正如@GiorgiNakeuri所说的,这是一个糟糕的设计,无法扩展。好吧!我承认这是一个糟糕的设计。如果我给出两个字符串,比如:@stringCola='A1,A2'和@StringColb='B1',并且它必须像这样存储:Cola=A1,A2和Colb=B1,NullYes,只需将JOIN替换为FULL JOINYup!完成。非常感谢你。