2010-06-15 34 views
2

我有以下存儲過程可以在TemplateName,CreatedOn和UploadedBy上升序和降序排序。以下SP運行時不會對記錄進行排序。如果我通過列名替換2,3,4,我得到一條錯誤消息「將nvarchar值'Test Template'轉換爲數據類型int時轉換失敗。」。請建議如何實現排序。動態順序通過不使用動態SQL?

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 

回答

0

我們在其中一個產品中執行類似的動態排序。 唯一不同於您的代碼的是,首先,我們不使用實時連接。 我們創建一個臨時表,所以我們可以執行分頁,然後應用訂單。 我們也使用ints進行排序,減少了字符串比較的開銷。

它確實讓你的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 
+0

Russ C - 這看起來不是一個非常有效的技術。 – ScottE 2010-06-15 12:17:07

+0

通過查詢分析器運行它,它高效且易於調試。 它也回答了你在下面提供的相同細節,並且我沒有將日期作爲整數。 – 2010-06-15 13:22:57

+0

與內聯排序情況相比,創建臨時表並有條件地返回其中的某些部分是有效的嗎?我對此表示懷疑。我懷疑編譯器甚至可以得到一個好的查詢計劃。 – ScottE 2010-06-15 14:46:00

1

的動態排序必須是相同的數據類型下面是我使用的情況下,爲了三個不同數據類型的東西的例子。 - 整數,日期(升序和降序)和字符串,這可能對你的工作不起作用ituation,但至少你可以看到一些用於轉換爲通用數據類型的技術。

...

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

下面的SP運行時不列入 排序records.if我通過 列名代替2,3,4,

你不應該更換2,3,4 ORDER BY子句通過列名稱。當您調用該過程時,只需將要排序的列作爲第三個參數傳遞。

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

的情況下會再評估像

...ORDER BY 3 DESC 

查詢到一些東西,排序SELECT子句中(即CreatedOn)由第三列的查詢