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

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);

Related

Substr with more than 4000 characters gets ORA-06502: PL/SQL: numeric or value error

In the below script if I try to substr for 4000 character it works and displays all text in my particular ID with respective DB field ID and Language, if I increase it even 4001 db pops up the error - ora-06502: pl/sql: numeric or value error.
Create or replace function GET_AER_TEXT5(M_AER_ID IN NUMBER,
F_ID IN VARCHAR2,PREF_LANGUAGE IN VARCHAR2)
IS
AERTEXT VARCHAR2(32000);
LANG_PARAM VARCHAR2(2000);
AER_CLOB CLOB;
BEGIN
FOR c1 IN (
select TEXT from AER_TEXT
where FIELD_ID=F_ID and AER_ID=M_AER_ID and LANGUAGE IN(PREF_LANGUAGE)
)
LOOP
IF c1.text IS NOT NULL THEN
AER_CLOB:=AER_CLOB || c1.text;
END IF;
END LOOP;
AERTEXT:=substr(AER_CLOB,1,4000);
RETURN(AERTEXT);
END;
Importance of increasing this to more than 4000 is to pull complete text data. If the DB column contains more than 4K character it doesn’t work.
I'm calling it with:
select AER_ID,GET_AER_TEXT5(AER_ID,at,field_id,'001')
from AER a,AER_TEXT AT
where AT.field_ID=12345 and a.aer_id=at.aer_id;
Can you please advise how to get rid of this issue.
Prior to Oracle 12c Oracle only allows 4000 bytes in a varchar2 value in an SQL context. You are allowed 32k in PL/SQL, so your function is sort of OK as it stands, even with the substrng getting the first 4001 characters; but only if you call it from PL/SQL. When you try to call it from SQL:
select AER_ID,GET_AER_TEXT5(AER_ID,at,field_id,'001') ...
... you're trying to assign a 4001-character value to the implicit SQL column in the return statement, and that is causing the error you are seeing.
You can either change your SAP call to use a PL/SQL context and a bind variable to get the return value, though you'll still be limited to 32k; or change your function to keep value as a CLOB, which makes the function a bit pointless as you can just get the value from the table. I'm not familiar with SAP so I'm not quite sure how you'd end up coding either approach.

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 reverse value of a clob data type in oracle 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.

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

How do I get textual contents from BLOB in Oracle SQL

