Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 为什么拆分逗号分隔字符串的XML方法比传统的游标或WHILE循环方法花费更多的时间_Sql_Sql Server 2008_Sql Server 2008 R2_Sql Server 2012_Sqlxml - Fatal编程技术网

Sql 为什么拆分逗号分隔字符串的XML方法比传统的游标或WHILE循环方法花费更多的时间

Sql 为什么拆分逗号分隔字符串的XML方法比传统的游标或WHILE循环方法花费更多的时间,sql,sql-server-2008,sql-server-2008-r2,sql-server-2012,sqlxml,Sql,Sql Server 2008,Sql Server 2008 R2,Sql Server 2012,Sqlxml,我有一个表,有4列,其中一列是一个字符串,值用逗号分隔。我使用了两种方法以表格的形式拆分和扩展该列表: I方法>使用XML: declare @tbl TABLE ( id1 int, id2 int, id3 int, str1 varchar(255) ) INSERT INTO @tbl SELECT p.n.value('@id1','INT'), p.n.value('@releaseId','INT'), p.n.va

我有一个表,有4列,其中一列是一个字符串,值用逗号分隔。我使用了两种方法以表格的形式拆分和扩展该列表:

I方法>使用XML:

declare @tbl TABLE (
    id1 int,
    id2 int,
    id3     int,
    str1        varchar(255)
    )

INSERT  INTO @tbl
SELECT p.n.value('@id1','INT'), p.n.value('@releaseId','INT'), p.n.value('@id3','INT'), '', p.n.value('.','nvarchar(150)')
FROM (SELECT CAST(('<r id1="'+CAST(id1 AS varchar(20))+'" id2="'+CAST(id2 AS varchar(20))+'" id3="'+CAST(id3 AS varchar(20))+'">'+REPLACE(CAST(str1 AS nvarchar(MAX)), ',', '</r><r id1="'+CAST(id1 AS varchar(20))+'" id2="'+CAST(id2 AS varchar(20))+'" id3="'+CAST(id3 AS varchar(20))+'">')+'</r>') AS XML) AS x 
    FROM SomeTable WITH(NOLOCK) WHERE CAST(str1 AS nvarchar(MAX)) <> '') R
CROSS APPLY R.x.nodes('/r') p(n)

select * from @tbl
II进近>使用光标和WHILE循环方法

    CREATE FUNCTION dbo.fnSplit(
        @sInputList VARCHAR(MAX) -- List of delimited items
      , @sDelimiter VARCHAR(8000) = ',' -- delimiter that separates items
    ) RETURNS @List TABLE (item VARCHAR(100))

    BEGIN
    DECLARE @sItem VARCHAR(8000)
    WHILE CHARINDEX(@sDelimiter,@sInputList,0) <> 0
     BEGIN
     SELECT
      @sItem=RTRIM(LTRIM(SUBSTRING(@sInputList,1,CHARINDEX(@sDelimiter,@sInputList,0)-1))),
      @sInputList=RTRIM(LTRIM(SUBSTRING(@sInputList,CHARINDEX(@sDelimiter,@sInputList,0)+LEN(@sDelimiter),LEN(@sInputList))))

     IF LEN(@sItem) > 0
      INSERT INTO @List SELECT @sItem
     END

    IF LEN(@sInputList) > 0
     INSERT INTO @List SELECT @sInputList -- Put the last item in
    RETURN
    END
    GO

-------------------------------------------
    DECLARE @id1    INT
    DECLARE @id2        INT
    DECLARE @id3        INT
    DECLARE @str1   nvarchar(MAX)

    declare @tbl TABLE (
            id1 int,
            id2 int,
            id3     int,
            str1        varchar(255)
            )

    DECLARE getList CURSOR FOR
    SELECT  Id1, Id2, Id3, str1
    FROM    someTable
    OPEN getaddUpdList
    FETCH NEXT FROM getList INTO @id1, @id2, @id3, @str1
    WHILE @@FETCH_STATUS = 0
    BEGIN
        INSERT  INTO @tbl
        SELECT  @id1, @id2, @id3, '', _ID
        FROM    fnSplit(@str1, ',')
        FETCH NEXT FROM getList INTO @id1, @id2, @id3, @sp, @str1
    END
    CLOSE getList
    DEALLOCATE getList

    select * from @tbl
正如我在网上读到的,任何地方都应该避免使用游标或WHILE循环。但在本例中,当我尝试上述两种方法时,I方法大约需要15-20秒,而II方法不到一秒。我不明白为什么会这样。我在SQLServer2008和2012上都尝试过,但结果是一样的


如果您能帮助理解这种不稳定的行为,我们将不胜感激。

这个问题很久以前就提出了,但也许您会再次提出。简单的一点是,您误解了通过XML拆分字符串的方法。看看这个例子:

declare @tbl TABLE (
    id1 int,
    id2 int,
    id3     int,
    str1        varchar(255)
    )

INSERT  INTO @tbl VALUES
 (1,2,3,'This,is,text,1')
,(10,20,30,'This,is,text,2')
,(100,200,300,'This,is,text,3')
,(1000,2000,3000,'This,is,text,4');


WITH Casted AS
(
    SELECT id1 
          ,id2
          ,id3
          ,CAST('<x>' + REPLACE(str1,',','</x><x>') + '</x>' AS XML) AS AsXml
    FROM @tbl
)
SELECT id1,id2,id3
      ,The.Node.value('.','varchar(max)') AS splitvalue 
FROM Casted
CROSS APPLY Casted.AsXml.nodes('/x') AS The(Node)
诀窍是,用结束和开始标记替换delimiter字符。开头的start标记和结尾的end标记允许字符串是部分XML。交叉应用程序调用nodes函数。value函数拾取当前节点的值,在本例中为唯一节点