2016-08-15 26 views
0

這是我的存儲過程來搜索用戶上傳圖片的畫廊:動態ORDER BY在存儲過程中不能按預期工作

ALTER PROCEDURE dbo.sp_SearchGallery 
(
@strSearchTerm NVARCHAR(50) = NULL, 
@strCategory NVARCHAR(50) = NULL, 
@nUserId INT = NULL, 
@nSortBy INT = 0, 
@nSortDesc BIT = 0, 
@nPage INT = 1, 
@nPageSize INT = 10 
) AS 

SET NOCOUNT ON 

DECLARE @nSortSwitch INT = 1 
IF @nSortDesc = 1 BEGIN 
    SET @nSortSwitch = -1 
END 

DECLARE @FirstRec INT = (@nPage - 1) * @nPageSize 
DECLARE @LastRec INT = (@nPage * @nPageSize + 1) 

; WITH rowQueryResults AS 
(
    SELECT *, ROW_NUMBER() OVER 
    (
     ORDER BY 
      CASE @nSortBy 
       WHEN 0 THEN Date 
       WHEN 1 THEN Title 
       WHEN 2 THEN Description 
       WHEN 3 THEN ID 
      END 
    ) AS RowNum 
    FROM dbo.GalleryItems 
    WHERE ((@strSearchTerm IS NULL OR Title LIKE '%' + @strSearchTerm + '%') OR 
      (@strSearchTerm IS NULL OR Description LIKE '%' + @strSearchTerm + '%')) AND 
      (@nUserId IS NULL OR UserId = @nUserId) AND 
      (@strCategory IS NULL OR Category LIKE '%' + @strCategory + '%') AND 
      (Accepted=1) 
) 
SELECT * 
FROM rowQueryResults 
WHERE RowNum > @FirstRec AND RowNum < @LastRec 
ORDER BY RowNum*@nSortSwitch 

RETURN 

我可以設置@nSortBy爲0,這工作正常。我可以將其設置爲3,這也正常,但只要我把它設置爲1或2,其不同之處崩潰Conversion failed when converting date and/or time from character string.

什麼我假設是它試圖將TitleDescription轉換爲DateTime訂購。 ID之所以能夠工作,是因爲它是一個Integer,因此可以安全地轉換爲DateTime(顯然,這不是我想要它做的)

但是,它爲什麼要這麼做呢?我如何做到這一點,所以它做了一個strcmp而不是一個時間比較訂購?

+2

「爲什麼會這樣做? - 因爲'CASE'是*表達式*。它產生一個值。因此它有一個數據類型。給定THEN條款中的所有表達式,它會考慮所有數據類型,應用適當的優先規則並確定表達式的整體類型。請記住,*一般情況下*不能保證'CASE'表達式只會爲*所有行*輸入一個單獨的THEN'子句(例如,它被定義爲用於多於常量表達式) –

+2

另外,注意 - ['CREATE PROCEDURE'](https://msdn.microsoft.com/zh-CN/library/ms187926.aspx) - 「避免在命名過程中使用** sp _ **前綴。此前綴由SQL使用服務器來指定系統過程。「 –

+0

@Damien_The_Unbeliever - 謝謝你的回答。我現在完全明白了。我會改名字:) – Andy

回答

3

這與數據優先級有關,當您遇到不同數據類型之間的情況時,SQL會將較低數據類型轉換爲最高數據類型。試試這樣你的最高數據類型變成varchar,所以它不會嘗試將標題和描述轉換爲日期時間。

ORDER BY 
     CASE @nSortBy 
      WHEN 0 THEN convert(varchar, Date) 
      WHEN 1 THEN Title 
      WHEN 2 THEN Description 
      WHEN 3 THEN convert(varchar, ID) 
     END 

https://msdn.microsoft.com/en-us/library/ms190309.aspx

+0

謝謝!那讓我瘋狂。我現在知道它是如何工作的。我很感激你花時間幫助我。 – Andy

3

有不需要轉換一個簡單的選擇:

ORDER BY 
     CASE WHEN @nSortBy = 0 THEN Date END, 
     CASE WHEN @nSortBy = 1 THEN Title END, 
     CASE WHEN @nSortBy = 2 THEN Description END, 
     CASE WHEN @nSortBy = 3 THEN ID END 

該作品以一個奇怪的小動作。理論上它是按排名順序在四個字段上進行ORDER BY。實際上,儘管@nSortBy只能有一個值,所以實際上只有四個排序中的一個被執行。 「爲什麼會那樣做?」

+0

太棒了!這也很乾淨/容易理解。謝謝,喬納森。 – Andy

+0

@Sonic我的榮幸。很開心你喜歡。 – 2016-08-15 16:29:47