简体   繁体   English

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

[英]What datatype should I bind as query parameter to use with NUMBER(15) column in Oracle ODBC?

I have just been bitten by issue described in SO question Binding int64 (SQL_BIGINT) as query parameter causes error during execution in Oracle 10g ODBC . 我刚刚被SO问题Binding int64(SQL_BIGINT)问题中描述的问题所困扰,因为查询参数在Oracle 10g ODBC中执行期间导致错误

I'm porting a C/C++ application using ODBC 2 from SQL Server to Oracle. 我正在将使用ODBC 2的C / C ++应用程序从SQL Server移植到Oracle。 For numeric fields exceeding NUMBER(9) it uses __int64 datatype which is bound to queries as SQL_C_SBIGINT. 对于超过NUMBER(9)的数字字段,它使用__int64数据类型,该数据类型作为SQL_C_SBIGINT绑定到查询。 Apparently such binding is not supported by Oracle ODBC. 显然,Oracle ODBC不支持这种绑定。 I must now do an application wide conversion to another method. 我现在必须在应用程序范围内将其转换为另一种方法。 Since I don't have much time---it's an unexpected issue---I would rather use proved solution, not trial and error. 由于我没有太多时间-这是一个意外的问题-我宁愿使用经过验证的解决方案,而不是反复试验。

What datatype should be used to bind as eg NUMBER(15) in Oracle? 在Oracle中应使用哪种数据类型进行绑定,例如NUMBER(15)? Is there documented recommended solution? 有记录的推荐解决方案吗? What are you using? 你在用什么 Any suggestions? 有什么建议么?

I'm especially interested in solutions that do not require any additional conversions. 我对不需要任何其他转换的解决方案特别感兴趣。 I can easily provide and consume numbers in form of __int64 or char* (normal non-exponential form without thousands separator or decimal point). 我可以轻松地以__int64或char *的形式提供和使用数字(正常的非指数形式,不带千位分隔符或小数点)。 Any other format requires additional conversion on my part. 任何其他格式都需要我进行其他转换。


What I have tried so far: 到目前为止我尝试过的是:

SQL_C_CHAR SQL_C_CHAR

Looks like it's going to work for me. 看起来这对我有用。 I was worried about variability of number format. 我担心数字格式的可变性。 But in my use case it doesn't seem to matter. 但是在我的用例中,这似乎并不重要。 Apparently only fraction point character changes with system language settings. 显然只有分数字符会随系统语言设置而变化。

And I don't see why I should use explicit cast (eg TO_NUMERIC) in SQL INSERT or UPDATE command. 而且我不明白为什么要在SQL INSERT或UPDATE命令中使用显式强制转换(例如TO_NUMERIC)。 Everything works fine when I bind parameter with SQL_C_CHAR as C type and SQL_NUMERIC (with proper precision and scale) as SQL type. 当我将参数SQL_C_CHAR绑定为C类型并将SQL_NUMERIC(具有适当的精度和小数位数)作为SQL类型绑定参数时,一切工作正常。 I couldn't reproduce any data corruption effect. 我无法重现任何数据损坏效果。

SQL_NUMERIC_STRUCT SQL_NUMERIC_STRUCT

I've noticed SQL_NUMERIC_STRUCT added with ODBC 3.0 and decided to give it a try. 我注意到ODBC 3.0中添加了SQL_NUMERIC_STRUCT,并决定尝试一下。 I am disappointed. 我很失望。

In my situation it is enough, as the application doesn't really use fractional numbers. 在我的情况下就足够了,因为该应用程序实际上并不使用分数。 But as a general solution... Simply, I don't get it. 但是作为一般解决方案...简单来说,我不明白。 I mean, I finally understood how it is supposed to be used. 我的意思是,我终于了解了应该如何使用它。 What I don't get is: why anyone would introduce new struct of this kind and then make it work this way . 我不明白的是: 为什么有人会引入这种新结构,然后使其以这种方式工作

SQL_NUMERIC_STRUCT has all the needed fields to represent any NUMERIC (or NUMBER, or DECIMAL) value with it's precision and scale. SQL_NUMERIC_STRUCT具有所有必需的字段,以其精度和小数位数表示任何NUMERIC(或NUMBER或DECIMAL)值。 Only they are not used. 只有它们不被使用。

When reading, ODBC sets precision of the number (based on precision of the column; except that Oracle returns bigger precision, eg 20 for NUMBER(15)). 读取时,ODBC设置数字的精度(基于列的精度;除了Oracle返回更大的精度,例如NUMBER(15)为20)。 But if your column has fractional part (scale > 0) it is by default truncated. 但是,如果您的列中有小数部分(小数位数> 0),则默认情况下会被截断。 To read number with proper scale you need to set precision and scale yourself with SQLSetDescField call before fetching data. 要以适当的比例读取数字,您需要设置精度并在获取数据之前通过SQLSetDescField调用自行缩放。

