【问题标题】:Invalid data (???????) returned from SQL Server stored procedure addressing linked Oracle server从 SQL Server 存储过程寻址链接的 Oracle 服务器返回的无效数据 (?????????)
【发布时间】:2016-03-21 17:45:06
【问题描述】:

我们有以下场景:过程是在输出上使用 Oracle 存储过程返回带有希腊字母的字符串。

Oracle 函数(示例)是:

FUNCTION GREEKLATINSTRING (a_latin_name IN VARCHAR2) RETURN VARCHAR2
 IS
 BEGIN RETURN 'ΣΤΡΟΒΟΛΟΣ/123/ABC'; END;

这个函数是从一个 T-SQL 存储过程中调用的(请假设所有连接都是 100%,因为我们有其他过程正在执行而没有问题)

TSQL 存储过程是:

CREATE PROCEDURE [dbo].[GreekLatinString] @NameLatin NVARCHAR(100)
AS 
    DECLARE @output NVARCHAR(100);
    DECLARE @SQL NVARCHAR(MAX);
BEGIN
    SET @SQL = N'BEGIN ? := LINKED_SERVER.DB_INSTANCE.GREEKLATINSTRING(?); END;';

    EXECUTE(@SQL, 
            @output            OUTPUT    ,
            @NameGr                      ) --1Params
            AT MYORACLE;

    SELECT cast (@output as nvarchar)
END

而 C# 代码并没有什么特别之处 - 只是取回数据:

dbCommand = CreateCommand();
dbCommand.Transaction = ModelContext.CurrentDBUtils.Transaction;
dbCommand.CommandText = "GreekLatinString";
dbCommand.CommandType = CommandType.StoredProcedure;

SqlParameter param0 = new SqlParameter("NameLatin", nameLatin);
param0.Direction = ParameterDirection.Input;
dbCommand.Parameters.Add(param0);

using (SqlDataAdapter adapter = new SqlDataAdapter(dbCommand as SqlCommand))
{
   adapter.Fill(dataset);
}

SQL Server 实例排序规则是 SQL_Latin1_General_CP1253_CI_AS AND Oracle NLS_LANGal32utf8

问题是,每当函数直接在 Oracle 中执行时,它都会返回应有的值,但是每当我们从 SQL Server 存储过程内部从 C# 调用时,数据集中的输出始终是 ????????

任何人都可以提出可能的原因吗?

【问题讨论】:

  • 尝试 BEGIN RETURN N'ΣΤΡΟΒΟΛΟΣ';
  • 从代码来看,greek_to_latin 看起来像是在返回希腊字母,所以我不清楚为什么叫它greek_to_latin。我没有听说过al8utf8,并且在Oracle 的全球化指南中找不到它的参考资料。 docs.oracle.com/database/121/NLSPG/index.htm#A
  • 如果我明白的话。您可以在 Oracle 框中调用 greek_to_latin 并获得正确的结果。从 C# 调用 GreekToLatin 会得到 ????...GreekToLatin 从 SSMS 直接在 SQL Server 中怎么样?
  • 如果您检查它的字节值,您会看到什么?您的应用是否能够显示来自其他来源的希腊字母(即硬编码)
  • @Frisbee 我已经更改了一些解释,请再看一遍 + 我提供了返回值作为示例。通常我们从 oracle 返回 varchar2 输出变量。有没有办法强制 N' ' 像 var 而不是一些 const 字符串的行为?

标签: c# sql-server oracle tsql stored-procedures


【解决方案1】:

不是一个真正的答案,但评论太长了:

当Oracle数据库和Oracle客户端的字符集不同时,Oracle会双向执行translation of character data。如果目标字符集不支持源字符,Oracle 将替换一些有效的字符。在许多单字节字符集中?,在Unicode 字符集中使用u+FFFD,REPLACEMENT CHARACTER

请注意,客户端字符集对于客户端计算机不是固定的,但可以在连接级别设置。

在这种情况下:

  1. 字符数据来源于 Oracle 数据库字符集。此字符数据包括希腊字母。
  2. 字符数据被发送到 SQL Server 的链接数据库连接使用的 Oracle 客户端。如果客户端字符集和数据库字符集不同,则会发生转换。
  3. 从 Oracle 客户端,字符数据可以通过其他软件层传输。 (例如 OLE DB。)
  4. 字符数据被导入 SQL Server。
  5. 显示字符数据。希腊字母变成了问号。

我的猜测是,步骤 2 中的 Oracle 客户端字符集是不支持希腊字母的单字节字符集,并且在此步骤中字符被转换为问号。这就是我要开始调查的地方。同样,没有为机器设置客户端字符集,因此无法在 SQL Server 机器上启动 SQLPlus 并说“有效,问题不在 Oracle 客户端字符集中”。因为 SQLPlus 使用的可能与 SQL Server 不同。

一旦您验证了 Oracle 客户端字符集是合适的,如果您仍然有问题,您将必须弄清楚如何继续工作。我没有任何指导可以提供。也许针对您正在使用的相同 OLE DB 驱动程序编写一个简单的客户端应用程序。我不确定。

【讨论】:

  • 这是很好的信息。您能否澄清一下:如果数据在Oracle中存储在同一列中,并且该数据既是希腊字符又是中文字符,Oracle客户端是否只能显示一组这些字符(取决于客户端字符集?)
  • @Nick.McDermaid 如果 Oracle 客户端字符集是 Oracle 的“通用字符集”之一,并且客户端软件可以正确使用和显示该字符集,则可以显示的字符没有限制. Oracle 的 AL32UTF8 是 Unicode 的 UTF-8,所以我们并不是在谈论 2015 年的任何超级异国情调。尽管 Oracle 的文档似乎暗示 Unicode 客户端字符集在 Windows 上不起作用。但是,嗯,他们这样做,至少有时是这样。通用字符集的文档链接:docs.oracle.com/database/121/NLSPG/applocaledata.htm#NLSPG589
  • 我不明白为什么 Oracle DB 中的 UTF-8 和客户端中的 UTF-8 不能对所有字符“正常工作”。也许确实如此,问题是 T-SQL 只是不支持 UTF-8 dba.stackexchange.com/questions/7346/…
  • @Nick.McDermaid,但 T-SQL 确实支持 UCS-2 的 N 类型中的 Unicode(我们假设是 UTF-16,非常感谢.)。 OP 在 SQL Server 中使用 N 类型。人们希望,如果在 Oracle DB 中是 AL32UTF8,在 Oracle 客户端中是 AL32UTF8,那么在 Oracle 客户端软件和 T-SQL N 字符串之间会有 UTF-8 和UCS-2。我不知道该翻译是否发生,或者需要进行什么配置才能实现。或者将客户端字符集设置为更接近 SQL Server 的 N 类型的 AL16UTF16 更好。
  • 我们正在尝试根据您的建议确定实际问题发生在哪里 - 我们将在获得结果后立即更新
猜你喜欢
  • 2013-08-07
  • 1970-01-01
  • 2020-02-15
  • 1970-01-01
  • 1970-01-01
  • 2013-12-06
  • 1970-01-01
  • 2015-04-19
相关资源
最近更新 更多