Динамический порядок без использования динамического SQL? - PullRequest
2 голосов
/ 15 июня 2010

У меня есть следующая хранимая процедура, которая может быть отсортирована по возрастанию и убыванию по TemplateName, CreatedOn и UploadedBy.Следующий SP при запуске не сортирует записи. Если я заменяю 2,3,4 на имя столбца, я получил сообщение об ошибке «Преобразование не удалось преобразовать значение nvarchar 'Test Template' в тип данных int.".

CREATE PROCEDURE [dbo].[usp_SEL_GetRenderingTemplate]
(
  @facilityID INT,
  @sortOrder VARCHAR(5),
  @sortExpression VARCHAR(100),
  @errorCode INT OUTPUT 
)
AS 
BEGIN       
    SET NOCOUNT ON ;
    BEGIN TRY   
        SET @sortOrder = CASE @sortOrder
                           WHEN 'Ascending' THEN 'ASC'
                           WHEN 'Descending' THEN 'DESC'
                           ELSE 'ASC'
                         END
        SELECT  TemplateID,
                TemplateName,
                CreatedOn,
                ( [user].LastName + ' ' + [user].FirstName ) AS UploadedBy
        FROM    Templates
                INNER JOIN [user] ON [user].UserID = Templates.CreatedBy
        WHERE   facilityid = @facilityID
        ORDER BY CASE WHEN @sortExpression = 'TemplateName'
                           AND @sortOrder = 'ASC' THEN 2
                      WHEN @sortExpression = 'CreatedOn'
                           AND @sortOrder = 'ASC' THEN 3
                      WHEN @sortExpression = 'UploadedBy'
                           AND @sortOrder = 'ASC' THEN 4
                 END ASC,
                CASE WHEN @sortExpression = 'TemplateName'
                          AND @sortOrder = 'DESC' THEN 2
                     WHEN @sortExpression = 'CreatedOn'
                          AND @sortOrder = 'DESC' THEN 3
                     WHEN @sortExpression = 'UploadedBy'
                          AND @sortOrder = 'DESC' THEN 4
                END DESC
        SET @errorCode = 0


    END TRY
    BEGIN CATCH
        SET @errorCode = -1                            
        DECLARE @errorMsg AS VARCHAR(MAX)  
        DECLARE @utcDate AS DATETIME   
        SET @errorMsg = CAST(ERROR_MESSAGE() AS VARCHAR(MAX))  
        SET @utcDate = CAST(GETUTCDATE() AS DATETIME)  
        EXEC usp_INS_LogException 'usp_SEL_GetFacilityWorkTypeList',
            @errorMsg, @utcDate  
    END CATCH 


END

Ответы [ 4 ]

1 голос
/ 15 июня 2010

Динамическое упорядочение должно быть одного типа.Вот пример того, что я использую, чтобы упорядочить три разных типа данных - целое число, дату (возрастание и убывание) и строку.Это может не работать в вашей ситуации, но, по крайней мере, вы можете увидеть некоторые приемы приведения к общему типу данных.

...

ORDER BY
    Case Parent.RankTypeID
      When 0 Then dbo.Documents.Rank
      When 1 Then Convert(int, dbo.Documents.DateStart, 112)
      When 2 Then (1 - Convert(int, dbo.Documents.DateStart, 112))
      When 3 Then Cast(dbo.Documents.Title as sql_variant)
    End

Примечание:

112 - формат даты ГГГГММДД - полезно для заказа.

0 голосов
/ 20 апреля 2011

Проблема в том, что в предложениях CASE возвращаемые значения должны иметь одинаковый тип данных.

Вы можете обойти эту проблему, используя несколько операторов CASE http://www.extremeexperts.com/sql/articles/CASEinORDER.aspx

Или приведение всего ктот же тип данных.

0 голосов
/ 15 июня 2010

Следующий SP при запуске не сортирует записи. Если я заменяю 2,3,4 именем столбца,

Вы не должны заменять 2, 3, 4 в предложении ORDER BYпо имени столбца.Когда вы вызываете процедуру, просто передайте столбец, по которому вы хотите отсортировать, как третий параметр.

EXEC [dbo].[usp_SEL_GetRenderingTemplate] 1,'Ascending','CreatedOn',@vErrorCode

Затем CASE оценивает запрос как что-то вроде

...ORDER BY 3 DESC

, что сортирует запрос по 3-му столбцу в предложении SELECT (т.е. CreatedOn)

0 голосов
/ 15 июня 2010

Мы выполняем подобный вид динамического заказа в одном из наших продуктов. Единственное, что реально отличается от вашего кода, во-первых, мы не используем live join. Мы создаем временную таблицу, чтобы мы могли выполнить разбиение на страницы, а затем применить порядок. Мы также используем целочисленные значения для упорядочения, сокращая накладные расходы при сравнении строк.

Это делает ваш SQL немного длиннее, но этот подход определенно быстрее для оптимизатора запросов. Кроме того, и что еще более важно, я не думаю, что вы можете смешивать типы в блоках Switch для упорядочения, поэтому, следуя исходному коду, вам придется конвертировать все ваши данные в одно и то же время, что побеждает объект: (

Так что у вас будет

DECLARE @temp TABLE(ID int identity(1,1), TemplateID int, TemplateName nvarchar(100), CreatedOn datetime, UploadedBy nvarchar(100))
INSERT INTO @temp(TemplateID, TemplateName, CreatedOn, UploadedBy)
SELECT TemplateID,
       TemplateName,
       CreatedOn,
       ( [user].LastName + ' ' + [user].FirstName ) AS UploadedBy
FROM Templates
  INNER JOIN [user] ON [user].UserID = Templates.CreatedBy
WHERE   facilityid = @facilityID

Тогда:

IF @SortOrder = 1 --'ASC'
  BEGIN
     IF @sort = 2
       Select *
       From @Temp
       Order by TemplateName ASC
     ELSE IF @sort = 3
       Select *
       From @Temp
       Order By CreatedBy ASC
     -- and so on...
  END

ELSE -- descending
  BEGIN
    -- Ad. Inf.
  END

Delete
  From @Temp
  WHERE ID < @pageStart or ID > @pageStart + @pageSize
...