SQL Server 2008有时会以错误的顺序出现

时间:2013-09-02 15:20:55

标签: sql-server sql-server-2008

我有一个奇怪的问题,偶尔只会发生。我已经运行了10000次,在不同的时间得到了2个错误,12个错误和没有错误。

这是我的测试脚本,它会尝试10000次并输出错误的

declare @i int
set @i = 10000

declare @v varchar(200)

while @i > 0
begin
    SELECT top 1 @v = val
    FROM f_split_string('a,b,c,d,e,f',',')
   if @v != 'a'
       print @v
   set @i = @i - 1
end

这是f_split_string函数:

CREATE FUNCTION [dbo].[f_split_string] (@s nvarchar(max), @delim nvarchar(10))
-- returns a table from a delimited string
-- Parameters:
--    @s                The delimited string
--    @delim            The delimiter characters
-- Example:
--    SELECT val FROM f_split_string('a b c',' ')
RETURNS @t TABLE (id int, val nvarchar(max))
AS
BEGIN
      DECLARE @c int, @v nvarchar(max)
      SET @c = 1
      SET @v = dbo.f_element(@s, @delim, @c)
      WHILE @v IS NOT NULL
      BEGIN
            INSERT INTO @t (id,val) VALUES (@c,@v)
            SET @c = @c + 1
            SET @v = dbo.f_element(@s, @delim, @c)
      END

      RETURN
END

这是f_element函数:

CREATE FUNCTION [dbo].[f_element](@Input varchar(max), @Delimiter varchar(10), @ElementNumber int)
-- returns an element from a delimited string
-- Example:
--   SELECT dbo.f_element('abc|def|ghij', '|', 2)
--     will return the 2nd element - def
RETURNS varchar(max)
AS
BEGIN
      DECLARE @Pointer INT, @Count INT, @Last INT, @retVal varchar(max)
      SET @Pointer = 1
      SET @Count = 1
      SET @Last = 1

      WHILE (@Count < @ElementNumber)
      BEGIN
            SET @Pointer = CHARINDEX(@Delimiter,@Input,@Pointer)
            IF @Pointer = 0
                  BREAK

            SET @Pointer = @Pointer + DATALENGTH(@Delimiter)
            SET @Count = @Count + 1
      END

      IF @Pointer = 0 OR @ElementNumber < 1
            SET @retVal = null;
      ELSE IF SUBSTRING(@Input,@Pointer,DATALENGTH(@Delimiter)) = @Delimiter
            SET @retVal = '';
      ELSE
      BEGIN
            SET @Last = @Pointer

            SET @Pointer = CHARINDEX(@Delimiter,@Input,@Last+1)

            IF @Pointer = 0
                  SET @retVal = SUBSTRING(@Input, @Last, 9999)
            ELSE
                  SET @retVal = SUBSTRING(@Input, @Last, @Pointer - @Last)
      END

      RETURN @retVal
END

这是在SQL Server 2008(而不是R2)

上进行测试的

首先,任何其他人都可以通过我的测试脚本获得错误,其次,为什么会发生这种情况?

我已经运行了f_element函数200000次没有问题,所以怀疑f_split_string函数,但是从f_split_string调用它可能是f_element函数

我在单个用户SQL Server 2008 R2上运行它没有任何问题,2008有多个用户

任何人都可以帮助我

错误是分隔字符串的错误部分。它应该是a,但有时它是其他部分。就像行以错误的顺序插入临时表一样。我将id列添加到临时表中,因此我可以对输出进行排序,但它没有任何区别。

2 个答案:

答案 0 :(得分:2)

如果您没有放置显式的ORDER BY语句,则SQL不保证您的订购。

即便是一个像你一样简单的例子 - 你希望内部应该像你想要的那样运作 - 表明事实并非如此。

解决方案:如果订单很重要,请添加ORDER BY。我知道你没有什么可以排序,所以也许修改你的拆分功能,以便它吐出两列:值和索引;然后,您可以对索引进行排序。

答案 1 :(得分:0)

除了我之前的回答,也许我可以指出另一种选择。

如果在您的数据库中使用CLR过程是一个选项,那么这是一种CLR代码比T-SQL更高性能的工作。另外,因为CLR函数被SQL Server视为不透明的枚举器,所以可能依赖于SELECT * FROM dbo.clr_func()clr_func枚举器的顺序相同,尽管我猜你不应该试图推动你的运气并使查询变得更复杂。

因为我没有看到这么简单的SELECT的重点,所以你可能不得不转向ORDER BY来进行更严肃的业务。

如果您对此选项感兴趣,可以查看本文的使用CLR 部分: http://www.codeproject.com/Articles/17802/Use-Table-Valued-Functions-as-Arrays-in-SQL-Server