我应该将哪种数据类型绑定为查询参数以与Oracle ODBC中的NUMBER(15)列一起使用?

时间:2010-07-15 18:00:49

标签: c oracle odbc

我刚刚被问题Binding int64 (SQL_BIGINT) as query parameter causes error during execution in Oracle 10g ODBC中描述的问题所困扰。

我正在使用ODBC 2从SQL Server移植到Oracle的C / C ++应用程序。对于超过NUMBER(9)的数字字段,它使用__int64数据类型,该数据类型作为SQL_C_SBIGINT绑定到查询。显然,Oracle ODBC不支持这种绑定。我现在必须进行应用程序范围的转换到另一种方法。由于我没有太多时间 - 这是一个意想不到的问题 - 我宁愿使用经证实的解决方案,而不是反复试验。

应使用什么数据类型进行绑定,例如Oracle中的NUMBER(15)?是否有建议的解决方案?你在用什么?有什么建议吗?

我对不需要任何额外转换的解决方案特别感兴趣。我可以轻松提供和使用__int64或char *形式的数字(正常的非指数形式,没有千位分隔符或小数点)。任何其他格式都需要我的额外转换。


到目前为止我尝试过:

SQL_C_CHAR

看起来它对我有用。我担心数字格式的可变性。但在我的用例中似乎并不重要。显然只有分数点字符随系统语言设置而变化。

我不明白为什么我应该在SQL INSERT或UPDATE命令中使用显式强制转换(例如TO_NUMERIC)。当我将SQL_C_CHAR作为C类型和SQL_NUMERIC(具有适当的精度和比例)作为SQL类型绑定参数时,一切正常。我无法重现任何数据损坏效果。

SQL_NUMERIC_STRUCT

我注意到SQL_NUMERIC_STRUCT添加了ODBC 3.0并决定尝试一下。我很失望。

在我的情况下,这已经足够了,因为应用程序并不真正使用小数。但作为一般解决方案......简单地说,我不明白。我的意思是,我终于理解了应该如何使用它。我没有得到的是:为什么有人会引入这种新结构,然后以这种方式工作

SQL_NUMERIC_STRUCT具有表示任何NUMERIC(或NUMBER或DECIMAL)值及其精度和比例的所有必需字段。只有它们不被使用。

在读取时,ODBC设置数字的精度(基于列的精度;除了Oracle返回更高的精度,例如对于NUMBER(15)为20)。但是,如果您的列具有小数部分(比例> 0),则默认情况下将其截断。要以适当的比例读取数字,您需要在获取数据之前使用SQLSetDescField调用设置精度并自行调整。

在编写时,感谢Oracle尊重SQL_NUMERIC_STRUCT中包含的扩展。但ODBC规范并未强制要求它,MS SQL Server会忽略此值。所以,再次回到SQLSetDescField。

有关详细信息,请参阅HOWTO: Retrieving Numeric Data with SQL_NUMERIC_STRUCTINF: How to Use SQL_C_NUMERIC Data Type with Numeric Data

为什么ODBC没有完全使用自己的SQL_NUMERIC_STRUCT?我不知道。看起来它有效,但我认为这只是太多的工作。


我想我会使用SQL_C_CHAR。

1 个答案:

答案 0 :(得分:2)

我个人的偏好是制作绑定变量字符串(VARCHAR2),让Oracle从字符转换到它自己的内部存储格式。很容易(在C中)以可接受的格式获得表示为空终止字符串的数据值。

所以,不要像这样编写SQL:

SET MY_NUMBER_COL = :b1
  , MY_DATE_COL = :b2

我像这样编写SQL:

SET MY_NUMBER_COL = TO_NUMBER( :b1 )
  , MY_DATE_COL   = TO_DATE( :b2 , 'YYYY-MM-DD HH24:MI:SS')

并提供字符串作为绑定变量。

这种方法有几个好处。

其中一个是解决与绑定其他数据类型时遇到的问题和错误。

另一个优点是绑定值更容易在Oracle事件10046跟踪上解密。

另外,EXPLAIN PLAN(我相信)期望所有绑定变量都是VARCHAR2,这意味着所解释的语句与正在执行的实际语句略有不同(由于绑定参数的数据类型时隐式数据转换)在实际语句中不是VARCHAR2。)

而且(不太重要)当我在TOAD中测试语句时,只需在输入框中键入字符串就更容易了,而不必在下拉列表框中更改数据类型。 / p>

我还让buitin TO_NUMBER和TO_DATE函数验证数据。 (至少在早期版本的Oracle中,我遇到了直接绑定DATE值的问题,并绕过了(至少某些)有效性检查,并允许无效的日期值存储在数据库中。

根据过去的经验,这只是个人偏好。我使用与Perl DBD相同的方法。

我想知道Tom Kyte(asktom.oracle.com)对这个话题有什么看法?