Порядок при конкатрировании varchar. Не работает, как ожидалось - PullRequest
2 голосов
/ 30 марта 2012

Я не знаю, задавался ли этот вопрос раньше. Но у меня есть проблема при конкатарировании 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

Тогда я обычно кончарую вархар так:

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]'

EDIT

Предположение, что @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

Потому что он выдаст сообщение об исключении, подобное этому:

Сообщение 1033, уровень 15, состояние 1, строка 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 Оператор SELECT, который назначает значение переменной не должно сочетаться с извлечением данных операции.

Ответы [ 2 ]

3 голосов
/ 30 марта 2012

Я не уверен, но я думаю, что ответ находится в порядке выполнения запроса.Я пробовал следующий код:

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, невозможно сказать, сломает ли его пакет обновления для вас.Я хотел бы перейти ко второму решению, которое вы описали, и оно простое и простое в обслуживании.


Об редактировании1: указание SELECT TOP 100 PERCENT позаботится об ошибке "no ordering in views", однакоSQL-сервер творит чудеса, и вы все равно получаете [1],[2],[3],[4],[5],[TITLE]

2 голосов
/ 30 марта 2012

Вы можете взглянуть на эту статью. PRB: план выполнения и результаты запросов совокупной конкатенации зависят от местоположения выражения

Для спецификации ANSI SQL-92 требуется, чтобы любой столбецссылка на предложение ORDER BY соответствует результирующему набору, определенному столбцами, присутствующими в списке SELECT.Когда выражение применяется к члену предложения ORDER BY, этот результирующий столбец не отображается в списке SELECT, что приводит к неопределенному поведению.

При использовании выражений в выражении вы получаете другой план выполненияпорядок по предложению.

enter image description here

Сортировка применяется после вычисления скаляра, а не до.

Безопасный способ объединения строк с заказом по заключается в использованииfor xml.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...