轉自:http://blog.chinaunix.net/uid-354915-id-3502551.html
一、PostgreSQL的區域
區域屬性有以下幾個:
LC_COLLATE:字符串排序順序
LC_CTYPE:字符分類(什么是字母?它是這個字母的等效大寫?)
LC_MESSAGES:信息的語言
LC_MONETARY:貨幣金額的格式
LC_NUMERIC:數字的格式
LC_TIME:日期和時間的格式
PostgreSQL 使用服務器操作系統提供的標准 ISO C 和 POSIX 區域機制。
區域支持是在使用 initdb 創建一個數據庫集群的時候自動初始化的。
如果你的OS已經設置為你的數據庫集群想要的區域,那么你就什么也不用干了。
如果你想要你的系統表現得像沒有區域支持一樣,那么使用特殊的區域 C 或 POSIX
一些區域性質的值一旦運行了 initdb 之后,你就再也不能更改它們了。LC_COLLATE 和 LC_CTYPE 就是這樣的。它們影響索引的排序順序,因此它們必需保持固定,其它區域性質可以在服務器啟動的時候根據需要通過配置postgresql.conf變量來改變,如果你在 postgresql.conf 里面刪除了這些缺省值,那么服務器將會繼承來自運行環境的設置。
我們談到從執行環境繼承區域的時候,比如字符集,按照下面的順序評估這些環境變量,直到找到一個已設置的:LC_ALL, LC_COLLATE, LANG 。如果這些環境變量一個都沒有設置,那么區域缺省為 C 。一些信息區域化庫也使用環境變量 LANGUAGE。
請檢查核實 PostgreSQL 確實使用了你認為它該用的區域設置。LC_COLLATE 和 LC_CTYPE 的設置都是在 initdb 時決定的,如果不重復 initdb 是不可能改變的。其它的區域設置包括 LC_MESSAGES 和 LC_MONETARY 都是由服務器的啟動環境決定的,但是可以在運行時修改。你可以用 SHOW 命令檢查數據庫正在使用的區域設置。
二、PostgreSQL的字符集
缺省的字符集是在使用 initdb 初始化數據庫集群的時候選擇的。在你創建數據庫的時候是可以覆蓋這個缺省的。因此,你可以為多個數據庫設置不同的字符集。
雖然你可以給一個數據庫聲明你需要的任何編碼,但選擇一個與你選擇的區域不一致的編碼還是不妥的做法。LC_COLLATE 和 LC_CTYPE 設置暗示一個特定的編碼,與區域相關的操作(比如排序)在不兼容的編碼里很有可能產生錯誤的解析。
一個安全使用多種編碼的方法是在 initdb 的時候把區域設置為 C 或 POSIX ,這樣就關閉了任何實際的區域敏感性。
PostgreSQL 支持在服務器和前端之間的自動編碼轉換。
假如無法進行特定的字符轉換,比如,你選的服務器編碼是 EUC_JP 而客戶端是 LATIN1 ,那么有些日文字符不能轉換成 LATIN1 。這時將報告錯誤。
三、擴展:
1、常見編碼及轉換
UTF8 = UNICODE8;
UNICODE16是我們經常說的UNICODE;
GBK即漢字內碼擴展規范,GBK是ANSI的一種,用0x80~0xFF 范圍的2個字節來表示1個字符,根據微軟資料,GBK是對GB2312-80的擴展,也就是CP936字碼表;
windows英文版默認的應該是windows1252;
windows中文版用的是GB2312/GBK(用dos命令chcp查看,936為簡體中文);
liunx很多默認編碼都是utf-8,但是你可以通過命令設置成GB2312;
網頁編碼,通常是跟編輯網頁的編輯器有關,比如說你的編輯器設置為GB2312字符集,那么你的網頁的編碼就是GB2312的。如果你用英文的操作系統打開就會是亂碼。不過現在的瀏覽器都支持字符集識別,它會幫你把GB2312編碼的網頁自動轉換為unicode的網頁,從而解決亂碼的問題。
如果你的文件編碼是GBK,而你的系統環境是windows1252英文環境,那么這時候你打開文件就會是亂碼的;
解決方案有兩種:
(1)改變系統的語言為中文就可以解決亂碼的問題;
(2)將GBK編碼的文件轉換為unicode編碼,unicode編碼是萬國碼,一般的操作系統都支持,不存在打開后亂碼的問題。
每種編碼都有自己的二進制編碼集,平時經常遇到的問題是:
(1)對字符進行了錯誤的編碼解析,導致出現亂碼;
(2)字符在兩個字符集中都存在,導致這部分字符變成“?”。
2、數據庫編程的編碼問題
數據庫編程設計的編碼問題包括三個方面:
數據庫服務器編碼;
數據庫客戶端編碼;
本地環境編碼。
(1)數據庫服務器字符編碼:
數據庫服務器支持某種編碼,是指數據庫服務器能夠從客戶端接收、存儲以及向客戶端提供該種編碼的字符,並能將該種編碼的字符轉換到其它編碼。
查看PostgreSQL數據庫服務器端編碼:
postgres=# show server_encoding;
server_encoding
-----------------
UTF8
postgres=# \l
名稱 | 擁有者 | 字元編碼 | Collate | Ctype | TestDb1 | TestRole1 | UTF8 | Chinese (Simplified)_People's Republic of China.936 | Chinese (Simplified)_People's Republic of China.936 |
TestDb2 | postgres | UTF8 | Chinese (Simplified)_People's Republic of China.936 | Chinese (Simplified)_People's Republic of China.936 |
postgres | postgres | UTF8 | Chinese (Simplified)_People's Republic of China.936 | Chinese (Simplified)_People's Republic of China.936 |
template0 | postgres | UTF8 | Chinese (Simplified)_People's Republic of China.936 | Chinese (Simplified)_People's Republic of China.936 |
(2)數據庫客戶端字符編碼:
客戶端工具支持某種編碼,必須能夠顯示從數據庫讀取的該種編碼的字符,也能通過本工具將該種編碼的字符提交到給服務器端。
查看PostgreSQL客戶端工具psql編碼:
postgres=# show client_encoding;
GBK
postgres=# \encoding
GBK
指定Postgresql會話的客戶端編碼:
postgres=# set client_encoding to 'utf8';
SET
postgres=# show client_encoding;
client_encoding
-----------------
UTF8
(3)本地環境編碼:
如果使用dos的命令行界面,本地環境就是指dos命令行環境的編碼,可以使用dos命令chcp查看dos環境編碼:
D:\Program Files\PowerCmd>chcp
活動代碼頁: 936
----936為簡體中文,GBK;
如果在使用某種編輯器,則本地環境編碼取該編輯器的編碼設置。
四、實例
雖然PG支持客戶端和服務器端的編碼自動轉換,但是還需要遵從一個原則:本地環境的編碼和客戶端編碼需一致。
1、PostgreSQL的數據庫postgres,服務器端字符編碼為utf8,客戶端工具psql字符編碼為GBK,本地環境dos命令編輯器編碼為GBK,此時:
postgres=# show server_encoding;
server_encoding
-----------------
UTF8
(1 行記錄)
postgres=# show client_encoding;
client_encoding
-----------------
GBK
(1 行記錄)
postgres=# \! chcp
活動代碼頁: 936
postgres=# select * from "TestTb1";
Column1
-----------
測試
11
由於本地環境和客戶端編碼都是GBK,一致,沒有問題;
insert時,客戶端接收本地環境輸入的GBK字符(兩者都為GBK),客戶端傳到服務器端時自動轉換為UTF-8編碼存儲,沒有問題;
select時,服務器端傳到客戶端,UTF-8編碼自動轉換為GBK編碼,在本地環境顯示時,本地環境就是GBK編碼,顯示沒有問題。
2、PostgreSQL的數據庫postgres,服務器端字符編碼為utf8,客戶端工具psql字符編碼為utf8,本地環境dos命令編輯器編碼為GBK,此時:
postgres=# set client_encoding to 'utf8';
SET
postgres=# insert into test values('測試1');
閿欒?: 鏃犳晥鐨?"UTF8" 緙栫爜瀛楄妭欏哄簭: 0xb2
postgres=# select * from test;
column1
--------------------
嫻嬭瘯
(1 行記錄)
由於客戶端和服務器的編碼一致,故不進行轉碼,
insert時,本地輸入的GBK編碼到客戶端不自動轉換,客戶端把接收的字符作為utf編碼傳給服務器端不轉換,GBK的編碼作為UTF-8存儲,故有問題。
報錯的信息為:ERROR: invalid byte sequence for encoding "UTF8": 0xb2;
select時,服務端的utf編碼傳給客戶端不轉換,客戶端把utf編碼傳給本地環境不自動轉換,utf8編碼用gbk編碼顯示,故有問題。
3、本地環境就是指此時使用的環境,起初我使用powercmd代替windows的cmd命令行工具,實現上面第1個實例是總是失敗(亂碼)。
原因就是,此時本地環境編碼是指powercmd的編碼,而不是執行chcp命令得到的編碼。
而powercmd使用的編碼究竟是什么,我也沒有找到。
