代码之家  ›  专栏  ›  技术社区  ›  dotjoe

带有select和order by的tsql字符串concat不适用于order by子句中的函数?

  •  4
  • dotjoe  · 技术社区  · 16 年前

    考虑以下TSQL…

    create function dbo.wtfunc(@s varchar(50)) returns varchar(10) begin return left(@s, 2); end
    GO
    select t.* into #test from (
        select 'blah' as s union
        select 'foo' union
        select 'bar'
    ) t
    select * from #test;
    
    declare @s varchar(100); 
    set @s = '';
    
    select @s = @s + s from #test order by s;
    select @s;
    set @s = '';
    select @s = @s + s from #test order by dbo.wtfunc(s);
    select @s;
    /* 2005 only*/
    select cast((select s+'' from #test order by dbo.wtfunc(s) for xml path('')) as varchar(100))
    
    drop function dbo.wtfunc;
    drop table #test;
    

    我在MSSQL2000和2005上尝试过,在使用ORDERBY中的函数时,两者都不连接字符串。在2005年,for xml路径(“”)确实有效。输出是…

    bar
    blah
    foo
    
    barblahfoo
    
    foo --nothing concatenated?
    
    barblahfoo
    

    我找不到记录的地方。有人能解释一下为什么这个不起作用吗?

    编辑:

    这是实际的执行计划。显然,排序和计算标量的顺序不同…

    alt text http://i41.tinypic.com/2d6pht3.jpg alt text http://i41.tinypic.com/w2og48.png

    3 回复  |  直到 16 年前
        1
  •  5
  •   CAbbott    16 年前

    似乎这是一个 known issue with Aggregate Concatenation Queries .

    从链接:

    “ANSI SQL-92规范要求ORDER BY子句引用的任何列与结果集匹配,该结果集由选择列表中的列定义。当表达式应用于ORDER BY子句的成员时,该结果列不会在选择列表中公开,从而导致未定义的行为。”

        2
  •  3
  •   Joe    16 年前

    可以通过使用计算列来完成此操作,例如:

    DROP TABLE dbo.temp;
    
    CREATE TABLE dbo.temp
    (
      s varchar(20)
     ,t AS REVERSE(s)
    );
    INSERT INTO dbo.temp (s) VALUES ('foo');
    INSERT INTO dbo.temp (s) VALUES ('bar');
    INSERT INTO dbo.temp (s) VALUES ('baz');
    INSERT INTO dbo.temp (s) VALUES ('blah');
    GO
    
    -- Using the function directly doesn't work:
    DECLARE @s varchar(2000);
    SELECT s, REVERSE(s) FROM dbo.temp ORDER BY REVERSE(s);
    SET @s = '';
    SELECT @s = @s + s FROM dbo.temp ORDER BY REVERSE(s);
    SELECT @s;
    GO
    
    -- Hiding the function in a computed column works:
    DECLARE @s varchar(2000);
    SELECT s, t FROM dbo.temp ORDER BY t;
    SET @s = '';
    SELECT @s = @s + s FROM dbo.temp ORDER BY t;
    SELECT @s;
    GO
    
        3
  •  2
  •   Darth Continent    16 年前

    我不知道这是否有帮助,但当我尝试以下方法时:

    set @s = '          ';
    
    select @s = @s + s from #test order by dbo.wtfunc(s);
    select @s AS myTest
    

    我得到这个(注意在“foo”前面有空格,后面没有空格):

      foo
    

    我想这是个不起眼的小虫子吧?!