2011-07-10 59 views
0

之間的轉換我有一個簡單的SELECT語句是這樣的:SQL服務器 - 簡單的選擇和int和string

SELECT [dok__Dokument].[dok_Id], 
     [dok__Dokument].[dok_WartUsNetto], 
     [dok__Dokument].[dok_WartUsBrutto], 
     [dok__Dokument].[dok_WartTwNetto], 
     [dok__Dokument].[dok_WartTwBrutto], 
     [dok__Dokument].[dok_WartNetto], 
     [dok__Dokument].[dok_WartVat], 
     [dok__Dokument].[dok_WartBrutto], 
     [dok__Dokument].[dok_KwWartosc] 
    FROM [dok__Dokument] 
WHERE [dok_NrPelnyOryg] = 2753 
    AND [dok_PlatnikId] = 174 
    AND [dok_OdbiorcaId] = 174 
    AND [dok_PlatnikAdreshId] = 625 
    AND [dok_OdbiorcaAdreshId] = 624 

dok_NrPelnyOryg的類型爲varchar(30),而不是空的。

該表在此列中包含整數值和字符串值,並且此選擇語句被激發了數百萬次。

然而最近,這種開始消息崩潰:轉換VARCHAR值 '的Garbi czerwiec B' 爲數據類型int時

轉換失敗。

小解釋:該表包含多個「文檔」記錄,所提到的列包含文檔原始編號(來自多個不同的來源)。

我知道我可以通過在數字周圍添加''來解決這個問題,但我寧願尋找一個解釋,爲什麼這用於工作,而現在不改變任何東西,現在它崩潰。

+0

顯然,錯誤消息說明了一切。如果'dok_NrPelnyOryg'的類型是'varchar',爲什麼不查詢它呢? 'dok_NrPelnyOryg ='2753''。自動轉換隻是失敗,因爲他無法將您的值轉換爲數字。 –

+2

公平地說,問題不在於如何解決這個問題,而是爲什麼它在一段時間內工作,然後停止工作。 –

+0

@Aaron Bertrand - 就是這一點。我知道如何解決這個問題,並且我寫了它。 – kubal5003

回答

2

計劃更改(由於更改後的統計信息,重新編譯等)可能會導致此數據在早期進行評估(例如全面掃描),或者此特定數據以前未在表中(可能在此之前開始發生,那裏沒有不好的數據)。如果它應該是一個數字,那麼把它作爲一個數字列。如果它還需要允許字符串,則不要再像數字那樣對待它。如果你正確地聲明瞭你的語句並且總是傳遞一個varchar,那麼你就不用擔心這個值是否被包含在單引號中。

+0

該查詢是參數化的,這些值僅爲示例。它是通過使用SqlCommand對象和ExecuteReader()來觸發的。 while循環與reader.Read()執行多次,然後崩潰在這一個。這種方式已經工作了半年多了。 – kubal5003

+0

如果它是參數化的,那麼如何通過在它周圍放置單引號來修復它?我想也許我們對參數化方法有不同的看法。您應該能夠將參數傳遞給C#中的查詢,而不必擔心字符串分隔符等技術細節。 –

+0

不,我認爲我們有同樣的想法參數化意味着什麼:)我的意思是,我可以在管理工作室執行它的時候像這樣修復它。我已經檢查過,在代碼中,參數的類型是System.Data.DbType.Int32,這是錯誤的。在代碼中解決這個問題並不容易,因爲我將所有的值作爲對象(不是具體類型)獲取,即使對象下的實際類型是System.String,SqlParameter也不能處理它本身。 – kubal5003

0

查詢停止工作,因爲有人使用INT將文本字符串插入到要查詢的字段中。直到那個時候,可以隱式轉換數據,但現在不再是這種情況。

我會去檢查你的數據,更重要的是,模型;正如Aaron所說,你是否需要允許該領域的字符串?如果沒有,請更改數據類型以防止將來發生這種情況。

+0

該字段來自會計軟件數據庫,我無法更改它。還有什麼我不想改變它,因爲它包含字符串和整數(因爲我寫這些值來自不同的來源)。因爲購買發票也存儲在那裏(根據許多不同的模式(如22/FV/2011等)編號) – kubal5003

+0

在這種情況下,正如Aaron所說,這可能是因爲數據已經改變,正在以不同的方式進行評估。如果所有的字符串數據在查詢的早期被排除,那麼隱式轉換不是問題。看起來,字符串數據現在正在使其進一步向下,並且轉換失敗。我知道你不是問如何解決問題,而是編寫使用隱式轉換的代碼,並希望它能夠永久工作,似乎有點樂觀:) – Tony

1

所有這些平等的比較操作受到的SQL Server Data Type Precedence規則:

當操作結合不同的數據類型的兩個 表情, 數據類型優先的規則 指定的數據類型其中 較低的優先級被轉換爲具有較高優先級的 數據類型。

由於性格類型具有優先級低於int型,查詢是基本相同:

SELECT ... 
    FROM [dok__Dokument] 
WHERE cast([dok_NrPelnyOryg] as int) = 2753 
    ... 

這有兩個方面的影響:

  • 它使所涉及列的所有索引WHERE子句無效
  • 它可能導致轉換錯誤。

你不是第一個有這個問題,其實幾個CSS情況下,我遇到了我最終寫這一篇文章:On SQL Server boolean operator short-circuit

問題的正確解決方案是如果字段值是數字,那麼列類型應該是數字。既然你說數據來自一個派對應用程序,你不能改變,最好的解決方案是放棄這個應用程序的供應商,並選擇一個知道正在做什麼的人。短的,你需要搜索字符類型字符列:

SELECT ... 
    FROM [dok__Dokument] 
WHERE [dok_NrPelnyOryg] = '2753' 
    ... 

在.NET託管ADO.Net的說法,這意味着你使用SqlCommand喜歡如下:

SqlCommand cmd = new SqlCommand (@" SELECT ... 
     FROM [dok__Dokument] 
    WHERE [dok_NrPelnyOryg] = @nrPelnyOryg 
     ... "); 
cmd.Parameters.Add("@nrPelnyOryg", SqlDbType.Varchar).Value = "2754"; 
... 

只要確保你不要陷入傳遞NVARCHAR參數(Unicode)以便與VARCHAR列進行比較的簡單陷阱,因爲之前引用的相同數據類型優先級規則將強制在NVARCHAR類型上進行比較,從而再次呈現索引,無用。陷入這個陷阱的最簡單的方法是使用粉碎的AddWithValue並傳遞一個字符串值。

+0

謝謝,我將按照你的建議實現查詢。 – kubal5003