【问题标题】:Why does Oracle require TO_NCHAR when binding SQL_C_WCHAR text via ODBC为什么 Oracle 在通过 ODBC 绑定 SQL_C_WCHAR 文本时需要 TO_NCHAR
【发布时间】:2008-12-03 16:30:38
【问题描述】:

我使用以下在 ODBC 中准备和绑定的语句:

SELECT (CASE profile WHEN ? THEN 1 ELSE 2 END) AS profile_order 
FROM engine_properties;

在与 AL32UTF8 字符集的 Oracle 10g 数据库的 ODBC 3.0 连接中执行,即使在使用 SQLBindParameter(SQL_C_WCHAR) 绑定到 wchar_t 字符串后,它仍然会给出错误 ORA-12704:字符集不匹配。

为什么?我绑定为 wchar。不应该将 wchar 视为 NCHAR 吗?

如果我更改参数以使用TO_NCHAR() 包装它,则查询将正常工作。但是,由于这些查询用于多个数据库后端,我不想只在 Oracle 文本绑定上添加 TO_NCHAR。有什么我想念的吗?不用 TO_NCHAR 锤子解决这个问题的另一种方法?

我无法通过搜索或手册找到任何相关内容。

更多细节...

-- 错误

SELECT (CASE profile WHEN          '_default'  THEN 1 ELSE 2 END) AS profile_order
FROM engine_properties;

-- 好的

SELECT (CASE profile WHEN TO_NCHAR('_default') THEN 1 ELSE 2 END) AS profile_order
FROM engine_properties;
SQL> 描述引擎属性; 名称空?类型 ----------------------------------------- -------- - -------------------------- EID 非空 NVARCHAR2(22) LID 非空数字 (11) 配置文件不为空 NVARCHAR2(32) PKEY 非空 NVARCHAR2(50) 值非空 NVARCHAR2(64) 只读非空数字(5)

这个没有 TO_NCHAR 的版本在 SQL Server 和 PostgreSQL(通过 ODBC)和 SQLite(直接)中运行良好。但是在 Oracle 中它返回“ORA-12704:字符集不匹配”。

SQLPrepare(SELECT (CASE profile WHEN ? THEN 1 ELSE 2 END) AS profile_order 
    FROM engine_properties;) = SQL_SUCCESS
SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_WCHAR, 
    SQL_VARCHAR, 32, 0, "_default", 18, 16) = SQL_SUCCESS
SQLExecute() = SQL_ERROR
SQLGetDiagRec(1) = SQL_SUCCESS
[SQLSTATE: HY000, NATIVE: 12704, MESSAGE: [Oracle][ODBC]
    [Ora]ORA-12704: character set mismatch]
SQLGetDiagRec(2) = SQL_NO_DATA

如果我使用 TO_NCHAR,没关系(但在 SQL Server、Postgres、SQLite 等中不起作用)。

SQLPrepare(SELECT (CASE profile WHEN TO_NCHAR(?) THEN 1 ELSE 2 END) AS profile_order
    FROM engine_properties;) = SQL_SUCCESS
SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_WCHAR, 
    SQL_VARCHAR, 32, 0, "_default", 18, 16) = SQL_SUCCESS
SQLExecute() = SQL_SUCCESS
SQLNumResultCols() = SQL_SUCCESS (count = 1)
SQLFetch() = SQL_SUCCESS

【问题讨论】:

    标签: oracle odbc oracle10g


    【解决方案1】:

    如果 Oracle 数据库字符集是 AL32UTF8,为什么列定义为 NVARCHAR2?这意味着您希望使用国家字符集(通常为 AL16UTF16,但在您的数据库上可能不同)对这些列进行编码。除非您主要存储亚洲语言数据(或其他需要在 AL32UTF8 中存储 3 个字节的数据),否则当数据库字符集支持 Unicode 时,在 Oracle 数据库中创建 NVARCHAR2 列相对不常见。

    一般来说,您最好坚持使用数据库字符集(CHAR 和 VARCHAR2 列)而不是尝试使用国家字符集(NCHAR 和 NVARCHAR2 列),因为需要跳过的箍要少得多通过事物的开发/配置方面。由于您不会通过选择 NVARCHAR2 数据类型来增加可以编码的字符集,因此我敢打赌,您会更喜欢 VARCHAR2 数据类型。

    【讨论】:

      【解决方案2】:

      谢谢贾斯汀。

      我仍然不能说我完全了解如何在 VARCHAR2 和 NVARCHAR2 之间进行选择。我曾尝试在我的约会中使用 VARCHAR2(其中确实包括许多不同的语言,包括欧洲和亚洲),但当时没有用。

      不过,我又玩了一会儿,发现使用贾斯汀的建议在这种组合中有效:

      • AL32UTF8 数据库字符集
      • VARCHAR2 列类型
      • 在启动 sqlplus.exe 之前设置 NLS_LANG=.UTF8
      • 使用 UTF-8 的数据文件(即包含所有 INSERT 语句的文件)
      • 使用 SQL_C_WCHAR 从数据库中插入和提取字符串

      我仍然觉得 Oracle 不像(例如)PostgreSQL 那样有趣...... :-)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-02
        • 2014-06-19
        • 1970-01-01
        • 2014-06-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多