How to reverse value of a clob data type in oracle sql? - sql

I want to reverse clob data type value in oracle in same way as we do for string data type fields with the help of 'reverse' function.Is there any inbuilt method for that.Google was not much help.Being a newbie in sql don't know whether it is even possible? I initially thought
that 'reverse' function can be used for clob data type fields also but its not working, here is the example I have tried-
drop table test;
create table test
(
name varchar2(4000),
description clob
)
insert into test values ('aadinath','I have to reverse a clob data type value')
select reverse(name) from test;
output= htanidaa
select reverse(name), reverse(description) from test;
output= ORA-00932: inconsistent datatypes: expected CHAR got CLOB
00932. 00000 - "inconsistent datatypes: expected %s got %s"

You need to convert clob to varchar2 first. Then perform the reverse.
Reference 1:
The Function to translate CLOB datatype into varchar() is DBMS_LOB. The DBMS_LOB package provides subprograms to operate on BLOBs, CLOBs, NCLOBs, BFILEs, and temporary LOBs. You can use DBMS_LOB to access and manipulation specific parts of a LOB or complete LOBs. DBMS_LOB can read and modify BLOBs, CLOBs, and NCLOBs; it provides read-only operations for BFILEs.
Syntax:
DBMS_LOB.SUBSTR (lob_loc, amount, offset)
dbms_lob.substr( clob_column, for_how_many_bytes, from_which_byte );
Parameter Description:
lob_loc: Locator for the LOB to be read i.e CLOB column name.
amount: Number of bytes (for BLOBs) or characters (for CLOBs) to be read.
offset: Offset in bytes (for BLOBs) or characters (for CLOBs) from the start of the LOB.
Example:
CREATE OR REPLACE VIEW temp_view
AS
SELECT
column1, -- datatype numeric
column2, -- datatype varchar()
DBMS_LOB.SUBSTR(column3, 2000,1) as column3, -- datatype CLOB
column4 -- datatype numeric
FROM temp_table;
Note: In this example I am reading first 2000 charactres.

Related

in Oracle database, how do I create a table of varchar2 type without length

for using it as a returning type in a function, I need to create a type at database level.
I do it by typing the command :
CREATE TYPE empno_tbl
IS TABLE OF VARCHAR2(100);
but this obliges me to choose a length.
I would like to create a string kind table type without a specific length.
is there a way to do this ?
If you really want it without a length then use CLOB.
CREATE TYPE empno_tbl IS TABLE OF CLOB;
(There is a limit but in Oracle 19c the CLOB datatype has a limit of 4GB * DB_BLOCK_SIZE initialization parameter, which gives a total size of 8 TB to 128 TB, and if you are reaching that limit then there is probably something wrong with your approach.)
The maximum size for a VARCHAR2 is 4000 bytes, so if you can cope with that limit then just use:
CREATE TYPE empno_tbl IS TABLE OF VARCHAR2(4000);

ORA-01481: invalid number format model in oracle insert query

I have below query where i am getting error as
ORA-01481: invalid number format model
The user is attempting to either convert a number to a string via TO_CHAR or a string
to a number via TO_NUMBER and has supplied an invalid number format model parameter.
I am using this query in stored procedure. The day_id column is number data type and the value stored in this column as YYYYMMDD. The month_id column is also number data type and i want to stored the value in this column as YYYYMM
INSERT INTO TEST_CHECK(MONTH_ID) VALUES
(to_char(REC.day_id, 'YYYYMM'));
You're applying a conversion to a number as if it was a date, trying to use the result (a string) as a number.
SQL> create table TEST_CHECK(MONTH_ID number);
Table created.
SQL> INSERT INTO TEST_CHECK(MONTH_ID) VALUES(to_char(20180101, 'YYYYMM'));
INSERT INTO TEST_CHECK(MONTH_ID) VALUES(to_char(20180101, 'YYYYMM'))
*
ERROR at line 1:
ORA-01481: invalid number format model
You may need something like:
SQL> INSERT INTO TEST_CHECK(MONTH_ID) VALUES(substr(to_char(20180101), 1, 6));
1 row created.
I would remember that storing dates and months in such a way is not a good idea.
Use
INSERT INTO TEST_CHECK(MONTH_ID) VALUES
(substr(REC.day_id, 1, 6));
instead, since both day_id and month_id are numbers.
If day_id were in date format you could make such a conversion to char but this not the case.
You may apply to_char conversion for REC.day_id as to_char(REC.day_id) but if there's no non-numeric character, oracle considers number as char implicitly without to_char, during a string operation such as substr.

