Ciao,
i've one problem with sql.
I've some table with datatype clob where is stored a clob.
In the same table if we have the xml format we use one function for take the xml_fied
CREATE OR REPLACE FUNCTION gettagvalue (
XMLBody IN CLOB, TagXml IN VARCHAR2) RETURN VARCHAR2 IS
BEGIN
return TO_CHAR (SUBSTR (XMLBody,
INSTR (XMLBody, '<'||TagXml||'>') + length(TagXml) + 2,
INSTR (XMLBody, '</'||TagXml||'>')
- INSTR (XMLBody, '<'||TagXml||'>')
- (length(TagXml) + 2)
)
);
END GetTagValue;
/
example :
Select errorhandler.GetTagValue(xml_content,'ORDERID')
from table_order
On the same table we have also some xml in json.
How i can create a copy of same function for take the field?
On xml is eay because we have the field with same name that start with and finish with but with json
I cannot understand how define the end of field
Do NOT try to parse XML or JSON as strings; use a proper XML or JSON parser.
If you have the table with the sample data:
CREATE TABLE table_name (
xml CLOB,
json CLOB CHECK ( json IS JSON )
);
INSERT INTO table_name ( xml, json ) VALUES (
'<a><b>BBB</b><c>CCC</c><d>DDD</d></a>',
'{"a":"aaa","b":"bbb","c":[1,2,3,4],"d":"ddd"}'
);
Then you can get the c values from both using the XMLQUERY or JSON_QUERY functions:
SELECT XMLQUERY(
'*/c/text()'
PASSING XMLTYPE(xml)
RETURNING CONTENT
) AS c_xml_value,
JSON_QUERY(
json,
'$.c'
RETURNING VARCHAR2(50)
) AS c_json_value
FROM table_name
Which outputs:
| C_XML_VALUE | C_JSON_VALUE |
| :---------- | :----------- |
| CCC | [1,2,3,4] |
If you have XML and JSON values in the same column then look at whether the first character is < or not and use the appropriate parsing function; do not try and create your own function to parse the values using substring matching.
For example:
CREATE TABLE table_name ( value CLOB );
INSERT INTO table_name ( value )
SELECT '<a><b>BBB</b><c>CCC</c><d>DDD</d></a>' FROM DUAL UNION ALL
SELECT '{"a":"aaa","b":"bbb","c":[1,2,3,4],"d":"ddd"}' FROM DUAL;
Then:
SELECT CASE
WHEN value LIKE '<%'
THEN CAST(
XMLQUERY( '*/c/text()' PASSING XMLTYPE(value) RETURNING CONTENT )
AS VARCHAR2(50)
)
ELSE JSON_QUERY( value, '$.c' RETURNING VARCHAR2(50) )
END AS c_value
FROM table_name
Outputs:
| C_VALUE |
| :-------- |
| CCC |
| [1,2,3,4] |
db<>fiddle here
Update
You can also use JSON_TABLE and XMLTABLE to get all the values out:
SELECT COALESCE( j.sourceChannel, x.sourceChannel ) AS sourceChannel,
COALESCE( j.transactionId, x.transactionId ) AS transactionId,
COALESCE( j.sessionId, x.sessionId ) AS transactionId,
COALESCE( j.status, x.status ) AS status,
COALESCE( j.errorcode, x.errorcode ) AS errorcode,
COALESCE( j.errordescription, x.errordescription ) AS errordescription
FROM table_name t
OUTER APPLY JSON_TABLE(
t.value,
'$.header'
COLUMNS (
sourceChannel VARCHAR2( 50) PATH '$.sourceChannel',
transactionId VARCHAR2( 50) PATH '$.transactionId',
sessionId VARCHAR2( 50) PATH '$.sessionId',
status VARCHAR2( 50) PATH '$.status',
errorcode VARCHAR2( 50) PATH '$.errorcode',
errordescription VARCHAR2(200) PATH '$.errordescription'
)
) j
LEFT OUTER JOIN LATERAL(
SELECT *
FROM XMLTABLE(
'/header'
PASSING XMLTYPE( value )
COLUMNS
sourceChannel VARCHAR2( 50) PATH 'sourceChannel',
transactionId VARCHAR2( 50) PATH 'transactionId',
sessionId VARCHAR2( 50) PATH 'sessionId',
status VARCHAR2( 50) PATH 'status',
errorcode VARCHAR2( 50) PATH 'errorcode',
errordescription VARCHAR2(200) PATH 'errordescription'
)
) x
ON ( t.value LIKE '<%' )
Which for the sample data:
CREATE TABLE table_name ( value CLOB );
INSERT INTO table_name ( value )
SELECT '<header>
<sourceChannel>xaaa</sourceChannel>
<transactionId>xbbb</transactionId>
<sessionId>xccc</sessionId>
<status>xddd</status>
<errorcode>xeee</errorcode>
<errordescription>xfff</errordescription>
</header>' FROM DUAL UNION ALL
SELECT '{"header":{"sourceChannel":"jaaa","transactionId":"jbbb","sessionId":"jccc","status":"jddd","errorcode":"jeee","errordescription":"jfff"}}' FROM DUAL;
Outputs:
SOURCECHANNEL
TRANSACTIONID
TRANSACTIONID
STATUS
ERRORCODE
ERRORDESCRIPTION
xaaa
xbbb
xccc
xddd
xeee
xfff
jaaa
jbbb
jccc
jddd
jeee
jfff
Related
Below the code which I'm trying but getting null value.
SELECT json_query(object_data,'$.AOF.LEAD_DATA.DIRECTOR[*]')
FROM TB_COP_BUSS_OBJ_TXN FD,
JSON_TABLE(FD.OBJECT_DATA,'$.AOF.LEAD_DATA.DIRECTOR[*]' columns
( AUS_FLAG VARCHAR2(40) PATH '$.CHECKBOX.AUS_FLAG.value')) j
WHERE FD.OBJECT_PRI_KEY_1 = 'XXXXXXX' and j.AUS_FLAG ='Y'
I'm trying to get full data which is inside director object/array. when I'm using 0,1,2, instead of * then I'm getting the data but I need to check aus flag and need those index data of that array object. please help
please help.
If you have the sample data:
CREATE TABLE TB_COP_BUSS_OBJ_TXN (
OBJECT_PRI_KEY_1 VARCHAR2(20) PRIMARY KEY,
OBJECT_DATA CLOB CHECK (OBJECT_DATA IS JSON)
);
INSERT INTO TB_COP_BUSS_OBJ_TXN (
OBJECT_PRI_KEY_1,
OBJECT_DATA
) VALUES (
'XXXXXX',
'{"AOF":{"LEAD_DATA":{"DIRECTOR":[1,2,3]}}}'
);
Then you can use:
SELECT JSON_QUERY(OBJECT_DATA,'$.AOF.LEAD_DATA."DIRECTOR"')
from TB_COP_BUSS_OBJ_TXN FD
WHERE OBJECT_PRI_KEY_1 = 'XXXXXX'
Which outputs:
JSON_QUERY(OBJECT_DATA,'$.AOF.LEAD_DATA."DIRECTOR"')
[1,2,3]
Or you can use:
SELECT value
from TB_COP_BUSS_OBJ_TXN FD
CROSS APPLY JSON_TABLE(
fd.object_data,
'$.AOF.LEAD_DATA."DIRECTOR"[*]'
COLUMNS (
value NUMBER PATH '$'
)
)
WHERE OBJECT_PRI_KEY_1 = 'XXXXXX'
Which outputs:
VALUE
1
2
3
db<>fiddle here
All the examples I have found for the Postgres 'returning' functionality (https://www.postgresql.org/docs/current/dml-returning.html) return values for a single row.
How do I read multiple result rows into a variable?
Executing the following outside a function gives the desired results:
create sequence core.test_id_seq start with 10000;
create table core.test (
test_id integer not null default nextval('core.test_id_seq'),
field integer not null
);
insert into core.test ( field )
select unnest( array[1, 2] ) as id
returning *
;
test_id | field
---------+-------
10000 | 1
10001 | 2
(2 rows)
But I want to read the results into a variable or table to work with:
do $$
declare
recs ??;
begin
create sequence core.test_id_seq start with 10000;
create table core.test (
test_id integer not null default nextval('core.test_id_seq'),
field integer not null
);
insert into core.test ( field )
select unnest( array[1, 2] ) as id
returning * into recs
;
end $$;
Is this possible?
Thanks
You need to use an array of integers:
do $$
declare
new_ids int[];
begin
with new_rows as (
insert into core.test ( field )
select unnest( array[1, 2] ) as id
returning *
)
select array_agg(field)
into new_ids
from new_rows;
... work with the new_ids array ...
end
$$;
I am writing a query in oracle where I have requirement to separate alphabet+numbers and numbers after special character as 2 different columns
Eg.
Colum Value is
ABC 123#78800,XYZ#4666,PQR 444#9900
Output Required
Column 1 : ABC 123,XYZ,PQR 444
Column 2 : 78800,4666, 9900
I tried following query:
select TRANSLATE('ABC 123#78800,XYZ#4666,PQR 444#9900 ','ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789#','ABCDEFGHIJKLMNOPQRSTUVWXYZ') from dual.
Output is "ABC ,XYZ,PQR " numbers are missing
What you need is regex
with table_name as
(
select 'ABC 123#78800,XYZ#4666,PQR 444#9900' col_name from dual
)
select
REGEXP_REPLACE(col_name,'#([^#,])*', null) alphabet_num
,REGEXP_REPLACE(col_name,'([^#,])*#', null) num_value
from
table_name;
Editted: Remove some redundant character as suggested by MTO
Oracle Setup:
CREATE TABLE table_name ( col VARCHAR2(100) );
INSERT INTO table_name VALUES ( 'ABC 123#78800,XYZ#4666,PQR 444#9900' );
CREATE TYPE key_value_pair AS OBJECT(
key VARCHAR2(20),
value NUMBER(10)
);
/
CREATE TYPE key_value_pair_table AS TABLE of key_value_pair;
/
Query:
SELECT *
FROM table_name t,
TABLE(
CAST(
MULTISET(
SELECT REGEXP_SUBSTR( t.col, '(^|,)([^,#]+)#(\d+)', 1, LEVEL, NULL, 2 ),
TO_NUMBER(
REGEXP_SUBSTR( t.col, '(^|,)([^,#]+)#(\d+)', 1, LEVEL, NULL, 3 )
)
FROM DUAL
CONNECT BY LEVEL <= REGEXP_COUNT( t.col, '(^|,)([^,#]+)#(\d+)' )
)
AS key_value_pair_table
)
);
Output:
COL KEY VALUE
----------------------------------- ------- -----
ABC 123#78800,XYZ#4666,PQR 444#9900 ABC 123 78800
ABC 123#78800,XYZ#4666,PQR 444#9900 XYZ 4666
ABC 123#78800,XYZ#4666,PQR 444#9900 PQR 444 9900
I have a simple query that is returning records where "column2" > 0
Here is the data in the database
Column1 Column2
1 123456789
2 123456781
3 13-151-1513
4 alsdjf
5
6 000000000
Her is the query
select column1, replace(a.Payroll_id,'-','')
from table1
where isnumeric(column2) = 1
I'd like to return the following:
Column1 Column2
1 123456789
2 123456781
3 131511513
This mean, I won't select any records when the column is blank (or null), will not return a row if it's not an integer, and will drop out the '-', and would not show row 6 since it's all 0.
How can I do this?
I think you can use something like this :
USE tempdb
GO
CREATE TABLE #Temp
(
ID INT IDENTITY
,VALUE VARCHAR(30)
)
INSERT INTO #Temp (VALUE) VALUES ('1213213'), ('1213213'), ('121-32-13'), ('ASDFASF2123')
GO
WITH CteData
AS
(
SELECT REPLACE(VALUE,'-','') as Valor FROM #Temp
)
SELECT * FROM CteData WHERE (ISNUMERIC(Valor) = 1 AND valor not like '%[0-0]%')
DROP TABLE #Temp
then you can apply validations for empty, NULL,0 etc
If you are using SQL2012 or above you can also use TRY_PARSE that is more selective in its parsing. This function will return NULL if a record can't be converted. You could use it like this:
CREATE TABLE #temp
(
ID INT IDENTITY ,
VALUE VARCHAR(30)
)
INSERT INTO #temp
( VALUE )
VALUES ( '1213213' ),
( '1213213' ),
( '121-32-13' ),
( 'ASDFASF2123' ),
( '0000000' )
SELECT ParsedValue
FROM #temp
CROSS APPLY ( SELECT TRY_PARSE(
Value AS INT ) AS ParsedValue
) details
WHERE ParsedValue IS NOT NULL
AND ParsedValue>0
I have a merge statement which works when I did not have to consider null values :
This works :
MERGE INTO LTABLE L
USING (SELECT 1392 UCL_USER_ID,11 REGISTER_ID ,5 REGION_ID FROM DUAL ) B
ON ( L.UCL_USER_ID = B.UCL_USER_ID
AND L.REGISTER_ID = B.REGISTER_ID
AND (L.REGION_ID = B.REGION_ID)
)
WHEN NOT MATCHED
THEN
INSERT (
L.LTABLE_ID
,L.UCL_USER_ID
,L.REGISTER_ID
,L.REGION_ID
)
VALUES (
SEQ_LTABLE_ID.NEXTVAL
,1392
,11
,5);
When I have to consider null values for REGION_ID the below works :
MERGE INTO LTABLE L
USING (SELECT 1392 UCL_USER_ID,11 REGISTER_ID ,NULL REGION_ID FROM DUAL ) B
ON ( L.UCL_USER_ID = B.UCL_USER_ID
AND L.REGISTER_ID = B.REGISTER_ID
AND (L.REGION_ID IS NULL AND B.REGION_ID IS NULL)
)
WHEN NOT MATCHED
THEN
INSERT (
L.LTABLE_ID
,L.UCL_USER_ID
,L.REGISTER_ID
,L.REGION_ID
)
VALUES (
SEQ_LTABLE_ID.NEXTVAL
,1392
,11
,NULL);
Question is how can I combine these two conditions when it can be null or some numeric value. I tried the below but sql developer gives the error that query is not right.
AND ((L.REGION_ID = B.REGION_ID) OR (L.REGION_ID IS NULL AND B.REGION_ID IS NULL))
ERROR :
SQL Error: DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610, SQLERRMC=FCS already resolved to different type, DRIVER=4.17.29
This is just a guess, but perhaps the problem is the default type for NULL. Perhaps a cast will fix the problem:
MERGE INTO LTABLE L
USING (SELECT 1392 UCL_USER_ID, 11 as REGISTER_ID,
CAST(NULL as VARCHAR(255)) as REGION_ID
FROM DUAL ) B
ON ( L.UCL_USER_ID = B.UCL_USER_ID
AND L.REGISTER_ID = B.REGISTER_ID
AND (L.REGION_ID IS NULL AND B.REGION_ID IS NULL)
)
Or whatever the appropriate type is for REGION_ID.