(3.6)常用知識-字符編碼與排序規則


修改實例、數據庫、表、字段參考:https://www.cnblogs.com/gered/p/9376896.html

服務器排序規則參考:https://docs.microsoft.com/zh-cn/sql/relational-databases/collations/set-or-change-the-server-collation?view=sql-server-2017

數據庫排序規則參考:https://docs.microsoft.com/zh-cn/sql/relational-databases/collations/set-or-change-the-database-collation?view=sql-server-2017

  概述:如果使用sql server在多種語言環境下開發應用系統,最容易產生額問題就是亂碼。保存在數據庫中的數據,在某些環境下能顯示為正常數據,而在某些環境下,顯示出來的是亂碼。在進行字符數據排序時,sql server究竟是按照上面標准來決定字符數據的先后順序的?在sql server中,這一切都與排序規則及字符存儲采用的數據類型有關。

 

1.字符編碼

  在sql server中,字符存儲有一下兩種選擇

  (1)使用char、varchar、varchar(max)或者text這類非Unicode數據類型

  使用這些數據類型時,每個字符的位模式以及存儲和比較字符使用的規則由排序規則確定,不同的排序規則對應不同的代碼頁。

  當使用費Unicode數據類型來存儲字符數據時,要求數據存儲的代碼頁和客戶端應用程序的代碼頁必須相同,否則不能保持字符數據的完整性,因為代碼頁不相同時,客戶端和服務器之間的轉換可能導致某些字符丟失。

  當客戶端和數據庫的代碼頁不匹配時,對所有發往(或發自)服務器的非Unicode字符串進行代碼頁轉換時必須的,不支持通過禁用sql server ODBC驅動程序的AotoTranslate功能來插入由服務器上其他代碼頁定義的數據;即使禁用了AotoTranslate,也不能防止SQL語言實踐進行代碼頁轉換。

  因為轉換可能導致某些字符丟失,因此,應盡量避免客戶端和數據庫的代碼頁不匹配,以避免轉換的發生,當然,也可以考慮客戶端和數據庫使用一種字符集大致相同的代碼頁,這樣,兩種嗲媽耶中的大部分字符可以想換轉換而不會丟失數據。

  (2)使用nchar、nvarchar、nvarchar(max)或者ntext這類Unicode數據類型

  當只使用字符數據和代碼頁時,在一個數據庫內很難以多種語言存儲數據,也很難為數據庫找到一種能存儲所有需要的語言特定字符的代碼頁。此外,當運行不同代碼頁的不同客戶端讀取和更新特殊字符時,很難保證正確轉換這些字符。使用Unicode類型可以解決這一類問題。

  Unicode是一種將碼位映射到字符的標准,它的設計涵蓋世界上所有語言的全部字符,因此不需要不同的代碼頁來處理不同的字符集。如果所有使用國際化數據庫的應用程序也采用Unicode變量而不是非Unicode變量,那么在系統中的任何地方都無需進行字符轉換,客戶端與所有其他客戶端看到的數據中的字符相同。

  即使采用了Unicode類型來存儲數據,如果數據交互的客戶端應用程序使用的是特殊代碼頁,也必須考慮如何保持字符數據的完整性。

  輸入數據

  在輸入數據時,當把客戶端發送的非Unicode數據以Unicode存儲在服務器中時,如果具備下列條件之一,則來自任何客戶端的任何代碼頁的數據都可以正確存儲。

  【1】字符串作為遠程過程調用(RPC)的參數發送到服務器

  【2】字符串常量以大寫字母N開頭。如果沒有字母N前綴,則SQL server會將字符串轉換為與數據庫的默認排序規則相對應的代碼頁,次代碼頁中沒有的字符都將丟失。

  演示舉例:

select SERVERPROPERTY('Collation') --查看服務器默認排序規則
select SERVERPROPERTY('SqlCharSetName')--查看服務器排序使用字符集名稱
--查看服務器排序規則(安裝時指定的排序規則)  
SELECT SERVERPROPERTY('COLLATION') AS ServerCollation  
,DATABASEPROPERTYEX('db_test','COLLATION') AS TempdbCollation  
,DATABASEPROPERTYEX(DB_NAME(),'COLLATION') AS CurrentDBCollation  
--查看字符集 select
SERVERPROPERTY('SqlCharSetName') as '服務器字符集',
DATABASEPROPERTYEX('db_test','SqlCharSetName') as '數據庫字符集'
--查看所有數據庫排序規則  
SELECT name, collation_name FROM sys.databases
  
 --查看當前服務器與指定數據庫的排序規則及字符集