Checking if the value inserted is a Varchar or an Integer

I'm using SQL Developer/Oracle and I need to check in a trigger if the the value inserted on a specific field is an integer or just a "string".
I tried isnumeric(), but this function doesn't exist in Oracle. What's the equivalent in Oracle since I can't find it anywhere?
From your last comment to the #Ben's answer
'1234' should be considered as a string and fail
it seems like you want to do a data type checking of a literal upon insertion and allow to insert only literals of numeric data types. Oracle does an implicit data type conversion when it makes sense. For example, you have a column of number data type in your table. When you try to insert a character literal '123' to that column, the operation will succeed despite the fact that the literal is of character data type(char, simple character literals are of CHAR data type not varchar2 by default), because Oracle takes a look at the data type of a column, then at data type and elements of the character literal and decides 'Yes, it makes sense to convert that character literal to a number.' and does it. As #Ben said , it probably would be better to let your application do the checking whether a value you are trying to insert into a table is of number or character data type.
Having said that, the probably simplest method to do a data type checking and allow to insert only literals or variables of numeric data types would be creating a package with one overloading function, say isnumber(). First version of the function has a formal parameter of varchar2 data type and its overloaded version has formal parameter of number data type. Depending on a data type of actual parameter Oracle will choose appropriate version of the function:
SQL> create or replace package Util1 as
2 function isnumber(p_val in varchar2)
3 return varchar2;
4 function isnumber(p_val in number)
5 return number;
6 end;
7 /
Package created
SQL> create or replace package body Util1 as
2 function isnumber(p_val in varchar2)
3 return varchar2 is
4 begin
5 raise_application_error(-20000, 'Not a numeric data type');
6 end;
7
8 function isnumber(p_val in number)
9 return number is
10 begin
11 return p_val;
12 end;
13 end;
14 /
Package body created
When you call util1.isnumber() function with actual parameter of numeric data type it simply returns it back, and when the function is called with an actual parameter of a character data type exception will be raised.
SQL> create table t1(col number);
Table created
SQL> insert into t1(col) values(util1.isnumber(123));
1 row inserted
SQL> commit;
Commit complete
SQL> insert into t1(col) values(util1.isnumber('123'));
ORA-20000: Not a numeric data type
ORA-06512: at "HR.UTIL1", line 5
SQL> insert into t1(col) values(util1.isnumber('12345f'));
ORA-20000: Not a numeric data type
ORA-06512: at "HR.UTIL1", line 5
Note This approach wont work in a trigger because of implicit data type conversion. In trigger you would have to do the following:
:new.col_name := util1.isnumber(:new.col_name)
As col_name is of number data type, Oracle will always call version of isnumber() function with formal parameter of number data type and insert will succeed even if actual value being inserted is (say) '123'.
I'm using an if. This means if the value inserted is varhchar I will raise an application error, otherwise I will do nothing.
When you insert a character into a numeric field you'll get an "invalid number" exception raised (ORA-01722). This makes your choice easier; don't test to see if the string you're inserting is a character. Capture the raised exception when a user inserts a character into a numeric field and re-raise as an application error (if you really feel you have to).
There's then no need to test at all.
For example:
create table test ( a number );
begin
insert into test values ('a');
exception when INVALID_NUMBER then
raise_application_error(-20000, 'The number wasn''t a number');
end;
/
It's worth noting that you could also test if something's a number in your application code (if it's an application). You wouldn't have to do the round trip to the database then.

collect function on clobs

I need to select several clobs as a nested table.
create table t (vc_val varchar2(100), clob_val clob);
create type varchar_t as table of varchar2(100);
create type clob_t as table of clob;
Following query works fine:
select cast(collect(vc_val) as varchar_t) from t;
And following fails, why?
select cast(collect(clob_val) as clob_t) from t;
Link to this example http://sqlfiddle.com/#!4/b01e7/3
Can someone explain me why second query fails?
It doesn't work because CAST doesn't support LOB types.
You can read about this in Oracle's Documentation: CAST Function In Oracle
Using your test data from SQLFiddle, CAST can convert a CLOB to a VARCHAR2:
SELECT CAST(clob_val AS VARCHAR2(100)) FROM t;
Result:
CAST(CLOB_VALASVARCHAR2(100))
-----------------------------
clob1
clob2
But we can't do it the other way around, the CLOBs are just not supported:
SELECT CAST(vc_val AS CLOB) FROM t;
> 00932. 00000 - "inconsistent datatypes: expected %s got %s"
CREATE OR REPLACE TYPE t_clob_tab as table of clob;
declare
l_clob_tab t_clob_tab;
begin
-- collect some data as clobs into a nested table
select
cast(multiset(
select to_clob(object_name)
from dba_objects
where rownum <= 10)
as t_clob_tab)
into l_clob_tab
from dual;
-- show the data
for i in 1 .. l_clob_tab.count
loop
dbms_output.put_line('Clob' || i || ' Value is: ' || l_clob_tab(i));
end loop;
end;
Output:
Clob1 Value is: C_OBJ#
Clob2 Value is: I_OBJ#
Clob3 Value is: TAB$
Clob4 Value is: CLU$
Clob5 Value is: C_TS#
Clob6 Value is: I_TS#
Clob7 Value is: C_FILE#_BLOCK#
Clob8 Value is: I_FILE#_BLOCK#
Clob9 Value is: C_USER#
Clob10 Value is: I_USER#
As for the CAST function support for LOB types:
CAST does not directly support any of the LOB data types. When you use
CAST to convert a CLOB value into a character data type or a BLOB
value into the RAW data type, the database implicitly converts the LOB
value to character or raw data and then explicitly casts the resulting
value into the target data type. If the resulting value is larger than
the target type, then the database returns an error.
This seems to refer to converting from a CLOB -> Varchar. But if you already have Clobs, you should be able to put them into a collection (a nested table in this case).
I typically use CAST + MULTISET instead of COLLECT, I think its easier and less fussy. I think your problem is with COLLECT + CAST here, not CAST itself (similar issue with NUMBER precisions).
EDIT:
I removed any suggestion of using Collect function, although I could use it without error in a simple select, I could not use it in pl/sql. Also, in addition to the CAST + MULTISET option above (SQL or pl/sql), you can (in pl/sql anyway) simply do:
select clob_col
bulk collect into l_clob_tab
from t;
Hope that helps.

How to interpret ALL_TAB_COLS.DATA_LENGTH = 4000 for Oracle's CLOB types?

When I create a table with a CLOB in it, the CLOB column is reported to have a DATA_LENGTH of 4000:
create table test (
data clob
);
-- Returns 4000
select data_length from all_tab_cols
where table_name = 'TEST';
How can I interpret that? Is that some backwards-compatible tweak, considering that the limit for VARCHAR2 is also 4000? Or is this to indicate that I can only insert / update string literals of length 4000? Is this behaviour of SYS.ALL_TAB_COLS documented somewhere?
Up to 4000 bytes can be stored in-line in the tablespace. If the length of the CLOB exceeds 4000 bytes it must be stored in/readed from LOB storage area via special functions.
See also:
http://www.dba-oracle.com/t_blob.htm
http://www.dba-oracle.com/t_table_blob_lob_storage.htm