OCI: Determine length of text representation of query columns - oracle

My goal is to execute a query (SELECT), fetch results and output them as text. Query is given as a parameter and can be e.g. select * from t.
I use OCIStmtPrepare and OCIStmtExecute, then I can describe columns of the query by OCIParamGet and series of OCIAttrGet. Suppose I get OCI_ATTR_DATA_TYPE = 12 (DATE) for one of the columns. Then OCI_ATTR_DATA_SIZE = 7 -- this is size of internal DATE representation.
I want to get this DATE as text, with respect to currect NLS settings. For that I use OCIDefineByPos with dty = SQLT_STR. It works alright, but I also need to supply a buffer for fetching. The question is: what size of buffer do I need?
Evidently it depends on NLS_DATE_FORMAT. I believe that Oracle knows this value:
SQL> create table x as select to_char(sysdate) d from dual;
Table created.
SQL> select value from nls_session_parameters where parameter='NLS_DATE_FORMAT';
VALUE
----------------------------------------
DD.MM.RR
SQL> select data_length from dba_tab_columns where table_name='X';
DATA_LENGTH
-----------
8
This is the exact length. Only when date format is masked from Oracle (by a function, for example), it uses absolute maximum (?) value of 75:
SQL> create or replace function get_date_format return varchar2 is
2 begin
3 return 'DD.MM.RR';
4 end;
5 /
Function created.
SQL> create table x as select to_char(sysdate,get_date_format) d from dual;
Table created.
SQL> select data_length from dba_tab_columns where table_name='X';
DATA_LENGTH
-----------
75
All said above applies to NUMBER as well.
So, is it possible to get length of text representation of a column in OCI?

The maximum buffer size for any date is 75. The maximum buffer size for any number is 42.
I hope that helps.

You can determine needed buffer size by calling OCIAttrGet for OCI_ATTR_DISP_SIZE attribute. It returns 40 for NUMBER, 75 for DATE, N for VARCHAR2(N). Add 1 byte for Null-termination and you good to go.

Yes - the trick is that in C, a string is really a pointer to a character array, so you would say char* mystring = OCIStringPtr(envhp, x); where x is a pointer to an OCIString, which you can get back by connecting with OCI_OBJECT set and asking for a SQLT_VST instead of an SQLT_STR. The actual memory for the string is allocated for you in the global env by OCI behind the scenes.

Related

when we declared number datatype in oracle what it will take default data type?

I was declared one column in oracle datatype is number ex:cust_acc_no NUMBER (9) DEFAULT (0),.
After creating table that column take double datatype why?
but that column is account number so when i select that particular field it shows account numbers with decimal.
If you didn't put any decimal numbers into it, then they aren't decimal numbers. If you think they are, please, post an example - copy/paste your SQL*Plus session which shows what you're saying. I suspect that it is matter of formatting, not data storage.
By the way, you could have used the INT datatype, e.g.
SQL> create table test (cust_acc_no int default 0);
Table created.
SQL> insert into test
2 select 100 from dual union
3 select 0.5 from dual union
4 select 20.6 from dual;
3 rows created.
SQL> select * from test;
CUST_ACC_NO
-----------
1
21
100
SQL>

Oracle vs HANA char data type handling

