Need help in converting and validating XMLType in Oracle SQL Table - sql

So the scenario here is data is coming from an external system to oracle database.
I need to convert CLOB datatype to XMLTYPE and validate the XMLTYPE field in a table.
If the validation or conversion fails, i need to push this record in another table. How can i achieve this.
I tried using XMLTYPE function and XMLISVALID function but i keep getting errors.

You could use WITH FUNCTION:
CREATE TABLE t(id INT, x CLOB);
INSERT INTO t(id, x) VALUES(1, '<root/>');
INSERT INTO t(id, x) VALUES(2, '<root></root>');
INSERT INTO t(id, x) VALUES(3, '<root><a></root>'); -- incorrect XML
Checking if content of column is valid XML:
WITH FUNCTION func(col CLOB) RETURN NUMBER
AS
x XMLTYPE;
BEGIN
x := XMLTYPE(col);
RETURN 1;
EXCEPTION WHEN OTHERS THEN
RETURN 0;
END;
SELECT *
FROM t
WHERE func(x) = 1; -- get only valid XML
-- WHERE func(x) = 0; -- get invalid XML
db<>fiddle demo

Related

Can't save comma separated number string in varchar2()

I've got a list of items I want to add in a single click, for this purpose I created a table with a column with a type varchar2(4000), in this column I want to list id's that refer to the other table so I can paste the value of this column as a parameter. ex. select t.* from table_name t where t.point_id in (varchar2 string of comma seprated point_ids).
The problem I've got is that when I put more than 1 id in the varchar2 field I get ORA-06502: PL/SQL: numeric or value error: character to number conversion error
How can I avoid this error? My field is varchar2, not number and I don't want it to be converted. I need the value I'm parsing to be saved. ex. (11, 12)
Picture of my Table:
EDIT: Note - My select is working okay, the problem I'm having is with saving the information.
My Insert :
procedure lab_water_pointsgroup (v_group_id lab_water_pointsgroups.group_name%type,
v_group_name lab_water_pointsgroups.group_code%type,
v_group_code lab_water_pointsgroups.lab_points_ids%type,
v_lab_points_ids lab_water_pointsgroups.group_id%type) as
begin
update lab_water_pointsgroups
set group_name = v_group_name,
group_code = v_group_code,
lab_points_ids = v_lab_points_ids
where group_id = v_group_id;
if ( SQL%RowCount = 0 ) then
insert into lab_water_pointsgroups
(group_id, group_name, group_code, lab_points_ids)
values
(v_group_id, v_group_name, v_group_code, v_lab_points_ids);
end if;
end;
Not sure how exactly I can help you here as you gave no example. Have a look at the below demo, maybe the contruct with xmltable solves your problem. HTH KR
create table testtab (id number);
insert into testtab values (1);
select * from testtab where id in ('1'); -- works
select * from testtab where id in (1); -- works
select * from testtab where id in (1,2); -- works
select * from testtab where id in ('1,2'); -- ORA-01722: invalid number
select * from testtab where id in (select to_number(xt.column_value) from xmltable('1,2') xt); -- works
Here is how you defined parameters for your procedure:
v_group_id lab_water_pointsgroups.group_name%type,
v_group_name lab_water_pointsgroups.group_code%type,
v_group_code lab_water_pointsgroups.lab_points_ids%type,
v_lab_points_ids lab_water_pointsgroups.group_id%type
I suspect that you made mistake with types, because id has name type, name has code type etc. So it should be:
v_group_id lab_water_pointsgroups.group_id%type,
v_group_name lab_water_pointsgroups.group_name%type,
v_group_code lab_water_pointsgroups.group_code%type,
v_lab_points_ids lab_water_pointsgroups.lab_points_ids%type
And I suggest to use merge instead of this update / insert, but it's not what you asked for :)
Your error is in that you don't make difference between variable containing comma separated numbers and actual enumeration in the 'in' operator. After your code analize and preparation to execution your statement will be like .. id in ('1,2,3') instead of ..id in (1,2,3), did you notice differnce ? So you need to transform comma separated values into array or in this case into collection. Your code should be like this:
select t.*
from table_name t
where t.point_id in
(select regexp_substr(YOUR_VARCHAR2_COLUMN_VALUE, '[^,]+', 1, level)
from dual
connect by regexp_substr(YOUR_VARCHAR2_COLUMN_VALUE, '[^,]+', 1, level) is not null)

