Условный порядок сортировки в предложениях оконных функций SQL Server - PullRequest
6 голосов
/ 26 августа 2011

Итак, это не обычный вопрос «условной сортировки» ... У меня тут довольно сложная проблема.:-) Я хочу разрешить моей хранимой процедуре предлагать условный порядок сортировки результатов.Обычно это можно сделать следующим образом:

SELECT *
INTO #ResultsBeforeSubset
FROM
    MyTable
ORDER BY
    CASE WHEN @SortAscending=1 THEN 'SortColumn' END ASC,
    CASE WHEN @SortAscending=0 THEN 'SortColumn' END DESC

Я хотел бы сделать оператор CASE вокруг фактического ASC / DESC, но это не работает.Причина, по которой работает вышеуказанный метод, заключается в том, что, когда @SortAscending не равно заданному значению, SQL-сервер преобразует оператор CASE в константу NULL.Итак, если @SortAscending равно 0, вы фактически получаете:

ORDER BY
    NULL ASC,
    SortColumn DESC

Первое выражение сортировки просто ничего не делает.Это работает, потому что в обычном операторе SELECT вы можете использовать константу в предложении ORDER BY.

Проблема в том, что время, которое я сортирую в моем сохраненном процессе, находится во время оператора SELECT, который содержитоконная функция ROW_NUMBER().Поэтому я хочу поместить оператор CASE в его предложение OVER, например, так:

SELECT *
INTO #ResultsBeforeSubset
FROM (
    SELECT
        ROW_NUMBER() OVER (
            ORDER BY
                CASE WHEN @SortAscending=1 THEN rowValues.[SortColumn] END ASC,
                CASE WHEN @SortAscending=0 THEN rowValues.[SortColumn] END DESC
        ) AS RowNumber,
        *
    FROM (
        -- UNIONed SELECTs returning rows go here...
    ) rowValues
) rowValuesWithRowNum

К сожалению, это вызывает следующую ошибку при запуске хранимой процедуры:

Windowed functions do not support constants as ORDER BY clause expressions.

Поскольку это условие оконной функции, преобразование оператора CASE в константу NULL недопустимо.

Может кто-нибудь придумать способ, которым я могу условно изменить порядок сортировкиUNION ed SELECT s, и назначить номера строк каждой строке, полученной в результате этих отсортированных результатов?Я знаю, что могу прибегнуть к построению всего запроса в виде строки и выполнить его как полностью динамический SQL, но я бы предпочел этого избежать, если это возможно.


ОБНОВЛЕНИЕ: Похожепроблема была не в операторе CASE per se , а в том, что я использовал только постоянные значения в условном предложении оператора CASE.Я задал новый вопрос об этом любопытном поведении здесь .

Ответы [ 6 ]

3 голосов
/ 19 июля 2012

Вы можете использовать константы, если заключите их в SELECT, например:

OVER( ORDER BY (SELECT NULL) )

Так что в вашем случае вы сможете сделать:

SELECT
    ROW_NUMBER() OVER (
        ORDER BY
            (SELECT CASE WHEN @SortAscending=1 THEN rowValues.[SortColumn] END) ASC,
            (SELECT CASE WHEN @SortAscending=0 THEN rowValues.[SortColumn] END) DESC
    ) AS RowNumber, 
1 голос
/ 26 августа 2011

Если вы собираетесь использовать эти номера строк как часть какой-то другой условной логики, возможно, что-то вроде этого будет работать:

CASE WHEN @SortAscending=1 THEN COUNT(*) OVER() + 1 ELSE 0 END +
(CASE WHEN @SortAscending=1 THEN -1 ELSE 1 END *
    ROW_NUMBER() OVER (ORDER BY SortColumn DESC)) as RowNumber

Это может быть даже расширено, так что если вы используете PARTITION, он продолжает работать до тех пор, пока оба выражения OVER() используют одни и те же предложения PARTITION.

1 голос
/ 26 августа 2011

Вы могли бы

  • добавить в промежуточные результаты столбцы Ascending и Descending
  • сортировка по одному из тех, что в конце.

Оператор SQL

SELECT  *
INTO    #ResultsBeforeSubset
FROM    (
          SELECT  ROW_NUMBER() OVER (ORDER BY rowValues.[SortColumn] ASC) AS AscSortColumn
                  , ROW_NUMBER() OVER (ORDER BY rowValues.[SortColumn] DESC) AS DescSortColumn
                  , *
          FROM    (-- UNIONed SELECTs returning rows go here...
                  ) rowValues
        ) rowValuesWithRowNum
ORDER BY
        CASE  WHEN @SortAscending = 1 
              THEN rowValues.[AscSortColumn] 
              ELSE rowValues.[DescSortColumn] 
        END 
1 голос
/ 26 августа 2011

Вы можете назначить номера строк в двух направлениях и выбрать один во внешнем order by:

select  *
from    (
        select  row_number() over (order by SortColumn) rn1
        ,       row_number() over (order by SortColumn) rn2
        ,       *
        from    @t
        ) as SubQueryAlias
order by
        case when @asc=1 then rn1 end
,       case when @asc=0 then rn2 end desc

Рабочий пример на Данные SE .

0 голосов
/ 30 декабря 2016

Вы можете использовать функцию управления окнами в order by, а не только в выборе. Оконные функции row_number, rank, density_rank все возвращают число (bigint), которое можно умножить на отрицательное значение, чтобы получить обратное ...

SELECT *
INTO #ResultsBeforeSubset
FROM MyTable
ORDER BY
  (rank() over (order by SortColumn)) * case when @asc=1 then 1 else -1 end 
0 голосов
/ 26 августа 2011
DECLARE @sign int = -1;
IF @SortAscending = 0 SET @sign = -1;

SELECT ROW_NUMBER() OVER (ORDER BY RowNumber) AS RN,
    *
INTO #ResultsBeforeSubset
FROM (
    SELECT
        @sign * ROW_NUMBER() OVER (ORDER BY rowValues.[SortColumn]) AS RowNumber,
        *
    FROM MyTable
) rowValuesWithRowNum
ORDER BY RN

--DECLARE @sign int = 1;
--IF @SortAscending = 0 SET @sign = -1;
--
--SELECT *
--INTO #ResultsBeforeSubset
--FROM (
--    SELECT
--        @sign * ROW_NUMBER() OVER (ORDER BY rowValues.[SortColumn] AS RowNumber,
--        *
--    FROM MyTable
--) rowValuesWithRowNum
--ORDER BY RowNumber;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...