Extract single repeating XML node through whole XML result - oracle

Given the following XML sample below, how can I extract all <table_no> values from top to bottom using Oracle XML extraction.
Based on below, I would expect to see the following individual rows from my select:
1
4
2
11
Table: tickets
Column holding XML: ticket_col
XML code:
<xml>
<ticket_order>
<table_no>1<table_no/>
<waiter>Jack<waiter/>
<total_people>12<total_people/>
</ticket_order>
<ticket_order>
<table_no>4<table_no/>
<waiter>Jackie<waiter/>
<total_people>3<total_people/>
</ticket_order>
<ticket_order>
<table_no>2<table_no/>
<waiter>Sally<waiter/>
<total_people>2<total_people/>
</ticket_order>
<ticket_order>
<table_no>11<table_no/>
<waiter>Mike<waiter/>
<total_people>6<total_people/>
</ticket_order>
</xml>

You can use XMLTable(); with (fixed) sample XML as a string in-line:
select x.*
from xmltable(
'/xml/ticket_order'
passing xmltype('<xml>
<ticket_order>
<table_no>1</table_no>
<waiter>Jack</waiter>
<total_people>12</total_people>
</ticket_order>
<ticket_order>
<table_no>4</table_no>
<waiter>Jackie</waiter>
<total_people>3</total_people>
</ticket_order>
<ticket_order>
<table_no>2</table_no>
<waiter>Sally</waiter>
<total_people>2</total_people>
</ticket_order>
<ticket_order>
<table_no>11</table_no>
<waiter>Mike</waiter>
<total_people>6</total_people>
</ticket_order>
</xml>')
columns table_no number path 'table_no'
) x;
TABLE_NO
----------
1
4
2
11
If the XML is a string (VARCHAR2 or CLOB) in a table you would pass it in via a cross join:
select x.*
from your_table t
cross join xmltable(
'/xml/ticket_order'
passing xmltype(t.xml_string)
columns table_no number path 'table_no'
) x;
If it's already am XMLType in the table you woudl skip that conversion:
select x.*
from your_table t
cross join xmltable(
'/xml/ticket_order'
passing t.xml
columns table_no number path 'table_no'
) x;
You can get multiple columns at once; and the generated relatinal column name doesn't have to be the same as the node name:
select x.*
from your_table t
cross join xmltable(
'/xml/ticket_order'
passing t.xml
columns table_number number path 'table_no',
server varchar2(10) path 'waiter',
covers number path 'total_people'
) x;
TABLE_NUMBER SERVER COVERS
------------ ---------- ----------
1 Jack 12
4 Jackie 3
2 Sally 2
11 Mike 6
Read more.

Related

XMLType Extract Unique ID from Single Cell

Can you please help me out to fix the following?
I only required a person_number once eg. 1000142 but I'm getting 10001421000142 like this.
Because the values I have in XML cell have repeating number, so I only want to extract one unique person number.
select xmltype('<?xml version="1.0"?>
<ROWSET>
<ROW0> <PERSON_NUMBER>1000142</PERSON_NUMBER> <LOAN_1>25000</LOAN_1> <LOAN_2>26000</LOAN_2>
</ROW0>
<ROW0> <PERSON_NUMBER>1000142</PERSON_NUMBER> </ROW0> <LOAN_1>25000</LOAN_1> <LOAN_2>26000</LOAN_2>
</ROW0>
</ROWSET>').extract( '//PERSON_NUMBER/text()' ).getstringval() p#
from dual;
Based on your initial version of the question (where the XML is a valid with a single root element rather than a forest of elements), you can use:
select xmltype(
'<?xml version="1.0"?>
<ROWSET>
<ROW>
<PERSON_NUMBER>1000142</PERSON_NUMBER>
<PERSON_NUMBER>1000142</PERSON_NUMBER>
<LOAN_1>25000</LOAN_1>
<LOAN_2>26000</LOAN_2>
</ROW>
</ROWSET>').extract( '//PERSON_NUMBER[1]/text()' ) .getstringval() p#
from dual;
Which outputs:
P#
1000142
db<>fiddle here

How to write correct left Join of two tables?

I want to join two tables, first table primary key data type is number, and second table primary key data type is VARCHAR2(30 BYTE). How to join both tables.
I tried this code but second tables all values are null. why is that?
SELECT a.act_phone_no,a.act_actdevice,a.bi_account_id, a.packag_start_date, c.identification_number,
FROM ACTIVATIONS_POP a
left JOIN customer c
on TO_CHAR(a.act_phone_no) = c.msisdn_voice
first table
act_phone_no bi_account_id
23434 45345
34245 43556
Second table
msisdn_voice identification_number
23434 321113
34245 6547657
It seems that you didn't tell us everything. Query works, if correctly written, on such a sample data:
SQL> with
2 -- Sample data
3 activations_pop (act_phone_no, bi_account_id) as
4 (select 23434, 45345 from dual union all
5 select 34245, 43556 from dual
6 ),
7 customer (msisdn_voice, identification_number) as
8 (select '23434', 321113 from dual union all
9 select '34245', 6547657 from dual
10 )
11 -- query works OK
12 select a.act_phone_no,
13 a.bi_account_id,
14 c.identification_number
15 from activations_pop a join customer c on to_char(a.act_phone_no) = c.msisdn_voice;
ACT_PHONE_NO BI_ACCOUNT_ID IDENTIFICATION_NUMBER
------------ ------------- ---------------------
23434 45345 321113
34245 43556 6547657
SQL>
What could be wrong? Who knows. If you got some result but columns from the CUSTOMER table are empty (NULL?), then they really might be NULL, or you didn't manage to join rows on those columns (left/right padding with spaces?). Does joining on e.g.
on to_char(a.act_phone_no) = trim(c.msisdn_voice)
or
on a.act_phone_no = to_number(c.msisdn_voice)
help?
Consider posting proper test case (CREATE TABLE and INSERT INTO statements).
You are using Oracle ?
Please check the below demo
SELECT a.act_phone_no, a.bi_account_id, c.identification_number
FROM ACTIVATIONS_POP a
left JOIN customer c
on TO_CHAR(a.act_phone_no) = c.msisdn_voice;
SQLFiddle

oracle xml parsing with multi rows

query from xml not return rows.
I running this query but not return rows.
The my xml is :
<?xml version="1.0" encoding="UTF-8"?>
<ns0:testata xmlns:ns0="http://siete">
<ns0:product>
<ns0:YEAR>2019</ns0:YEAR>
<ns0:PERIOD>1</ns0:PERIOD>
</ns0:product>
<ns0:product>
<ns0:YEAR>2019</ns0:YEAR>
<ns0:PERIOD>2</ns0:PERIOD>
</ns0:product>
</ns0:testata>
My query is
FROM XMLTABLE('/testata/product'
PASSING
(select xmltype(t.XML1) doc
from tb_test t)
COLUMNS
name varchar2(4) PATH './YEAR'
) xmlt
0 rows
please help me
Your XML document has a namespace, so you either need to wildcard the nodes in your XMLTable call, or - preferably - supply the same namespace information and prefixes:
-- CTE for sample data
with tb_test (xml1) as (select '<?xml version="1.0" encoding="UTF-8"?>
<ns0:testata xmlns:ns0="http://siete">
<ns0:product>
<ns0:YEAR>2019</ns0:YEAR>
<ns0:PERIOD>1</ns0:PERIOD>
</ns0:product>
<ns0:product>
<ns0:YEAR>2019</ns0:YEAR>
<ns0:PERIOD>2</ns0:PERIOD>
</ns0:product>
</ns0:testata>' from dual
)
-- actual query
select x.year
from tb_test t
cross join xmltable(
xmlnamespaces('http://siete' as "ns0"),
'/ns0:testata/ns0:product'
passing xmltype(t.xml1)
columns year number path 'ns0:YEAR'
) x;
YEAR
----------
2019
2019

Reading xml using Oracle

We have to read a xml using pl/sql. The top few lines of the xml are pasted below. In the xml, for one Node,there is one Equipment. For one Equipment, there are multiple Cabinet. For one Cabinet there are multiple Subrack & for one Subrack there are multiple Boards.
We have developed a below query to parse.
Step-1:
create table emp_xml of xmltype xmltype store as securefile binary xml;
Step-2:
insert into emp_xml values (xmltype(bfilename('XML_DIR','ahm_2015_04_01_172428.xml'), nls_charset_id('AL32UTF8') ));
Step-3:
select * from emp_xml;
Step-4:
select x.*
from emp_xml t,
xmltable(xmlnamespaces(default 'http://www.ericsson.com/axe/export/hw'(http :/ /
www.ericsson.com / axe /
export /
hw%27)),
'/NetworkInventory/Node' passing t.object_value columns
SiteName varchar2(10) path '#Name',
SiteType varchar2(10) path '#Type',
BuildingPractice varchar2(10) path
'//Equipment/#BuildingPractice') x;
This query is working perfectly.But when I am trying to fetch the Cabinet or Subrack details, we are getting below error.
ORA-19279: XPTY0004 - XQuery dynamic type mismatch: expected singleton sequence - got multi-item sequence
ORA-06512: at line 33
19279. 00000 - "XQuery dynamic type mismatch: expected singleton sequence - got multi- item sequence"
*Cause: The XQuery sequence passed in had more than one item.
*Action: Correct the XQuery expression to return a single item sequence.
Top Few Line of XML is given below.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<NetworkInventory xmlns="http://www.ericsson.com/axe/export/hw" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.ericsson.com/axe/export/hw file:/opt/ericsson/nms_smo_srv/etc/export.xsd">
<Description>AXE HARDWARE INVENTORY DATA</Description>
<ExportDateTime Date="2015-04-01" Time="17:24:28"/>
<Node AdjustDate="2015-03-21" FunctionType=" " Name="BSC20" Site=" " Type="AXE" UserLabel="">
<Equipment BuildingPractice="BYB501">
<Cabinet Position="CabNumber=1">
<Subrack Name="FAN-1" Position="X=3,Y=2" Type="CP">
<Board Name=" " SlotPosition="255" Type="CP">
<ProductData FirstOperationDate="2013-11-20" LastChangedDate="2013-11-20" ManufacturedDate=" " ProductName=" " ProductNumber=" " ProductRevision=" " SerialNumber=" " Supplier="Ericsson AB"/>
</Board>
<Board Name=" " SlotPosition="255" Type="CP">
<ProductData FirstOperationDate="2013-11-20" LastChangedDate="2013-11-20" ManufacturedDate=" " ProductName=" " ProductNumber=" " ProductRevision=" " SerialNumber=" " Supplier="Ericsson AB"/>
</Board>
</Subrack>
Because your Cabinet is set not a single iterate.
When you want to present repeating groups in relational format, you have to extract the sequence of items in the main XQuery expression.
Each item is then passed to the COLUMNS clause to be further shredded into columns.
You're trying to expand a construct that's sort of similar to nested tables. Your Equipment node can have multiple Cabinets, so to extract details from those you need to pass those to a second XMLTable:
select x.SiteName, x.SiteType, x.BuildingPractice, y.Position
from emp_xml t
cross join xmltable(
xmlnamespaces(default 'http://www.ericsson.com/axe/export/hw'),
'/NetworkInventory/Node' passing t.object_value columns
SiteName varchar2(10) path '#Name',
SiteType varchar2(10) path '#Type',
BuildingPractice varchar2(10) path 'Equipment/#BuildingPractice',
Equipment XMLType path 'Equipment'
) x
cross join xmltable(
xmlnamespaces(default 'http://www.ericsson.com/axe/export/hw'),
'//Cabinet' passing x.Equipment columns
Position varchar2(15) path '#Position'
) y;
SITENAME SITETYPE BUILDINGPRACTICE POSITION
---------- ---------- ---------------- ---------------
BSC20 AXE BYB501 CabNumber=1
To get the the SubRack data too, you'd need to pass that out to a third level of XMLTable, etc.

how to merge data while loading them into hive?

I'm tring to use hive to analysis our log, and I have a question.
Assume we have some data like this:
A 1
A 1
A 1
B 1
C 1
B 1
How can I make it like this in hive table(order is not important, I just want to merge them) ?
A 1
B 1
C 1
without pre-process it with awk/sed or something like that?
Thanks!
Step 1: Create a Hive table for input data set .
create table if not exists table1 (fld1 string, fld2 string ) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
(i assumed field seprator is \t, you can replace it with actual separator)
Step 2 : Run below to get the merge data you are looking for
create table table2 as select fld1,fld2 from table1 group by fld1,fld2 ;
I tried this for below input set
hive (default)> select * from table1;
OK
A 1
A 1
A 1
B 1
C 1
B 1
create table table4 as select fld1,fld2 from table1 group by fld1,fld2 ;
hive (default)> select * from table4;
OK
A 1
B 1
C 1
You can use external table as well , but for simplicity I have used managed table here.
One idea.. you could create a table around the first file (called 'oldtable').
Then run something like this....
create table newtable select field1, max(field) from oldtable group by field1;
Not sure I have the syntax right, but the idea is to get unique values of the first field, and only one of the second. Make sense?
For merging the data, we can also use "UNION ALL" , it can also merge two different types of datatypes.
insert overwrite into table test1
(select x.* from t1 x )
UNION ALL
(select y.* from t2 y);
here we are merging two tables data (t1 and t2) into one single table test1.
There's no way to pre-process the data while it's being loaded without using an external program. You could use a view if you'd like to keep the original data intact.
hive> SELECT * FROM table1;
OK
A 1
A 1
A 1
B 1
C 1
B 1
B 2 # Added to show it will group correctly with different values
hive> CREATE VIEW table2 (fld1, fld2) AS SELECT fld1, fld2 FROM table1 GROUP BY fld1, fld2;
hive> SELECT * FROM table2;
OK
A 1
B 1
B 2
C 1

Resources