Circular Dependency -Table Insertion Error

I want to insert data into table but got below error..Can any one help me..
CREATE OR REPLACE TYPE TEST_TYP FORCE IS OBJECT
("id" VARCHAR(5000 NULL)
NOT FINAL;
CREATE OR REPLACE TYPE TEST_TAB is table of REF TEST_TYP;
CREATE OR REPLACE TYPE TEST1_TYP FORCE IS OBJECT
("id" VARCHAR2(500) NULL,
"extension" "TEST_TAB" NULL )
NOT FINAL;
CREATE TABLE "TEST_OBJ_TABLE" OF "TEST1_TYP"
NESTED TABLE "extension" STORE AS "Allin"
When I try to insert using this statementL
insert into "TEST_OBJ_TABLE" ("id","extension")
VALUES(
'0FE71A85',
"TEST_TAB"("TEST_TYP"( '0FE71A8'))
);
It throws this error
Error at Command Line : 59 Column : 12
Error report -
SQL Error: ORA-00932: inconsistent datatypes: expected REF SUB_HWOW.TEST_TYP got SUB_HWOW.TEST_TYP
00932. 00000 - "inconsistent datatypes: expected %s got %s"
*Cause:
*Action:
You have to modify object TEST_TYP -> varchar2 has to be max 4000.
You have to store this object in db.
Create object table for TEST_TYP
create table t_for_test_type of TEST_TYP;
To obtain object reference, the object have to be save in db table. In your case:
declare
v_ref_to_test_type1 ref TEST_TYP;
begin
insert into t_for_test_type t values('abcd1') return ref(t) into v_ref_to_test_type1;
end:
Join all parts together.
declare
v_ref_to_test_type1 ref TEST_TYP;
v_ref_to_test_type2 ref TEST_TYP;
begin
insert into t_for_test_type t values('abcd1') return ref(t) into v_ref_to_test_type1;
insert into t_for_test_type t values('abcd2') return ref(t) into v_ref_to_test_type2;
insert into TEST_OBJ_TABLE values (TEST1_TYP('abcd',new TEST_TAB(v_ref_to_test_type1,v_ref_to_test_type2)));
end;
Query table.
select t."id",x.column_value from TEST_OBJ_TABLE t, table(t."extension") x it returns id + ref to other object
Viewing the referenced object.
select t."id",deref(x.column_value) from TEST_OBJ_TABLE t, table(t."extension") x
Note1. You should avoid declaring attribute using double quote. Db becomes case sensitive and it's not normal situation :)
Note2. I don't know why code formatting is not working today
Question. Why are you trying to use such complicated construction?
Changed the original answer. The quotes are doing you no favors - nor was calling your column names id. Removed the REF reference.
CREATE OR REPLACE TYPE TEST_TYP FORCE IS OBJECT
(id1 VARCHAR(4000) NULL)
NOT FINAL;
CREATE OR REPLACE TYPE TEST_TAB is table of TEST_TYP;
CREATE OR REPLACE TYPE TEST1_TYP FORCE IS OBJECT
(id2 VARCHAR2(500) NULL,
extension TEST_TAB NULL )
NOT FINAL;
CREATE TABLE TEST_OBJ_TABLE OF TEST1_TYP
NESTED TABLE extension STORE AS Allin ;
insert into TEST_OBJ_TABLE ( ID2, EXTENSION)
VALUES(
'0FE71A85',
TEST_TAB(TEST_TYP( '0FE71A8'))
);
SELECT * FROM TEST_OBJ_TABLE ;

UPDATEXML throws SQL Error: ORA-00927: missing equal sign when attempting to convert and update CLOB datatype

I worked through the example through the Oracle documentation page for the UPDATEXML function:
https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions205.htm
Now, I'm trying to apply this to the data in my database. The column in my database is CLOB (used for multiple things), so I need to convert my data to the xmltype before performing xml related operations. However, my attempt is returning the following error SQL Error: ORA-00927: missing equal sign.
Is there a way to update the clob-stored xml without modifying the column data type?
Attempt
Reusing the Oracle example with datatypes of my database.
1. Creating table
CREATE TABLE xwarehouses
(
MSD_ID INTEGER,
CDATA CLOB
);
2. Adding data
INSERT INTO xwarehouses VALUES
(1,
('<?xml version="1.0"?>
<Warehouse>
<WarehouseId>1</WarehouseId>
<WarehouseName>Southlake, Texas</WarehouseName>
<Building>Owned</Building>
<Area>25000</Area>
<Docks>2</Docks>
<DockType>Rear load</DockType>
<WaterAccess>true</WaterAccess>
<RailAccess>N</RailAccess>
<Parking>Street</Parking>
<VClearance>10</VClearance>
</Warehouse>'));
3. Converting CLOB to XMLTYPE to extract value from specified tag
SELECT EXTRACTVALUE(XMLTYPE(cdata),'/Warehouse/WaterAccess') as VAL from xwarehouses;
VAL | true
4. Attempt to update value using same conversion in UPDATE
update XWAREHOUSES
set XMLTYPE(cdata) =
updatexml(XMLTYPE(cdata),'/Warehouse/WaterAccess/text()','false')
where msd_id = 1;
**5. This returns the error:
SQL Error: ORA-00927: missing equal sign
Ok, I solved this 2 different ways, both basically the same way, but one is query and one is a script.
Solution 1
load the data as xmltype, then perform xml operation, and finally convert back to clob before executing the update
update xwarehouses
set cdata =
(
select updatexml(xmltype(cdata),'/Warehouse/WaterAccess/text()','true').getclobval()
from xwarehouses where msd_id = 1
)
where msd_id = 1;
commit;
Solution 2
This isn't the tidiest version, as I could probably make due with the query from solution 1 and just add some variables. This essentially does the same thing with all the conversions listed out.
DECLARE
p_msg_id number := 1;
p_cdata xmltype;
p_value varchar(50) :='false';
p_data clob;
BEGIN
select cdata into p_data from xwarehouses;
p_cdata := xmltype(p_data);
select updatexml(p_cdata,'/Warehouse/WaterAccess/text()',p_value) into p_cdata from dual;
p_data := p_cdata.getclobval();
update xwarehouses
set cdata = p_data
where msd_id = p_msg_id;
commit;
END;
From ORACLE 11
All Oracle SQL functions for updating XML data are deprecated. Oracle
recommends that you use XQuery Update instead. These are the
deprecated XML updating functions:
Migration from Oracle Functions for Updating XML Data to XQuery Update
Example:
UPDATE xwarehouses SET cdata =
xmlserialize(document XMLQuery('copy $tmp := $source modify
(for $i in $tmp/Warehouse/WaterAccess/text()
return replace value of node $i
with "false")
return $tmp'
PASSING xmltype(cdata) as "source" RETURNING CONTENT))
WHERE cdata IS NOT NULL;

Query table datatype from function in Oracle SQL

colleagues
I have a problem with table function in Oracle.
More specifically, I have a function that converts BLOB into table of varchar2.
create type string_array is table of varchar2(255);
create or replace function blob_to_strings(p_blb in BLOB) return string_array as
begin
-- some processing here
end;
Also I have table containing BLOBS I need to work with.
create table my_blobs (id number, data blob)
Now, having id in my_blobs table, I want to query result of convert function. Something like
select t.* from table(blob_to_strings(b.data)) t, my_blobs b where b.id = 123;
(I know this is incorrect, just showing what I need)
This query expectedly returns b.data: invalid identifier as you can't access other table columns inside from section.
I understand how to do it in PL/SQL running 2 queries, but really need to do it in SQL.
Can anybody help me?
Thank you in advance.
UPD: I tried following:
select * from table(select blob_to_strings(b.data) from my_blobs b where b.id = 123);
Result: ORA-00902: invalid datatype
Any other ideas?
Possibly the issue with your original query was that you had the table name coming after the attempt to select from the array (from table(blob_to_strings(b.data)) t, my_blobs b). In other words, you were trying to select from something that hadn't yet been declared. Switch the order of the items in the from clause, and it should work.
Here's a test case that I knocked up to demonstrate (I used CLOBs since we're apparently dealing with text; I'm not sure why you're using BLOBs?):
create table t1 (id number,
clob_col clob);
insert into t1 values (1, 'abcd');
insert into t1 values (2, 'efg');
commit;
create type string_array is table of varchar2(255);
create or replace function clob_to_str_tab (p_clob in clob)
return string_array
is
v_str_arr string_array := string_array();
begin
for i in 1.. length(p_clob)
loop
v_str_arr.extend;
v_str_arr(i) := substr(p_clob, i, 1);
end loop;
return v_str_arr;
end;
/
select t1.id,
t2.column_value res
from table(clob_to_str_tab(t1.clob_col)) t2,
t1;
ORA-00904: "T1"."CLOB_COL": invalid identifier
select t1.id,
t2.column_value res
from t1,
table(clob_to_str_tab(t1.clob_col)) t2;
ID RES
---------- ---
1 a
1 b
1 c
1 d
2 e
2 f
2 g
You can achieve this with Oracle's PIPE ROW statement
See: Pipelined Table Functions

Fetching BLOB data and inserting into a Table

I have a BLOB content stored in a table (x_files) with MIME_TYPE = 'text/plain' , I want to parse this BLOB data and want to insert the data into a table (TEMP_UPLOAD_DATA) having a VARCHAR2 column.
Can you please help me with a sample code .. If you have? I Have written a code as mentioned below - if I do a DBMS_OUTPUT things are working fine, but when I am trying to insert the data into the table things are not working fine
Is it that I need to convert the BLOB to CLOB first and then parse and insert the data into the Table? Request your inputs
Tables in my database:
Table_name: X_files
ID BLOB_CONTENT MIME_TYPE FILE_NAME LAST_UPDATED CHARECTER_SET
7 BLOB text/plain testing_blob.txt 01/28/2013 -
Table name: TEMP_UPLOAD_DATA
Column Name Data Type Nullable Default Primary Key
UPLOAD_COLUMN VARCHAR2(1000) Yes -
-
Code which I have written :-
This is working fine when I do a DBMS_OUTPUT , but not working fine when i am trying to insert the data into the table.
DECLARE
l_num NUMBER(8);
i NUMBER(4);
lob_loc BLOB;
update_details VARCHAR2(10000);
BEGIN
SELECT BLOB_CONTENT INTO lob_loc FROM x_files WHERE id = 7;
update_details := UTL_RAW.CAST_TO_VARCHAR2(DBMS_LOB.SUBSTR(lob_loc, 10000, 1));
l_num := (LENGTH(update_details)-LENGTH(REPLACE(update_details,'##')))/LENGTH('##');
for i in 1..l_num
LOOP
DBMS_OUTPUT.PUT_LINE('STRING IS---' || SUBSTR(update_details,instr(update_details,'##',1,i),(instr(update_details,'##',1,i)-instr(update_details,'##',1,i)+1)));
--INSERT INTO TEMP_UPLOAD_DATA VALUES(SUBSTR(update_details,instr(update_details,'##',1,i),(instr(update_details,'##',1,i)-instr(update_details,'##',1,i)+1)));
END LOOP;
END;
Thanks
This example shows how simple it can be to insert substrings of blob data into a varchar2 column. The original question has a myriad of incomplete setup scripting the code is blending in more commands than the question demands.
create table blob_table ( id number primary key, blob_content blob );
create table char_table ( id number, char_content varchar2(10) );
insert into blob_table
values (1, utl_raw.cast_to_raw('ABCDEFGHIJKLMNOPQRSTUVWXYZ'));
insert into char_table (id, char_content)
select bt.id, utl_raw.cast_to_varchar2(dbms_lob.substr(bt.blob_content, 10, 1))
from blob_table bt
where bt.id = 1;
select * from char_table;
ID CHAR_CONTENT
---------- ------------
1 ABCDEFGHIJ