为什么Oracle在通过ODBC绑定SQL_C_WCHAR文本时需要TO_NCHAR

时间:2008-12-03 16:30:39

标签: oracle odbc oracle10g

我使用以下语句编写并绑定在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> describe engine_properties;
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 EID                                       NOT NULL NVARCHAR2(22)
 LID                                       NOT NULL NUMBER(11)
 PROFILE                                   NOT NULL NVARCHAR2(32)
 PKEY                                      NOT NULL NVARCHAR2(50)
 VALUE                                     NOT NULL NVARCHAR2(64)
 READONLY                                  NOT NULL NUMBER(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

2 个答案:

答案 0 :(得分:0)

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

通常,使用数据库字符集(CHAR和VARCHAR2列)而不是尝试使用国家字符集(NCHAR和NVARCHAR2列)可以更好地服务,因为需要跳转的环路要少得多通过开发/配置方面的事情。由于您没有增加可以通过选择NVARCHAR2数据类型进行编码的字符集,我会打赌您对VARCHAR2数据类型更满意。

答案 1 :(得分:0)

感谢贾斯汀。

我不能说我完全理解如何在VARCHAR2和NVARCHAR2之间进行选择。我曾尝试将VARCHAR2用于我的约会(其中包括许多不同的语言,包括欧洲和亚洲),并且它在那段时间没有用。

我再次玩了一遍,我发现使用Justin的建议可以在这个组合中使用:

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

我仍然觉得使用Oracle(例如)PostgreSQL虽然很有趣...: - )