Pages

2010年10月26日 星期二

無法解析 equal to 作業中 "Chinese_Taiwan_Stroke_CI_AS" 與 "Chinese_Taiwan_Stroke_BIN" 之間的定序衝突

如果在曾在不同版本的 SQL Server 上搬移過 Database,或是匯出、匯入過不同語系的 Database,都很有可能在下 SQL 語法的時候發生資料庫「定序」(Collation)錯誤的問題,那… 定序(Collation)到底是什麼咧?我相信妳看到這裡一點都不會想知道,所以我今天是說給其它一些想了解的人聽的。

「定序」到底是什麼?最簡單的來說,就是決定資料在資料庫裡排列的方式。聽起來好像也沒什麼大不了的,就只是排列的方式嘛… 對吧對吧?排列的方式可以有多重要?可以比吃飯重要嗎?只要結果資料可以秀出來,排列不對只是個小事而已,其實,我當初也是這樣想…

說到這裡,感覺好像還聽不出什麼重點。就讓我直說吧,當兩個 table 定序不同的時候如果有做 join 的動作,那就一定會發生「無法解析 equal to 作業中 xxx 與 ooo 之間的定序衝突」,因為 SQL Server 無法得知妳到底要遵從哪種定序,所以就直接給妳錯誤然後死在那裡,超級不負責任,跟我完全不一樣!

舉個例子,我們都知道 SQL 裡的 Order By 欄位,不過我們所謂的 Order By 欄位到底是 Order By 欄位裡的什麼呢?英文大小寫有差嗎?字體的全形半形有影響嗎?如果欄位裡面存的是中文資料,那是 Order By 筆劃嗎?還是發音?講了這麼多,「定序」(Collation)就是在做這件事。

如果在妳的 MS SQL Server Management Studio 上的 Database 上按滑鼠右鍵,妳可以在資料庫屬性裡的「一般」或是「擴充屬性」裡看到這個資料庫目前設定的「定序」是什麼。

妳目前所看到的是「Chinese_Taiwan_Stroke_BIN」,前面「Chinese_Taiwan」指的是語系,而後面 BIN 則是指「Binary」的意思,換句換說,就是表示目前是使用 Binary 來做排序,而也因為每個字的 binary 值不同,所以也可說是是這些資料欄位是有區分大小寫的。

再舉個例子「Chinese_Taiwan_Stroke_CI_AS」,「CI」是指 Case Insensitive(不區分大小寫),「AS」是指 Accent sensitivity(區分腔調),其他比較常見的還有「CS」Case sensitivity(區分大小寫)、「AI」Accent Insensitive(不區分腔調),「WS」Width sensitivity(區分全形半形)等等,其中還有比較特殊的「BOPOMOFO」可以讓妳不依照筆劃反而是依照中文 ㄅㄆㄇㄈ 發音來排序。

說了這麼多,相信妳應該有了個底,接下來就是整篇的重點了,萬一妳在 join 兩個定序不同的 table 而發生了譬如說「無法解析 equal to 作業中 "Chinese_Taiwan_Stroke_CI_AS" 與 "Chinese_Taiwan_Stroke_BIN" 之間的定序衝突」的問題,那該怎麼辦?這個可以區分為兩個主要解決辦法。

如果妳是開發人員角色,且在沒有辦法去修改後端資料庫時,最簡單的辦法就是在妳所 Join 的 table 後面直接加上 Collate 新定序名稱,這樣就解決了。例子如下
select EmpId, EmpName, CityName from Emp
join City on Emp_CityId=CityId collate Chinese_Taiwan_Stroke_CI_AS
where EmpId='9F40460'
簡單吧!我就說,我也不懂為什麼外面的書籍或是教學文件為什麼要弄得那麼複雜。好吧,接下來就有一些些複雜了,如果妳是資料庫管理人員,而妳在無法更動程式的狀況下,想要直接一勞永逸修正資料庫來解決問題,就要照以下的步驟來做。

如果妳想要更改整個資料庫的定序,妳必須下以下的指令,因為在 MS SQL Management Studio 裡是不允許妳直接修改定序(避免妳操作不當選擇了錯誤的語系而把整個資料庫毀了)。
ALTER DATABASE 妳的資料庫名稱 SET SINGLE_USER WITH ROLLBACK IMMEDIATE
ALTER DATABASE 妳的資料庫名稱 Collate Chinese_Taiwan_Stroke_CI_AS
ALTER DATABASE 妳的資料庫名稱 SET MULTI_USER WITH ROLLBACK IMMEDIATE
第一行是鎖定目前資料庫給妳一個人使用,避免其他人更新,最後一行是恢復成多人使用,而第二行則是設定妳所想要的定序名稱。這個指令,不僅會直接更改資料庫的定序,連同這個資料庫下面的所有 tables 也都會被更改成這個新的定序,不過… 這邊就要聽好,重點來了,這個也僅只會更改「資料庫」與「Table」的定序,而 Table 下的欄位也有自己的定序,通常預設是跟 Table 一樣,不過有時候也有例外的情形…

如果以上的指令下過了,妳還是發生同樣的定序錯誤,那妳就得看一下 SQL 語法到底是哪個欄位與欄位之間做 join 時定序發生錯誤,而直接去修改那個欄位的定序。

修改欄位的定序可以在 MS SQL Management Studio 上直接設定。

可以指定或或是使用目前 Table 的預設值(還原預設值)。

不過… 天底下有時候就是這麼剛好有這麼衰的事,當妳無從得知程式背後是如何運作的同時,又剛好發生定序錯誤… 唯一的辦法,就是一個 table、一個 table、一個欄位、一個欄位的掃一遍了… 而這種好死不死的衰事,最近這幾天就剛好發生在我身上… 唉…(要不然也不會有這麼枯燥的這篇出現了)

13 回應:

竹本語溪 提到...

嗯....
閱))只針對中文字有沒有錯字而已!!
(飄過)))))

竹本語溪 提到...

等一下,我抓到一個錯字!
資料褲!!除非你這個一堆堆的東西是要穿褲子的,不然這個應該是錯字...

Unknown 提到...

修正修正!

玉姐您老慢走啊~

匿名 提到...

啊~~~~~

原來如此 !!

希望我可以解決我的問題 !!

小于 提到...

終於找到了如何修改db定序的方法,
感激不盡 ^0^

P.N.J. 提到...

這種好用的文章應該多一點才是

小妃 提到...

看... 看不懂 ~>_<~

Jacob 提到...

如果欄位定序錯亂,那還真的是超慘的...
我也是苦主之一啊,真的無解 ><

杜賓 提到...

謝謝你的生日祝福!我真喜歡你!
雖然你老是寫一些我根本看不懂的文章,我還是喜歡你!
別忘了222喔。

匿名 提到...

感謝您的文章,讓我解決了問題....
thank you ^^

匿名 提到...

水啦...清楚無比,謝啦~

匿名 提到...

讚讚讚~
簡單明瞭 清楚易懂!

匿名 提到...

感恩大大
祝福您~