I am trying to see from an SQL console what is inside an Oracle BLOB.
I know it contains a somewhat large body of text and I want to just see the text, but the following query only indicates that there is a BLOB in that field:
select BLOB_FIELD from TABLE_WITH_BLOB where ID = '<row id>';
the result I'm getting is not quite what I expected:
BLOB_FIELD
-----------------------
oracle.sql.BLOB#1c4ada9
So what kind of magic incantations can I do to turn the BLOB into it's textual representation?
PS: I am just trying to look at the content of the BLOB from an SQL console (Eclipse Data Tools), not use it in code.
First of all, you may want to store text in CLOB/NCLOB columns instead of BLOB, which is designed for binary data (your query would work with a CLOB, by the way).
The following query will let you see the first 32767 characters (at most) of the text inside the blob, provided all the character sets are compatible (original CS of the text stored in the BLOB, CS of the database used for VARCHAR2) :
select utl_raw.cast_to_varchar2(dbms_lob.substr(BLOB_FIELD)) from TABLE_WITH_BLOB where ID = '<row id>';
SQL Developer provides this functionality too :
Double click the results grid cell, and click edit :
Then on top-right part of the pop up , "View As Text" (You can even see images..)
And that's it!
You can use below SQL to read the BLOB Fields from table.
SELECT DBMS_LOB.SUBSTR(BLOB_FIELD_NAME) FROM TABLE_NAME;
Use this SQL to get the first 2000 chars of the BLOB.
SELECT utl_raw.cast_to_varchar2(dbms_lob.substr(<YOUR_BLOB_FIELD>,2000,1)) FROM <YOUR_TABLE>;
Note: This is because, Oracle will not be able to handle the conversion of BLOB that is more than length 2000.
If you want to search inside the text, rather than view it, this works:
with unzipped_text as (
select
my_id
,utl_compress.lz_uncompress(my_compressed_blob) as my_blob
from my_table
where my_id='MY_ID'
)
select * from unzipped_text
where dbms_lob.instr(my_blob, utl_raw.cast_to_raw('MY_SEARCH_STRING'))>0;
I can get this to work using TO_CLOB (docs):
select
to_clob(BLOB_FIELD)
from
TABLE_WITH_BLOB
where
ID = '<row id>';
This works for me in Oracle 19c, with a BLOB field which larger the the VARCHAR limit. I get readable text (from a JSON-holding BLOB)
Barn's answer worked for me with modification because my column is not compressed. The quick and dirty solution:
select * from my_table
where dbms_lob.instr(my_UNcompressed_blob, utl_raw.cast_to_raw('MY_SEARCH_STRING'))>0;
I struggled with this for a while and implemented the PL/SQL solution, but later realized that in Toad you can simply double click on the results grid cell, and it brings up an editor with contents in text. (i'm on Toad v11)
In case your text is compressed inside the blob using DEFLATE algorithm and it's quite large, you can use this function to read it
CREATE OR REPLACE PACKAGE read_gzipped_entity_package AS
FUNCTION read_entity(entity_id IN VARCHAR2)
RETURN VARCHAR2;
END read_gzipped_entity_package;
/
CREATE OR REPLACE PACKAGE BODY read_gzipped_entity_package IS
FUNCTION read_entity(entity_id IN VARCHAR2) RETURN VARCHAR2
IS
l_blob BLOB;
l_blob_length NUMBER;
l_amount BINARY_INTEGER := 10000; -- must be <= ~32765.
l_offset INTEGER := 1;
l_buffer RAW(20000);
l_text_buffer VARCHAR2(32767);
BEGIN
-- Get uncompressed BLOB
SELECT UTL_COMPRESS.LZ_UNCOMPRESS(COMPRESSED_BLOB_COLUMN_NAME)
INTO l_blob
FROM TABLE_NAME
WHERE ID = entity_id;
-- Figure out how long the BLOB is.
l_blob_length := DBMS_LOB.GETLENGTH(l_blob);
-- We'll loop through the BLOB as many times as necessary to
-- get all its data.
FOR i IN 1..CEIL(l_blob_length/l_amount) LOOP
-- Read in the given chunk of the BLOB.
DBMS_LOB.READ(l_blob
, l_amount
, l_offset
, l_buffer);
-- The DBMS_LOB.READ procedure dictates that its output be RAW.
-- This next procedure converts that RAW data to character data.
l_text_buffer := UTL_RAW.CAST_TO_VARCHAR2(l_buffer);
-- For the next iteration through the BLOB, bump up your offset
-- location (i.e., where you start reading from).
l_offset := l_offset + l_amount;
END LOOP;
RETURN l_text_buffer;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('!ERROR: ' || SUBSTR(SQLERRM,1,247));
END;
END read_gzipped_entity_package;
/
Then run select to get text
SELECT read_gzipped_entity_package.read_entity('entity_id') FROM DUAL;
Hope this will help someone.
You can try this:
SELECT TO_CHAR(dbms_lob.substr(BLOB_FIELD, 3900)) FROM TABLE_WITH_BLOB;
However, It would be limited to 4000 byte
Worked for me,
select lcase((insert(
insert(
insert(
insert(hex(BLOB_FIELD),9,0,'-'),
14,0,'-'),
19,0,'-'),
24,0,'-'))) as FIELD_ID
from TABLE_WITH_BLOB
where ID = 'row id';
Use TO_CHAR function.
select TO_CHAR(BLOB_FIELD) from TABLE_WITH_BLOB where ID = '<row id>'
Converts NCHAR, NVARCHAR2, CLOB, or NCLOB data to the database character set. The value returned is always VARCHAR2.