We have Oracle as source and HANA 1.0 sps12 as target. We are mirroring Oracle to HANA with Informatica CDC through real-time replication. In Oracle, for many columns we have datatype as CHAR i.e. fixed length datatype. As HANA officially doesn't support CHAR datatype so we are using NVARCHAR data type instead of same. Problem we are facing is -as in Oracle CHAR datatype is of fixed length and append spaces whenever actual string is of lesser length than datatype, we have lot of extra spaces in target HANA db for such columns.
For eg. If column col1 has data type
CHAR(5)
and value as 'A', it is replicated in HANA as 'A ' i.e. 'A' appended by four extra spaces, causing lot of problems in queries and data interpretation
Is it possible to implement CHAR like datatype in HANA?
You can use RPAD function in Informatica while transferring data to Hana. Just make sure if Hana doesn't trim automatically.
So, for the CHAR(5) source column you should use:
out_Column = RPAD(input_Column, 5)
Pretty much exactly, as the documentation says:
I don't know HANA and this is more a comment than an answer, but I chose to put it here as there's some code I'd like you to see.
Here's a table whose column is of a CHAR datatype:
SQL> create table test (col char(10));
Table created.
SQL> insert into test values ('abc');
1 row created.
Column's length is 10 (which you already know):
SQL> select length(col) from test;
LENGTH(COL)
-----------
10
But, if you TRIM it, you get a better result, the one you're looking for:
SQL> select length( TRIM (col)) from test;
LENGTH(TRIM(COL))
-----------------
3
SQL>
So: if you can persuade the mirroring process to apply TRIM function to those columns, you might get what you want.
[EDIT, after seeing Lars' comment and re-reading the question]
Right; the problem seems to be just the opposite of what I initially understood. If that's the point, maybe RPAD would help. Here's an example:
SQL> create table test (col varchar2(10));
Table created.
SQL> insert into test values ('abc');
1 row created.
SQL> select length(col) from test;
LENGTH(COL)
-----------
3
SQL> insert into test values (rpad('def', 10, ' '));
1 row created.
SQL> select col, length(col) len from test;
COL LEN
---------- ----------
abc 3
def 10
SQL>

Oracle Precision

I want a number to take values between -7.2E-75 to +7.2E+75. How should I specify precision and scale for the NUMBER. (The scale range is 1 to 38 and precision is -84 to 127).
If there is any other way to accomplish this please suggest.
The numeric values you propose are well within the limits of the Oracle NUMBER datatype.
Do you need to specify a precision? Defining a column as just NUMBER is allowed:
SQL> desc t1
Name Null? Type
----------------------------------------- -------- ----------------------------
COL1 NUMBER
COL2 NUMBER
COL3 NUMBER
COL4 NUMBER
SQL> insert into t1 (col1, col2) values ( -7.2E-75, +7.2E+75);
1 row created.
SQL>
If it's the range bounds which are bothering you, you need to define a CHECK constraint to enforce the rule.
"Suppose i want COL1 to take 123456766675544.344546567676, with NUMBER as datatype its failing"
Failing? How? That value works fine for me (same table as before):
SQL> insert into t1 (col1) values ( 123456766675544.344546567676);
1 row created.
SQL>
So, please provide more details, such as the error message.
"When i fire the above query it is showing just 123456766675544,"
That sounds like a display issue. The right values are being inserted. Check this out:
SQL> set numwidth 50
SQL> select col1 from t1
/
2
COL1
--------------------------------------------------
7.20000000000000000000000000000000000000000000E+75
123456766675544.344546567676
SQL>
In this case, setting the NUMWIDTH to its maximum allowed value ( in SQL*plus) allows us to display one value but the other is still too big, and so we have to use scientific notation.

How to show star at first two character of a string in oracle query?

Example if an ID is 1213 i want show **13.
If it's a number
select '**' || substr(to_char(id),3)
from my_table
Or, if it's already a character
select '**' || substr(id,3)
from my_table
This concatenates ** onto the beginning of the string, using the Oracle concatenation operator || and removes the first two characters of the id using substr.
Here's a SQL Fiddle to demonstrate.
If you don't want to sacrifice performance too much, to mask first two characters you can use-
SQL> select regexp_replace('1213','(.)2','**') from dual; --if VARCHAR
MASKED
------------
**13
SQL> select regexp_replace(1213,'(.)2','**') from dual; --if NUMBER
MASKED
------------
**13
REGEXP_REPLACE will work alike on NUMBER and VARCHAR so you save some conversion time there.
Consecutively, you can create a Function Based Index on the regexp function operation to optimize the query like (considering you would always want to mask only first two characters of ID) -
CREATE INDEX
mask_id
ON
table_name
(regexp_replace(id,'(.)2','**'));

Oracle Number data type and its strictness

I'm very new to oracle but I've been learning about it in class and I've recently come across the number data type. I've read the documentation regarding scale and precision (s,p) but I still am not positive regarding the type's proper usage.
Let's say I want to store percent values as a decimal. The decimal can be anywhere from 0 to 1 and may have up to 3 numbers following the decimal place.
Some possible decimals to be stored may include:
.66
.553
1.00
If I were to make the column NUMBER(4,3) would that work EVEN IF there were only two numbers? See below
.22
.10
.35
etc...
In short, does the number type require that the EXACT sizes are met? Eg. Would NUMBER(4,3) ABSOLUTELY REQUIRE that the data inserted is 4 numbers, 3 of them falling after the decimal place?
Thanks for the help!
Data types for columns limit the range of values that can be stored. But they don't do anything to force a particular length or precision.
Just like you can store a single character or a NULL in a VARCHAR2(100) column, you can store numbers with less than 3 digits of precision and less than 4 digits of scale. For example, the values 0 and 6.1 are both perfectly valid for a NUMBER(4,3) column. If you insert a value that has too many digits of precision, the value will be silently rounded to the precision specified in the column definition.
SQL> create table foo (
2 col1 number(4,3)
3 );
Table created.
SQL> insert into foo values( 9.999 );
1 row created.
SQL> insert into foo values (0);
1 row created.
SQL> insert into foo values( 6.1 );
1 row created.
SQL> insert into foo values( 1.2345 );
1 row created.
SQL> select * from foo;
COL1
----------
9.999
0
6.1
1.235

Resources