Re: [cx-oracle-users] Types used for values returned from a query
Brought to you by:
atuining
|
From: Paul M. <p.f...@gm...> - 2005-02-10 19:34:59
|
On Thu, 10 Feb 2005 07:50:11 -0700, Anthony Tuininga
<an...@co...> wrote:
> > Quite possibly. I can just bind the variable as a String in Java, and
> > then load it into a Number column, I guess. Could there be any format
> > issues (exponential formats, commas in numbers, etc)? I only ask
> > because the environemnt makes it annoyingly hard to report errors, so
> > when things go wrong it's a real pain to debug :-(
>
> Not certain. Since I've only dumped it for future import into an Oracle
> database that hasn't been an issue for me. You'll have to try -- you can
> find out what happens by simply issuing "to_char(number)" on any number
> you would care to and looking at the resulting string.
I tried it out, and it works perfectly. Thanks for the pointer. But
(see below) the result isn't always the same as to_char() gives, in
the presence of NLS parameters...
> > That may be an option, but frankly, this is pretty specialised use
> > where an exact representation is crucial. Maybe just having a way of
> > saying that a specific column in a query must be returned as a string,
> > and then doing string->Decimal in Python would be suitable. Something
> > like
[...]
> > All I really care about is having some way of being sure that there's
> > no precision loss - using strings does it, the rest is just
> > convenience (only using strings where it's really needed).
> >
> > Sorry - must dash, but I hope you get the idea...
>
> I do and I've considered something similar. Perhaps a
> cursor.define(position, data_type) which would allow you to override the
> default retrieve definition. In your example the call would be
> "c.define(1, cx_Oracle.STRING)". I suspect it would have to take place
> before the execute() call, though. Comments, anyone?
That looks fine. In practice, though, for my requirement,
OPT_NumbersAsStrings is perfectly adequate. As things stand, I don't
have a use for anything finer grained, and the only example I can
think of is using a string to allow me to construct a Decimal without
loss of precision. It would probably be worth having some additional
use cases before expending much effort on this :-)
One question that does come up is that of format. My application was
basically like yours - dump the numbers to strings so that you can
later load the strings back into the database. As this is
Oracle->Oracle, no format issue arises. However, if you want to use
the results elsewhere, you'd need to define the format. A check of the
Oracle OCI documentation wasn't clear to me so I did some
experimenting. It *looks* like the format is
<digits>.<digits>E<sign><digits>
with the .<digits> and the E<sign><digits> parts optional. But it's
not affected by NLS_NUMERIC_CHARACTERS, which is probably good...
OK, I'm overdoing this now. But the point remains that ultimately use
of OPT_NumbersAsStrings and any column-level equivalent is going to
hit a need to be sure what the valid formats are. Oracle's
documentation isn't very clear on this, and expecting Python
programmers to have a good understanding of OCI is probably expecting
a bit too much.
Hmm, actually it may not even be roundtrip-safe. Try this:
>>> cn = cx_Oracle.connect("scott/tiger")
>>> cx_Oracle.OPT_NumbersAsStrings = 1
>>> c = cn.cursor()
>>> c.execute("select 123456/100 from dual")
[<NumberVar object at 0x00973ED0>]
>>> n, = c.fetchone()
>>> n
'1234.56'
>>> c.execute("create table t (n number)")
>>> c.execute("insert into t values (:a)", a=n)
>>> c.execute("alter session set NLS_NUMERIC_CHARACTERS=',.'")
>>> c.execute("select 123456/100 from dual")
[<NumberVar object at 0x00973ED0>]
>>> n, = c.fetchone()
>>> n
'1234.56'
>>> c.execute("insert into t values (:a)", a=n)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
cx_Oracle.DatabaseError: ORA-01722: invalid number
>>>
Ick. This is getting complicated...
Well, it works for me. So this is not something I'm going to lose sleep over :-)
Paul.
|