2010-09-27 43 views
12

在我寫的一個測試案例中,字符串比較似乎在SQL Server/.NET CLR之間沒有相同的工作方式。.NET與T-SQL之間的比較差異?

此C#代碼:

string lesser = "SR2-A1-10-90"; 
string greater = "SR2-A1-100-10"; 

Debug.WriteLine(string.Compare("A","B")); 
Debug.WriteLine(string.Compare(lesser, greater)); 

將輸出:

-1 
1 

此SQL Server代碼:

declare @lesser varchar(20); 
declare @greater varchar(20); 

set @lesser = 'SR2-A1-10-90'; 
set @greater = 'SR2-A1-100-10'; 

IF @lesser < @greater 
    SELECT 'Less Than'; 
ELSE 
    SELECT 'Greater than'; 

將輸出:

Less Than 

爲什麼區別?

+0

您是否考慮了區分大小寫? – 2010-09-27 21:47:08

+0

案件是一樣的。區別在於每個人如何將'0'對待爲' - '。 – 2010-09-27 21:47:49

+0

我認爲這是一個Unicode問題。編輯:也許不是。對我來說,SQL Server代碼返回'大於'。您正在測試的數據庫中的默認排序規則是什麼? – 2010-09-27 21:51:52

回答

10

這是documented here

Windows排序規則(例如Latin1_General_CI_AS)使用Unicode類型整理規則。 SQL排序規則不。

這會使連字符在兩者之間被區別對待。

+0

select * from fn_helpcollat​​ions() 其中名稱如'%SQL_Latin1_General_CP1_CI_AS%' 或name ='Latin1_General_CI_AS' – gbn 2010-09-27 22:25:22

+0

非Unicode排序不同,使用CP 1252.我確信LATIN1 ..也做了同樣的事情......不,它不.. http://msdn.microsoft.com/en-us/library/ms143515.aspx – gbn 2010-09-27 22:26:10

3
  • 在SQL您使用VARCHAR這基本上是ASCII(需覈對),這將給 - 前0
  • 在C#中的所有字符串都是Unicode

UTF-XX的細點(C# )與UCS-2(SQL Server)相當棘手。

編輯:

我太早公佈

我得到 「大於」 SQL Server 2008上與整理Latin1_General_CI_AS

編輯2:

我也想嘗試SELECT ASCII(...)您短跑。例如,如果SQL片段曾經在Word文檔中,則 - (150)不是 - (45)我複製到SQL Server中,用於從我的瀏覽器中測試您的問題。請參閱CP 1252(= CP1 = SQL Server術語)

編輯3:請參閱Martin Smith的答案:2個排序規則有不同的排序順序。

+0

啊,我明白了。當我使用nvarchar(20)時,我得到了「大於」。 – 2010-09-27 22:00:20

+0

我得到這與varchar。您的數據庫整理與服務器整理不同嗎? – gbn 2010-09-27 22:03:00

7

除了gbn的回答,您可以通過在C#中使用CompareOptions.StringSort(或使用StringComparison.Ordinal)使其行爲相同。這將符號視爲發生在字母數字符號之前,因此「 - 」<「0」。

但是,由於ASCII代碼頁的十六進制代碼逐字地轉換爲Unicode代碼頁,因此Unicode與ASCII無法解釋任何內容:「 - 」爲002D(45),而「0」爲0030(48)。

發生的事情是,.NET默認使用「語言」排序,這是基於指定或當前文化對各種符號應用的非序號排序和權重。這種語言算法允許例如「簡歷」(帶有重音符拼寫)緊接在「重新開始」(沒有重音拼寫)之後出現在已排序的單詞列表中,因爲「é」在「e」之後給出了分數次序並且遠在「f」之前。它還允許將「合作」和「合作」緊密地放在一起,因爲短劃線符號被賦予低「重量」;當排序諸如「比特」,「比特」和「比特移位」(其將按照該順序出現)之類的詞時,它僅僅作爲絕對的最後的分隔符。由於字母變體通常在ASCII/Unicode序號中的基本未裝飾的拉丁字母后出現,所以所謂的序數排序(嚴格根據Unicode值,有或沒有大小寫不敏感)將產生非常不同並且有時不合邏輯的結果,而符號出現在它之前。例如,「é」在「z」之後,因此「resume」,「rosin」,「ruble」,「résumé」這樣的詞將按照該順序排序。 「Bit's」,「Bit-shift」,「Biter」,「Bits」將按順序排列,首先是撇號,然後是短劃線,然後是字母「e」,然後是字母「s」。從「自然語言」的角度來看,這些看起來都不合邏輯。

+0

代碼頁僅影響字符> 127,否? – gbn 2010-09-27 22:10:12

+0

很酷。通過使用'CompareOption.StringSort',我可以使用當前數據庫整理設置運行我的測試。 – 2010-09-27 22:16:46

+0

@gbn - 技術上是的。這也是C#似乎排序「錯誤」;沒有StringSort,符號字符在字母數字之後。我會編輯。 – KeithS 2010-09-27 22:50:47

0

幾個很好的答案已經在爲什麼會發生這種情況,但我確信其他人只是想知道C#代碼以與SQL服務器相同的順序迭代集合。我發現以下作品最好。 「Ordinal」解決了連字符問題,而「IgnoreCase」似乎也反映了SQL Server默認設置。

Debug.WriteLine(string.Compare(lesser, greater, StringComparison.OrdinalIgnoreCase));