解决 SAP 的排序规则冲突
解决 SAP 中的排序规则混合问题 (SQL_Latin1_General_CP850_BIN vs. Latin1_General_CI_AS)。
引言
如果您在 SQL Server 上运行 SAP 安装(无论您使用 2000 还是 2005 版本),您都必须使用 SQL_Latin1_General_CP850_BIN 排序规则(例如,请参阅 http://searchsap.techtarget.com/generic/0,295582,sid21_gci1169892,00.html?bucket=REF)。 这不是 SQL Server 中的默认排序规则;如果您遵循安装程序的建议,它将使用 Latin1_General_CI_AS。 如果您想从您的 SAP 数据库正确地将数据传输到例如在 SQL Server 的标准排序规则上运行的 DWH 数据库,这会导致问题。
幸运的是,您可以轻松解决这个问题。 在我们讨论解决方案之前,让我向您提供有关该问题的更多详细信息。 作为起点,我在运行在 SQL_Latin1_General_CP850_BIN 上的 SAP 数据库上执行以下 SQL SELECT
语句
select MTEXT, cast(MTEXT as varbinary) from T000
它返回表 T000 中的所有行,并以文本和二进制格式显示 varchar
列 MTEXT
的内容。 在我的示例中,我有一行包含一个变音符号(德语“变音符 O”字符:Ö):Österr.[...]
。 如果我们看一下该文本的二进制格式,它包含以下 ASCII 代码
Ö s t e r r .
D6 73 74 65 72 72 2E
如果您愿意,您可以自己检查字符代码。 您可以在 Wikipedia 上查找代码页 850 的字符映射,网址为 http://en.wikipedia.org/wiki/CP850。 当我这样做时,我非常惊讶于变音符 O 的代码不正确(它应该是 99;它是 D6)。 事实上,D6 是代码页 1252(=Latin1_General_CI_AS;请参阅 http://en.wikipedia.org/wiki/CP1252)中变音符 O 的字符代码! 看起来 SAP 要求使用代码页 850,但使用代码页 1252 存储值。 那么让我们看看这在使用链接服务器传输数据时会如何影响我们。
在本文中,我假设目标服务器正在运行 SQL Server 2005 版本。 如果您在那里创建链接服务器,您有两个关于排序规则的选项
- 使用 Remote Collation = True 或
- 使用 Remote Collation = False
创建链接服务器并尝试使用 Use Remote Collation 设置为 true 和 false 执行以下查询一次
select x1.MTEXT, cast(x1.MTEXT as varbinary)
from SAP01SQL.P01.dbo.T000 x1
inner join SAP01SQL.P01.dbo.T000 x2 on
x1.MANDT=x2.MANDT
and x1.MTEXT=x2.MTEXT
and x2.MTEXT like '_sterr%'
将 Use Remote Collation 设置为 false 的结果如下所示
正如您所看到的,结果是正确的! 变音符 O 正确显示。 为什么? 简单原因:设置 Use Remote Collation: false 告诉 SQL Server 检索链接服务器的内容,无需任何代码页转换。 正如我们之前看到的,SAP 存储 ANSI 字符代码(=代码页 1252);因此,忽略所有转换会导致正确的结果。 但是,此解决方案会导致一个重要的缺点:SQL Server 无法将连接和 where 子句传递给远程服务器,因为远程服务器将使用其代码页,而我们已经告诉 SQL Server 不 使用远程排序规则。 因此,所有表的内容都会完全传输到目标服务器,并且连接以及 where 子句都会在目标服务器上执行 -> 性能不佳。 这是显示正在发生的事情的执行计划
现在让我们将 Use Remote Collation 的设置更改为 true,并再次执行 SELECT
语句。 这是结果
这次结果是错误的。 原因在于 SQL Server 试图将列的内容从代码页 850 转换为 ANSI(=代码页 1252)。 记住,SAP 将 ANSI 字符代码写入 ASCII 列 -> 转换导致上述错误结果。 优点是连接和 where 子句在 SAP 服务器上执行 -> 性能良好
似乎我们必须在具有糟糕性能的正确结果或具有良好性能的错误结果之间做出选择?! 不,有一些方法可以确保正确的结果并且 具有良好的性能。
第一个解决方案是将 SAP 服务器上的连接和 where 子句封装在视图中。 您可以使用 Use Remote Collation 设置为 true 访问这些视图,并且您将获得正确的结果。 连接和 where 子句在 SAP 服务器上执行。 作为替代方案,您也可以使用 OPENQUERY
而不是视图。
如果您不想将业务逻辑放在您的 SAP 服务器上,而是将逻辑放在目标服务器中,您可以手动更改排序规则。 为此,我编写了一个小的 C# 程序集,您可以在 SQL Server 2005 中使用它。 这是代码
using System;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
public partial class UserDefinedFunctions
{
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString ConvertCodepage( byte[] binString, SqlInt32 len )
{
if (len.IsNull)
return SqlString.Null;
else
{
Encoding ai = Encoding.GetEncoding(1252);
return new SqlString(ai.GetString(binString, 0, len.Value));
}
}
};
您可以部署此函数并在之前显示的 SELECT
语句中使用它
select x1.MTEXT, cast(x1.MTEXT as varbinary),
dbo.ConvertCodepage( cast(x1.MTEXT as varbinary), len(x1.MTEXT) )
from SAP01SQL.P01.dbo.T000 x1
inner join SAP01SQL.P01.dbo.T000 x2 on
x1.MANDT=x2.MANDT
and x1.MTEXT=x2.MTEXT
and x2.MTEXT like '_sterr%'
检查结果,您将看到它有效