在汇总varchar时排序。不能按预期工作

时间:2012-03-30 07:42:51

标签: sql sql-server-2008 tsql sql-order-by concatenation

我不知道此问题是否曾被提出过。但是在查找varchars时遇到问题。

让我解释一下:

我有这张桌子:

CREATE TABLE Table1
(
    [Field] [varchar](10) NOT NULL
)
INSERT INTO Table1
VALUES('1'),('2'),('3'),('4'),('5'),('TITLE')

我喜欢输出是这样的:

'[TITLE],[1],[2],[3],[4],[5]'

我想要' TITLE'先订购然后1,2,3,4,5

因此,此查询将返回有序结果。我没有比'TITLE'

更长的数字
SELECT
    *
FROM
    Table1
ORDER BY
    LEN([Field]) DESC,
    [Field] ASC

然后我通常会像这样连接varchar:

DECLARE @cols VARCHAR(MAX)
SELECT  @cols = COALESCE(@cols + ','+QUOTENAME([Field]),
                     QUOTENAME([Field]))
FROM
    Table1
ORDER BY
    LEN([Field]) DESC,
    [Field] ASC

但这回归:

'[5]'

我觉得这很奇怪。有人可以解释一下原因吗?

我知道有一种替代varchar的替代解决方案。像这样:

DECLARE @cols VARCHAR(MAX)
SELECT @cols=STUFF
(
    (
        SELECT 
            ',' +QUOTENAME([Field])
        FROM
            Table1
        ORDER BY 
            LEN([Field]) DESC,
            [Field] ASC
        FOR XML PATH('')
    )
,1,1,'')

这将返回我的预期结果:

'[TITLE],[1],[2],[3],[4],[5]'

修改

建议@cols在开始时无效。因为如果我删除order by。像这样:

DECLARE @cols VARCHAR(MAX)
SELECT  @cols = COALESCE(@cols + ','+QUOTENAME([Field]),
                     QUOTENAME([Field]))
FROM
    Table1

我的结果将是这样的:

'[1],[2],[3],[4],[5],[TITLE]'

EDIT1

这不起作用:

DECLARE @cols VARCHAR(MAX)
SELECT  @cols = COALESCE(@cols + ','+QUOTENAME([Field]),
                     QUOTENAME([Field]))
FROM(
  SELECT [Field]
  FROM
      Table1
  ORDER BY
      LEN([Field]) DESC,
      [Field] ASC
) AS t

因为它会发出如下的异常消息:

  

Msg 1033,Level 15,State 1,Line 17 ORDER BY子句无效   视图,内联函数,派生表,子查询和公用表   表达式,除非还指定了TOP或FOR XML。

EDIT2

像我预期的那样。我不能这样做:

SELECT  @cols, @cols = COALESCE(@cols + ','+QUOTENAME([Field]),
                     QUOTENAME([Field]))
FROM
    Table1
ORDER BY
    LEN([Field]) DESC,
    [Field] ASC

因为这会引发这样的异常:

  

消息141,级别15,状态1,行9指定a的SELECT语句   变量的值不得与数据检索相结合   操作

2 个答案:

答案 0 :(得分:3)

我不确定,但我认为答案是在查询的执行顺序中。我尝试过以下代码:

DECLARE @x INT
SET @x = 0
SELECT  @x =@x + 1
FROM
   Table1
ORDER BY
  LEN(Field) DESC, Field ASC
SELECT @x

然后返回1,

DECLARE @x INT
SET @x = 0
SELECT  @x =@x + 1
FROM
   Table1
SELECT @x

返回6,这最多是奇数。

但是,从第一个查询的执行计划可以看出事件的顺序是:

Table Scan -> Compute Scalar -> Sort -> Select

所以我最好的猜测是首先计算结果,然后排序,最后得到一些中间值。

恕我直言,这是滥用SQL服务器执行引擎,基本上是未定义的行为。即使你设法让它在这个SQL服务器上工作,也不知道服务包是否会为你破解它。我会选择你所描述的第二种解决方案,它是直截了当的,更容易维护。


关于edit1:指定SELECT TOP 100 PERCENT负责“视图中没有排序”错误,但是,SQL服务器做了一些魔术,你仍然最终得到[1],[2],[3],[4],[5],[TITLE]

答案 1 :(得分:2)

您可以查看这篇文章PRB: Execution Plan and Results of Aggregate Concatenation Queries Depend Upon Expression Location

  

ANSI SQL-92规范要求引用的任何列   ORDER BY子句匹配由列定义的结果集   出现在SELECT列表中。将表达式应用于成员时   ORDER BY子句,结果列未公开   SELECT列表,导致未定义的行为。

在order by子句中使用表达式时,会得到不同的执行计划。

enter image description here

排序在Compute Scalar之后而不是之前应用。

将字符串与顺序连接的安全方法是使用for xml

相关问题