Как использовать Order By в хранимой процедуре без использования динамического SQL

#sql-server #tsql #sql-order-by #dynamic-sql

#sql-сервер #tsql #sql-order-by #dynamic-sql

Вопрос:

У меня есть следующая хранимая процедура MS SQL. Мне нужно отсортировать результаты без использования динамического SQL и sp_executesql метода

@Order by может иметь возможные значения ProductName ASC , ProductName DESC , ProductCode ASC VendorName DESC , VendorCode ,,, или ClientName

Я пытался использовать ORDER BY CASE , есть ли какая-либо проблема, если ProductName , ProductCode имеют разный тип?

 ALTER PROCEDURE [dbo].[SortedReport]
(
    @ClientID INT,
    @RecordLimit,
    @FromDate DATETIME,
    @ToDate DATETIME,
    @OrderBy NVARCHAR(MAX)
)

AS
BEGIN

IF (@OrderBy IS NULL) BEGIN
    SET @OrderBy = 'ProductName';
END    

SELECT TOP (@RecordLimit) 
        sv.ClientID,
        sv.VendorID,
        sv.ProductID,
        sv.TransactionTime,
        sv.ClientName,
        sv.VendorName,
        sv.ProductName,
        sv.ProductCode,
        sv.VendorCode,
FROM SortedReportiew AS sv 
WHERE (sv.ClientID = @ClientID)
    AND (sv.TransactionTime >= @FromDate)
    AND (sv.TransactionTime < @Date)
  

Обновить:

Правильна ли приведенная ниже часть? ссылка из здесь

 ORDER BY 
    CASE @OrderBy WHEN 'ProductCode ASC' THEN ProductCode WHEN 'ProductCode DESC' THEN ProductCode END DESC,
    CASE @OrderBy WHEN 'ProductName ASC' THEN ProductName WHEN 'ProductName DESC' THEN ProductName END DESC,
  

Комментарии:

1. Почему не динамический SQL? Это намного быстрее, чем любое из статических решений для такого рода задач.

2. Почему вы хотите избежать динамического SQL для выполнения динамической инструкции?

3. @RBarryYoung, @Markus Winand, просто потому, что клиент хочет преобразовать эти динамические SQL в статические

4. Итак, спросите клиента, зачем это делать 😉 Существует » миф о том, что динамический SQL работает медленно «, который часто приводит к подобным запросам. Однако правильно выполненный dynamic-sql (с использованием параметров привязки), как правило, лучше.

5. @RBarryYoung: избавление от динамического sql для «order by» приводит к повышению производительности в этих запросах order by.

Ответ №1:

Как вы уже сказали: используйте ORDER BY CASE , но несколько раз, чтобы избежать проблем с разными типами столбцов:

 ...
ORDER BY 
 CASE WHEN @OrderBy ='ProductName ASC' THEN sv.ProductName END,
 CASE WHEN @OrderBy ='ProductName DESC' THEN sv.ProductName END DESC,
 CASE WHEN @OrderBy ='ProductCode ASC' THEN sv.ProductCode END,
 CASE WHEN @OrderBy ='ProductCode DESC' THEN sv.ProductCode END DESC,
 CASE WHEN @OrderBy ='VendorName ASC' THEN sv.VendorName END,
 CASE WHEN @OrderBy ='VendorName DESC' THEN sv.VendorName END DESC,
 CASE WHEN @OrderBy ='VendorCode' THEN sv.VendorCode END,
 CASE WHEN @OrderBy ='ClientName' THEN sv.ClientName END
  

Редактировать:

Обновил запрос, чтобы соответствовать вашему обновленному вопросу. Я полагаю, вы имели в виду ProductCode ASC и ProductCode DESC ?

Комментарии:

1. Пожалуйста, смотрите обновленный вопрос, @OrderBy также содержит направление сортировки, подобное ProductName ASC

2. ASC / DESC является необязательным, поскольку ASC используется по умолчанию: msdn.microsoft.com/en-us/library/ms188385.aspx

Ответ №2:

Я понимаю, порядок использует только один столбец. В этом случае я мог бы попробовать что-то вроде этого:

  1. Разделить @OrderBy на @OrderByCol и @OrderByDir .

  2. Используйте этот шаблон:

     ...
    ORDER BY
      CASE @OrderByDir WHEN 'ASC' THEN
        CASE @OrderByCol
          WHEN 'Column1' THEN Column1
          WHEN 'Column2' THEN Column2
          ...
        END
      END ASC,
    
      CASE @OrderByDir WHEN 'DESC' THEN
        CASE @OrderByCol
          WHEN 'Column1' THEN Column1
          WHEN 'Column2' THEN Column2
          ...
        END
      END DESC
      

    Или, если вы используете SQL Server 2005 , возможно, этот, в качестве альтернативы:

     WITH sorted AS (
      SELECT
         ... /* columns, omitted */
         Column1Order = ROW_NUMBER() OVER (ORDER BY Column1),
         Column2Order = ROW_NUMBER() OVER (ORDER BY Column2),
         ...
      FROM ...
    )
    SELECT ...
    FROM sorted
    ORDER BY
      CASE @OrderByCol
        WHEN 'Column1' THEN Column1Order
        WHEN 'Column2' THEN Column2Order
        ...
      END * CASE @OrderByDir WHEN 'DESC' THEN -1 ELSE 1 END
      

Как @Greg Ogle правильно указал в комментарии, первый шаблон может работать только тогда, когда различные критерии сортировки имеют совместимые типы, в противном случае инструкция будет прервана.

Комментарии:

1. Обратите внимание, что ORDER BY должны быть одного и того же типа данных для каждого СЛУЧАЯ, иначе будет выдана ошибка преобразования.

2. Спасибо, я добавил примечание к своему ответу (не знаю, почему я не смог этого сделать, когда отправлял ответ).