2010-11-10 89 views
2

我有以下的存儲過程,而不是寫完整的存儲過程,但有的卻是:INT數據庫字段被如何比VARCHAR類型

@course int = null, 
    SET @query = @query + 'Where course_id='+ cast(@course as varchar) 

我想知道什麼時候我已經轉換了@course爲VARCHAR類型,而我的數據庫中的course_id是INT類型 - 如何進行比較?

回答

6

在SQL Server中兩個不同類型之間的比較發生這樣的:

與數據類型:

  • 首先這兩個類型的優先級是基於Data Type Precedence規則相比,較低優先級轉換爲具有較高優先級的數據類型

  • 接下來的類型具有較低優先級澆鑄到該類型的具有較高優先級

  • 比較,然後該類型的原始值之間進行具有較高的優先級和所述類型的具有較低優先級
  • 轉換後的值有關的緣故討論:INT(優先級16,高)和VARCHAR(優先級27,低)將通過將VARCHAR轉換爲INT然後比較這兩者進行比較。

    在你的情況下,雖然沒有發生轉換,但會發生什麼,@course值會附加到動態構建的@sql。不用說,那很糟糕。正確的做法是傳遞下來@course作爲參數傳遞給dymnamic SQL調用:

    @course INT = null 
    ... 
    SET @query = @query + 'Where course_id= @course'; 
    ... 
    exec sp_executesql @sql, '@course int', @course; 
    

    這就是:

    • 更快:參數化查詢,而不是硬codded值
    • 更安全:如果代碼被重構,並且@counter變成可以攜帶SQL注入的類型,則降低SQL注入的風險
    • 不易出錯:沒有NULL值的風險傳播以消除整個@sql
    +0

    你的上述查詢將自動檢查是空的@course,我明確做.....如果@course不爲空 – NoviceToDotNet 2010-11-10 17:52:56

    +0

    先生你得到我的問題我想知道這將執行上述查詢如果我寫這個長查詢沒有檢查isNull在動態查詢書寫......就像我檢查過程和分支如果@ course不爲空然後只附加它相同的所有參數即時做 – NoviceToDotNet 2010-11-11 02:59:05

    +0

    我假設NULL意味着可選過濾器,如果是NULL,那麼它不應該被添加去WHERE。然後分支'@ sql'的構造:'如果@ p1不爲空set @sql + ='AND c1 = @ p1';如果@ p2不是空集@sql + ='AND c2 = @ p2';'等等。然後將* all *參數傳遞給動態SQL:'exec sp_executesql @sql,'@ p1 int,@ p2 int。 ..',@ p1,@ p2,...;'。動態SQL將使用添加到'@ sql'的參數並忽略那些不是(即NULL)的參數。 – 2010-11-11 03:42:36

    4

    您發佈的代碼的基本原理是,需要爲SQL Server發生數據類型更改才能允許字符串連接發生。語句本身是一個字符串,提交給優化器,它將比較視爲正確的數據類型 - INT到INT。

    可以使用測試&確認自己在Management Studio /蟾蜍的/ etc以下:

    DECLARE @course INT 
        SET @course = 1234 
    
    SELECT 'Where course_id='+ @course 
    

    這將失敗,並出現錯誤讀數:轉換爲varchar時

    轉換失敗值'where course_id ='到數據類型int。

    ...而這一點:

    DECLARE @course INT 
        SET @course = 1234 
    
    SELECT 'Where course_id='+ CAST(@course AS VARCHAR) AS output 
    

    ...將返回:

    output 
    --------------------- 
    Where course_id=1234 
    

    有接近dynamic SQL. I highly recommend reading this article -- The Curse and Blessings of Dynamic SQL -- on the subject的其他手段。

    +0

    所以所有的輸入數據類型我應該把varchar類型只?我不需要爲任何輸入參數爲他的SQL查詢採取任何int或其他數據類型?是否正確 – NoviceToDotNet 2010-11-10 17:44:27

    +2

    @NoviceToDotNet:爲了滿足字符串連接需求而將所有內容轉換爲VARCHAR的複雜操作對於處理諸如DATETIME/etc之類的事情可能會非常痛苦。我建議將'sp_executesql'方法用於動態SQL,以便無需使用顯式數據類型轉換就可以對變量進行參數化。 – 2010-11-10 18:21:08

    +0

    如果我使用的方法告訴你sp_executesql,我不必明確地檢查null屬性,就像我在我的動態查詢中一樣,如果@course不爲空...... – NoviceToDotNet 2010-11-10 18:27:50

    1

    你似乎是混亂的比較(a = b)和分配(SET @a = b

    VARCHARINT之間的比較,前者總是被轉換爲後者,所以這個查詢將失敗:

    SELECT 1 
    WHERE 'ab' = 1 
    

    ,因爲'ab'不強制轉換爲INT

    在一個分配,源值(b)總是投射到所述目標的類型(@a):

    DECLARE @av VARCHAR(100) 
    SET  @av = 1 
    GO 
    
    DECLARE @ai INT 
    SET  @ai = 'ab' 
    GO 
    

    由於一個INT總是可澆注到一個VARCHAR,第一批將總是成功,不同於將VARCHAR投射到INT的第二批次。

    1

    在您的查詢中,您實際上只是構建另一個(動態)查詢。所以,如果你有,例如:

    SET @course = 2 
    SET @query = 'SELECT * FROM Courses' 
    SET @query = @query + 'Where course_id='+ cast(@course as varchar) 
    

    @course的值轉換爲字符,追加到@query和到底是:

    SELECT * FROM Courses Where course_id=2 
    

    這是完全有效的SQL,而不在執行之前需要轉換任何東西。

    相關問題