--查看所有庫的排序規則

 

 
        

 

 



  {1}在簡體中文的環境下,創建排序規則為英文的數據庫db_test,並在該庫上演示使用Unicode類型nvarchar來存儲數據,是否會產生亂碼。

  

--創建英文字符排序規則DB
create database db_test
collate Latin1_General_CI_AS
GO
--構造演示數據
use db_test
declare @tb tabl
(
    id int,
    col nvarchar(10)
)

insert @tb(id,col) select id = 1,col='' union all
select id = 2,col = N''

--1.顯示數據
select * from @tb

--2.條件檢索
select * from @tb
where col=''

select * from @tb
where col=N''

 演示如圖:

  

 

  結論,不同排序編碼對應使用不同字符集。

  在顯示數據1中:由於db_test數據庫使用的是英文排序規則,無法其代碼頁無法識別中文,所以出現亂碼(為了統一信息sql server會把這種無法識別的字符給一個?號存儲表示)

  在顯示數據2中:那么在篩選的時候,第1次篩選 where col = '中',這里'中'這個字符無法識別,會轉換成?號到內部,所以所有無法識別的?號數據全都查不出來了。而在第2次篩選 where col =N'中',則可以正常使用,不受排序規則的影響,因為其輸入與存儲都是用的Unicode 字符標准。

  數據檢索

  如果客戶端應用程序不支持Unicode而將數據檢索到了非Unicode緩沖區,則客戶端只能檢索或修改客戶機代碼頁可以表示的數據。

  這樣說不太明白,舉例:即使用正常的方式存儲了中文字符到數據庫,但如果在未安裝中文字符集的英文系統中檢索數據,這些中文字符依然無法正常顯示。

  

 

2.排序規則

  在描述字符編碼的時候已經提到了排序規則,它僅僅適用於非Unicode數據類型,每個排序規則與某個特定的代碼頁關聯,確定了每個字符的位模式以及存儲和比較字符使用的規則。

  排序規則確定了字符排序規則根據特定的語言和區域設置的標准制定對字符串數據進行排序和比較的規則。以order by 子句為例:如果按升序排列,說英語的人認為字符串Chiapas應該排在Colima之前:但是,對於在墨西哥說西班牙語的人來說,他們會認為以Ch開頭的單詞應該顯示在以C開頭的單詞列表的末尾。排序規則規定了這些排序和比較規則。利用排序規則的這些特性,可以處理一些特殊的應用需求。

  (1)區分大小寫

  通過默認設置安裝SQL Server時,sql server是不區分大小寫的,所以很多用戶會誤以為sql server的處理是不區分大小寫的,其實這個主要跟排序規則有關。

  下面的示例演示如何通過collate子句來轉換表達式的排序規則,從而實現字符的比較按指定的排序規則進行(需要注意示例中的全角和半角字符)

  

select 
    case when 'a' collate chinese_prc_90_cs_as = 'A'
    then 1 else 0 end '區分大小寫',
    case when 'a'  collate chinese_prc_90_ci_as = '' 
    then 1 else 0 end '不區分全角與半角',
    case when 'a'  collate chinese_prc_90_ci_as_ws = '' 
    then 1 else 0 end '區分全角與半角'

結果:


參數示例:
CI:不區分大小寫  CS:區分大小寫  WS:區分全角與半角
AI:不區分重音   AS:區分重音   KS:區分假名類型
BIN:指定使用后向后兼容的二進制排序順序
BIN2:指定使用sql server2005中引入的碼位比較寓意的二進制排序順序

--查看sql server所支持的所有有效的windows與sql排序規則
select * from ::fn_helpcollations()

 

  (2)排序規則排序

  除了應用排序規則字符的比較方式,還可以使用排序規則實現特定的排序。

  【1】按拼音排序

  

;with test as
(
    select N'排序規則' as 'col' union all
    select N'' union all
    select N'中文字符' union all
    select N'用拼音排序' union all
    select N'的應用'  union all
    select N''
)
select * from test order by col collate chinese_prc_90_cs_as_ks_ws

結果如圖:
    

   【2】按筆畫排序

  

;with test as
(
    select N'排序規則' as 'col' union all
    select N'' union all
    select N'中文字符' union all
    select N'用拼音排序' union all
    select N'的應用'  union all
    select N''
)
select * from test order by col collate chinese_Stroke_prc_90_cs_as_ks_ws

 

很明顯,這只按第一個字,如果筆畫相同才會考慮第二個字。

 
        

 

 

 

  

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM