SQL 服务器链接服务器到 PostgreSQL 土耳其字符问题
SQL Server Linked Server to PostgreSQL Turkish Character Issue
在 this blog post 的帮助下,我已将 PostgreSQL 链接服务器添加到我的 SQL 服务器。我的问题是当我使用下面的查询时,我遇到了土耳其语字符问题。
在 Microsoft SQL Server 2012 上的查询:
SELECT *
FROM OpenQuery(CARGO, 'SELECT taxno ASACCOUNTNUM, title AS NAME FROM view_company');
实际结果:
MUSTAFA ÞAHÝNALP
预期结果:
MUSTAFA ŞAHİNALP
问题是源编码是使用代码页 1254 的 8 位扩展 ASCII -- Windows Latin 5 (Turkish). If you follow that link, you will see the Latin5 chart of characters to values. The value of the Ş
character -- "Latin Capital Letter S with Cedilla" -- is 222 (Decimal) / DE (Hex). Your local server (i.e. SQL Server) has a default Collation of SQL_Latin1_General_CP1_CI_AS
which is also 8-bit Extended ASCII, but using Code Page 1252 -- Windows Latin 1 (ANSI)。如果您遵循 link,您将看到显示 Þ
字符的 Latin1 图表 - "Latin Capital Letter Thorn" - 也具有 222 的值(十进制)/DE(十六进制)。这就是您的角色以这种方式翻译的原因。
您可以尝试以下几种方法:
使用sp_serveroption设置以下两个选项:
EXEC sp_serveroption @server=N'linked_server_name',
@optname='use remote collation',
@optvalue=N'true';
EXEC sp_serveroption @server=N'linked_server_name',
@optname='collation name',
@optvalue=N'Turkish_100_CI_AS';
不确定这是否适用于 PostgreSQL 作为远程系统,但至少值得一试。请注意,这需要将所有远程列排序规则设置为此特定值:土耳其语/代码页 1254.
对每列强制排序规则:
SELECT [ACCOUNTNUM], [NAME] COLLATE Turkish_100_CI_AS
FROM OPENQUERY(CARGO, 'SELECT taxno AS ACCOUNTNUM, title AS NAME FROM view_company');
将字符串值(只是那些有字符映射问题的)转换为 VARBINARY
并插入到一个临时的 table 中,其中列设置为正确的排序规则:
CREATE TABLE #Temp ([AccountNum] INT, [Name] VARCHAR(100) COLLATE Turkish_100_CI_AS);
INSERT INTO #Temp ([AccountNum], [Name])
SELECT [ACCOUNTNUM], CONVERT(VARBINARY(100), [NAME])
FROM OPENQUERY(CARGO, 'SELECT taxno AS ACCOUNTNUM, title AS NAME FROM view_company');
SELECT * FROM #Temp;
这种方法首先将传入的字符转换为二进制/十六进制表示形式(例如 Ş
--> 0xDE
),然后在将 0xDE
插入 VARCHAR
temp table 中的列,它会将 0xDE
转换为代码页 1254 的值 的预期字符(因为这是柱子)。结果将是 Ş
而不是 Þ
.
更新
选项 # 1 适用于 O.P。
在 this blog post 的帮助下,我已将 PostgreSQL 链接服务器添加到我的 SQL 服务器。我的问题是当我使用下面的查询时,我遇到了土耳其语字符问题。
在 Microsoft SQL Server 2012 上的查询:
SELECT *
FROM OpenQuery(CARGO, 'SELECT taxno ASACCOUNTNUM, title AS NAME FROM view_company');
实际结果:
MUSTAFA ÞAHÝNALP
预期结果:
MUSTAFA ŞAHİNALP
问题是源编码是使用代码页 1254 的 8 位扩展 ASCII -- Windows Latin 5 (Turkish). If you follow that link, you will see the Latin5 chart of characters to values. The value of the Ş
character -- "Latin Capital Letter S with Cedilla" -- is 222 (Decimal) / DE (Hex). Your local server (i.e. SQL Server) has a default Collation of SQL_Latin1_General_CP1_CI_AS
which is also 8-bit Extended ASCII, but using Code Page 1252 -- Windows Latin 1 (ANSI)。如果您遵循 link,您将看到显示 Þ
字符的 Latin1 图表 - "Latin Capital Letter Thorn" - 也具有 222 的值(十进制)/DE(十六进制)。这就是您的角色以这种方式翻译的原因。
您可以尝试以下几种方法:
使用sp_serveroption设置以下两个选项:
EXEC sp_serveroption @server=N'linked_server_name', @optname='use remote collation', @optvalue=N'true'; EXEC sp_serveroption @server=N'linked_server_name', @optname='collation name', @optvalue=N'Turkish_100_CI_AS';
不确定这是否适用于 PostgreSQL 作为远程系统,但至少值得一试。请注意,这需要将所有远程列排序规则设置为此特定值:土耳其语/代码页 1254.
对每列强制排序规则:
SELECT [ACCOUNTNUM], [NAME] COLLATE Turkish_100_CI_AS FROM OPENQUERY(CARGO, 'SELECT taxno AS ACCOUNTNUM, title AS NAME FROM view_company');
将字符串值(只是那些有字符映射问题的)转换为
VARBINARY
并插入到一个临时的 table 中,其中列设置为正确的排序规则:CREATE TABLE #Temp ([AccountNum] INT, [Name] VARCHAR(100) COLLATE Turkish_100_CI_AS); INSERT INTO #Temp ([AccountNum], [Name]) SELECT [ACCOUNTNUM], CONVERT(VARBINARY(100), [NAME]) FROM OPENQUERY(CARGO, 'SELECT taxno AS ACCOUNTNUM, title AS NAME FROM view_company'); SELECT * FROM #Temp;
这种方法首先将传入的字符转换为二进制/十六进制表示形式(例如
Ş
-->0xDE
),然后在将0xDE
插入VARCHAR
temp table 中的列,它会将0xDE
转换为代码页 1254 的值 的预期字符(因为这是柱子)。结果将是Ş
而不是Þ
.
更新
选项 # 1 适用于 O.P。