When writing, Oracle thankfully respects scale contained in SQL_NUMERIC_STRUCT. 编写时,Oracle值得庆幸的是遵守SQL_NUMERIC_STRUCT中包含的规模。 But ODBC spec doesn't mandate it and MS SQL Server ignores this value. 但是ODBC规范没有强制要求它,MS SQL Server忽略此值。 So, back to SQLSetDescField again. 因此,再次回到SQLSetDescField。

See HOWTO: Retrieving Numeric Data with SQL_NUMERIC_STRUCT and INF: How to Use SQL_C_NUMERIC Data Type with Numeric Data for more information. 有关更多信息,请参见HOWTO:使用SQL_NUMERIC_STRUCT检索数字数据INF:如何将SQL_C_NUMERIC数据类型与数字数据一起使用

Why ODBC doesn't fully use its own SQL_NUMERIC_STRUCT? 为什么ODBC无法完全使用其自己的SQL_NUMERIC_STRUCT? I don't know. 我不知道。 It looks like it works but I think it's just too much work. 看起来可行,但我认为这太繁琐了。


I guess I'll use SQL_C_CHAR. 我想我将使用SQL_C_CHAR。

My personal preference is to make the bind variables character strings (VARCHAR2), and let Oracle do the conversion from character to it's own internal storage format. 我个人的喜好是使绑定变量字符串(VARCHAR2),并让Oracle进行从字符到其自身内部存储格式的转换。 It's easy enough (in C) to get data values represented as null terminated strings, in an acceptable format. 很容易(用C语言)以可接受的格式获取以空终止字符串表示的数据值。

So, instead of writing SQL like this: 因此,与其像这样编写SQL:

SET MY_NUMBER_COL = :b1
  , MY_DATE_COL = :b2

I write the SQL like this: 我这样写SQL:

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

and supply character strings as the bind variables. 并提供字符串作为绑定变量。

There are a couple of advantages to this approach. 这种方法有两个优点。

One is that works around the issues and bugs one encounters with binding other data types. 一种是解决绑定其他数据类型时遇到的问题和错误。

Another advantage is that bind values are easier to decipher on an Oracle event 10046 trace. 另一个优点是,绑定值更容易在Oracle事件10046跟踪上破译。

Also, an EXPLAIN PLAN (I believe) expects all bind variables to be VARCHAR2, so that means the statement being explained is slightly different than the actual statement being executed (due to the implicit data conversions when the datatypes of the bind arguments in the actual statement are not VARCHAR2.) 另外,EXPLAIN PLAN(我相信)期望所有绑定变量都为VARCHAR2,因此这意味着所解释的语句与实际执行的语句略有不同(由于实际中的bind参数的数据类型为隐式数据转换,语句不是VARCHAR2。)

And (less important) when I'm testing of the statement in TOAD, it's easier just to be able to type in strings in the input boxes, and not have to muck with changing the datatype in a dropdown list box. 而且(不太重要),当我在TOAD中测试该语句时,能够在输入框中键入字符串会更容易,而不必在下拉列表框中更改数据类型就很麻烦了。

I also let the buitin TO_NUMBER and TO_DATE functions validate the data. 我还让buitin TO_NUMBER和TO_DATE函数验证数据。 (In earlier versions of Oracle at least, I encountered issues with binding a DATE value directly, and it bypassed (at least some of) the validity checking, and allowed invalid date values to be stored in the database. (至少在早期版本的Oracle中,我遇到了直接绑定DATE值的问题,并且它绕过了(至少是某些)有效性检查,并允许将无效的日期值存储在数据库中。

This is just a personal preference, based on past experience. 根据过去的经验,这只是个人喜好。 I use this same approach with Perl DBD. 我对Perl DBD使用相同的方法。

I wonder what Tom Kyte (asktom.oracle.com) has to say about this topic? 我想知道汤姆·基特(Tom Kyte)(asktom.oracle.com)对这个话题怎么说?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 用于在插入中测试参数(按数字)的ODBC API是一个标识列 - ODBC API to test of a parameter (by number) in an insert is an identity column 这是一个查找数字阶乘的程序。 为什么我得到0作为答案? 我应该改用哪种数据类型? - Here's a program to find the factorial of a number. Why am I getting 0 as the answer? Which datatype should I use instead? 是否应为多个连接使用单独的ODBC环境? - Should I use a seperate ODBC environment for multiple connections? 是否应将单个ODBC环境用于多个连接? - Should I use a single ODBC environment for multiple connections? PostgreSql查询中的参数数据类型出错 - Error with parameter datatype in PostgreSql query 如何通过本机ODBC绑定数组参数(存储过程) - How to bind an Array Parameter (Stored Procedure) via Native ODBC 我应该使用什么数据结构来计算超过50位长数字的阶乘? - What datastructure should I use to calculate the factorial of a more than 50 digits long number? 十进制数字应使用哪种c数据类型? - Which c datatype should be use for decimal numbers? 我应该使用哪种数据类型以C语言存储变量10 ^ 200? - which datatype should i use to store a variable 10^200 in C language? 我应该#include使用'htonl'? - What should I #include to use 'htonl'?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM