Oracle join on two xmltables - oracle

In an attempt to make every two item into one from the following XML,
<items>
<item><a>a1</a><b>b1</b></item>
<item><b>b2</b><a>a2</a></item>
<item><a>a3</a><b>b3</b></item>
<item><a>a4</a><b>b4</b></item>
<item><a>a5</a><b>b5</b></item>
<item><a>a6</a><b>b6</b></item>
</items>
I came with this solution:
select * from xmltable ( '/items/item[position() mod 2 = 0]' passing
xmltype('
<items>
<item><a>a1</a><b>b1</b></item>
<item><a>a2</a><b>b2</b></item>
<item><a>a3</a><b>b3</b></item>
<item><a>a4</a><b>b4</b></item>
<item><a>a5</a><b>b5</b></item>
<item><a>a6</a><b>b6</b></item>
</items>') columns
"id" for ordinality,
"a" varchar2(10) path 'a',
"b" varchar2(10) path 'b'
) x,
xmltable ( '/items/item[position() mod 2 = 1]' passing
xmltype('
<items>
<item><a>a1</a><b>b1</b></item>
<item><b>b2</b><a>a2</a></item>
<item><a>a3</a><b>b3</b></item>
<item><a>a4</a><b>b4</b></item>
<item><a>a5</a><b>b5</b></item>
<item><a>a6</a><b>b6</b></item>
</items>') columns
"id" for ordinality,
"c" varchar2(10) path 'a',
"d" varchar2(10) path 'b'
) y
where x.id = y.id;
The problem is that it does not recognize the second table in the ON clause:
ORA-00904: "Y"."ID": invalid identifier
00904. 00000 - "%s: invalid identifier"
*Cause:
*Action:
Error at Line: 29 Column: 18
It rendered me helpless. I have tried multiple subqueries, subqueries within subqueries but there were no hope.
Thanks for your help and guidance.

You've made your XMLTable columns with quoted identifiers. You either need to quote the references too:
where x."id" = y."id";
Or change the column clauses to not be quoted, which is simpler:
id for ordinality
... etc.

Related

Oracle Spatial: Update a numeric column based on Point-coordinates

(Already solved with a second solution, but I wonder why the first idea does not work).
I have a table with FID, Geom (Point-data), orientation and so on. I want to update the Orientation based on the coordinates, like "set orientation = 99 where X = something and Y = something"
I have this:
UPDATE WW_POINT
SET
ORIENTATION = 99.9
WHERE
F_CLASS_ID_ATTR = 77
AND GEOM.SDO_POINT.X = 2695056.511
AND GEOM.SDO_POINT.Y = 1279718.364;
The result is:
Error starting at line : 1 in command -
UPDATE WW_POINT
SET
ORIENTATION = 99.9
WHERE
F_CLASS_ID_ATTR = 77 -- haltunsgverbindung
AND GEOM.SDO_POINT.X = 2695056.511
AND GEOM.SDO_POINT.Y = 1279718.364
Error at Command Line : 7 Column : 12
Error report -
SQL Error: ORA-00904: "GEOM"."SDO_POINT"."Y": invalid identifier
00904. 00000 - "%s: invalid identifier"
*Cause:
*Action:
A simple select returns X and Y as expected:
SELECT
X.GEOM.SDO_POINT.X
, X.GEOM.SDO_POINT.Y
FROM
WW_POINT X
So the question is: What is wrong here?
My second solution with SDO_EQUAL seem to work fine:
UPDATE WW_POINT
SET
ORIENTATION = 389.608
WHERE
F_CLASS_ID_ATTR = 77 -- haltunsgverbindung
AND SDO_EQUAL (
GEOM
, MDSYS.SDO_GEOMETRY (
2001
, 2056
, SDO_POINT_TYPE (
2695056.511
, 1279718.364
, NULL
)
, NULL
, NULL
)
) = 'TRUE';
Comparing both of your queries: the second one (working) has a form <table alias>.<column name>.<attr>.<attr>, but the first one is <column name>.<attr>.<attr>.
From the documentation:
t_alias
Specify a correlation name, which is an alias for the table, view, materialized view, or subquery for evaluating the query. This alias is required if the select list references any object type attributes or object type methods.
Given this sample table:
create table t (p)
as
select
SDO_GEOMETRY (
2001, 2056
, SDO_POINT_TYPE (1, 1, NULL)
, NULL, NULL
)
from dual
A query without table alias fails:
select t.p.sdo_point.x
from t
where t.p.sdo_point.x = 1
ORA-00904: "T"."P"."SDO_POINT"."X": invalid identifier
And the query with table alias works as expected allowing attribute access in the select list as well as in the where clause:
select t.p.sdo_point.x
from t t
where t.p.sdo_point.x = 1
P.SDO_POINT.X
1
db<>fiddle here

ORA-01722: invalid number 01722. 00000 - "invalid number" *Cause: The specified number was invalid. *Action: Specify a valid number

I am new to Oracle SQL Developer, and today while running this
select r.id, r.date, it.group, it.comment, it.item, it.remark, r.summary,
substr (it.remark, instr(it.remark,'ABC')+8,7 ) as label1,
cast(substr (it.remark, instr(it.remark,'-')+1,3 ) as integer) as label2
from it_table it
inner join sp_table sp on sp.id = substr (it.remark, instr(it.remark,'ABC')+8,7 ) and sp.label_id = cast(substr (it.remark, instr(it.remark,'-')+1,3 ) as integer)
inner join sq_table sq on sq.id = sp.id
where it.date > '01-jan-2020' and it.remark like '%ABC%' and it.group= 'O'
order by sp.id, it.id;
it caught the error:
ORA-01722: invalid number
01722. 00000 - "invalid number"
*Cause: The specified number was invalid.
*Action: Specify a valid number.
I think the problem lies with the extraction as in row 3 (cast(substr (it.remark, instr(it.remark,'-')+1,3 ) as integer)), where I need to convert a string into a number using cast.
According to doc, the error occurs when an attempt is made to convert a character string into a number, and the string cannot be converted into a valid number.
So, I tried replacing:
cast(substr (it.remark, instr(it.remark,'-')+1,3 ) as integer)
with
to_number(substr (it.remark, instr(it.remark,'-')+1,3 ))
and even tried to_char but didn't work. However, the original script seems to work fine in sandbox database. I am wondering why this is happening. Any help is greatly appreciated.
Update:
Sample data it:
ID DATE NAME GROUP REMARK COMMENT ...
100 20-10-08 AABC X ACS LOCATION 1 - ABC IDD x105213-1
​101 20-10-08 AxB Y MN LOCATION 8 - ABC IDD x105244-2
...
Sample data sp:
ID DATE NAME GROUP label_id
105213 20-10-08 AABC X 1
​105244 20-10-08 AxB Y 2
...
It turns out that the error was caused by having 2 - in remark which lead to ambiguity and I just need the second one.
New question then:
How do I extract the last - in the value to join with another value in the other column?
Use cast with default null on conversion error to avoid exception and investigate the cause of the failed conversion.
Example
with dt as
(select '001' remark from dual union all
select ' 2' from dual union all
select 'OMG' from dual)
select substr(remark,1,3) txt,
cast (substr(remark,1,3) as INT default null on conversion error) num
from dt;
TXT NUM
--- ----------
001 1
2 2
OMG

Oracle xmltable query / ORA-19279: XPTY0004 - XQuery dynamic type mismatch: expected singleton

I have this query :
SELECT TYPE, IDVIEW, ATTRIBUTE, VALUE
FROM XML_IMPORT_REPOSITORY t
CROSS JOIN XMLTABLE ('for $item in /SRDBSW/OBJ_DF[#IdView="ICU-ASW"]/*[#IdView]
for $item_attr in $item/#*
return element {$item/name(.)}
{
element idview {$item/#IdView/string()},
element attr {$item_attr/local-name(.)},
element value {$item_attr/string()}
}
' PASSING t.XMLDATA COLUMNS
TYPE VARCHAR2(30) PATH 'local-name(.)',
IDVIEW VARCHAR2(30) PATH 'idview',
attribute VARCHAR2(30) PATH 'attr',
value VARCHAR2(30) PATH 'value' ) x
I´m getting this error :
ORA-19279: XPTY0004 - XQuery dynamic type mismatch: expected singleton
sequence - got multi-item sequence
19279. 00000 - "XPTY0004 - XQuery dynamic type mismatch: expected singleton sequence - got multi-item sequence"
I found the problem , the problem is this line :
element value {$item_attr/string()}
But can´t find a workaround to get the value of the attribute ...
where a sample off the xml
<OBJ_DF IdView="ICU-ASW" CategoryFlag="0" OwnerFlag="0" ObjLevel="Element" IsDefined="Y" ShortDescription="CONFIG Major function" ShortDescriptionCore="CONFIG Major function" LongDescription="CONFIG Major function Manual Load" Mnemonic="CONFIG Major function">
<TEXTUAL_CURVE_DF IdView="0001" ShortDescription="PhysSide octet" ShortDescriptionCore="PhysSide octet" LongDescription="Type identifying the physical side of a unit in 8 bits" Mnemonic="Physical_Side_Octet_T" CategoryFlag="0" OwnerFlag="0" IsDirect="Y" Type="CURVE" CurveType="Textual" RawFormat="Unsigned Integer">
<DIG_POINT_LIST>
<DIG_POINT LowValue="0" StatusText="SIDE_1" Mnemonic="Side_1" Ldesc="FCI/Config/Physical_Side_Octet.Side_1" HighValue="0"/>
<DIG_POINT LowValue="1" StatusText="SIDE_2" Mnemonic="Side_2" Ldesc="FCI/Config/Physical_Side_Octet.Side_2" HighValue="1"/>
</DIG_POINT_LIST>
</TEXTUAL_CURVE_DF>
<TEXTUAL_CURVE_DF IdView="0002" ShortDescription="Health_T" ShortDescriptionCore="Health_T" LongDescription="Type for Health of unit or equipment" Mnemonic="Health_T" CategoryFlag="0" OwnerFlag="0" IsDirect="Y" Type="CURVE" CurveType="Textual" RawFormat="Unsigned Integer">
<DIG_POINT_LIST>
<DIG_POINT LowValue="0" StatusText="UNHEALTHY" Mnemonic="Unhealthy" Ldesc="FCI/Config/Health.Unhealthy" HighValue="0"/>
<DIG_POINT LowValue="1" StatusText="HEALTHY" Mnemonic="Healthy" Ldesc="FCI/Config/Health.Healthy" HighValue="1"/>
</DIG_POINT_LIST>
</TEXTUAL_CURVE_DF>
<TEXTUAL_CURVE_DF IdView="0003" ShortDescription="Logical_Power_T" ShortDescriptionCore="Logical_Power_T" LongDescription="Type for Logical On or Off status of unit or equipment" Mnemonic="Logical_Power_T" CategoryFlag="0" OwnerFlag="0" IsDirect="Y" Type="CURVE" CurveType="Textual" RawFormat="Unsigned Integer">
<DIG_POINT_LIST>
<DIG_POINT LowValue="0" StatusText="OFF" Mnemonic="Off" Ldesc="FCI/Config/Logical_Power.Off" HighValue="0"/>
<DIG_POINT LowValue="1" StatusText="ON" Mnemonic="On" Ldesc="FCI/Config/Logical_Power.On" HighValue="1"/>
</DIG_POINT_LIST>
</TEXTUAL_CURVE_DF>
</OBJ_DF>
the query shoud return the name of the items and all is attribues
the working set is :
CREATE OR REPLACE directory XTDIR AS 'C:\Users\aadr\Documents\SCCOPEN\NEW-IMPORT\demo';
BEGIN
DBMS_XMLSCHEMA.registerSchema(
SCHEMAURL => 'http://www.w3.org/2001/XMLSchema',
SCHEMADOC => bfilename('XTDIR','SRDBSW_schema_full.xsd'));
END;
CREATE TABLE XML_IMPORT_REPOSITORY (xmlkey VARCHAR(20) PRIMARY KEY, xmlData XMLType)
xmltype column xmlData XMLSCHEMA "http://www.w3.org/2001/XMLSchema"
element "SRDBSW" tablespace USERS;
INSERT INTO XML_IMPORT_REPOSITORY(XMLKEY, XMLDATA) VALUES
('full',XMLType(bfilename('XTDIR', 'full.xml'), nls_charset_id('AL32UTF8')));
commit;
with all of this is not working , the reason I´m doing this is to increase preformace on the query whitout this the query is very slow whit large xmls files
This looks like bug 13060499, which is related to 7554407; see My Oracle Support doc ID 1373311.1. There isn't much info though. It's known to affect 11.2.0.2 but it isn't clear if or when it was fixed - I don't see the issue in 11.2.0.3 so it may have been quietly fixed in that patch set.
A workaround seems to be to add what should be a redundant index to the attribute reference:
element value {$item_attr[1]/string()}
But as that on its own doesn't seem to help, perhaps add it to everything:
SELECT TYPE, IDVIEW, ATTRIBUTE, VALUE
FROM XML_IMPORT_REPOSITORY t
CROSS JOIN XMLTABLE ('for $item in /SRDBSW/OBJ_DF[#IdView="ICU-ASW"]/*[#IdView]
for $item_attr in $item[1]/#*
return element {$item[1]/name(.)}
{
element idview {$item[1]/#IdView[1]/string()},
element attr {$item_attr[1]/local-name(.)},
element value {$item_attr[1]/string()}
}
' PASSING t.XMLDATA COLUMNS
TYPE VARCHAR2(30) PATH 'local-name(.)',
IDVIEW VARCHAR2(30) PATH 'idview',
attribute VARCHAR2(30) PATH 'attr',
value VARCHAR2(30) PATH 'value' ) x;
In 11.2.0.3 that gives the same result as not having the node index. I don't have an 11.2.0.2 instance to verify it on though (and SQL Fiddle, which is that version, fails without a helpful message).
You can also do this with a single for in the XQuery, by going straight to attribute level and then referring to the parent node with ../:
SELECT TYPE, IDVIEW, ATTRIBUTE, VALUE
FROM XML_IMPORT_REPOSITORY t
CROSS JOIN XMLTABLE ('for $item_attr in
/SRDBSW/OBJ_DF[#IdView="ICU-ASW"]/*[#IdView]/#*
return element {$item_attr[1]/../name(.)}
{
element idview {$item_attr[1]/../#IdView[1]/string()},
element attr {$item_attr[1]/local-name(.)},
element value {$item_attr[1]/string()}
}'
PASSING t.XMLDATA
COLUMNS
TYPE VARCHAR2(30) PATH 'local-name(.)',
IDVIEW VARCHAR2(30) PATH 'idview',
attribute VARCHAR2(30) PATH 'attr',
value VARCHAR2(30) PATH 'value' ) x;
I've left the [1] in just in case that is still helpful/needed. But SQL Fiddle now works with and without them, which is rather more promising.
SELECT x.* FROM XML_IMPORT_REPOSITORY t
CROSS JOIN XMLTABLE ('/SRDBSW/OBJ_DF/*[/SRDBSW/OBJ_DF/#IdView="ICU-ASW"]'
PASSING t.XMLDATA
COLUMNS IdView VARCHAR2(30) PATH '#IdView',
attr_name VARCHAR2(30) PATH 'local-name(.)') x
union all
SELECT z.* FROM XML_IMPORT_REPOSITORY tt
CROSS JOIN XMLTABLE ('/SRDBSW/OBJ_DF/*[/SRDBSW/OBJ_DF/#IdView="ICU-ASW"]/#*'
PASSING tt.XMLDATA
COLUMNS
attr_name VARCHAR2(30) PATH 'local-name(.)',
attr_value VARCHAR2(30) PATH '.') z
this is all must good for me ... if I find a way ( if there is one ) to separate "data" from the two query ...

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.

Expected CHAR got NUMBER

DB: Oracle 11g
Query:
SELECT CASE
WHEN rs.OPTION = '3'
THEN
(SELECT COUNT(DISTINCT ex.EXTS) AS TMPCOL0
FROM CRSIDM.SUB_OPTS ex
INNER JOIN CRSIDM.SUB_OPTS_GRP cg
ON cg.GROUP_ID = ex.GRP_ID
)
ELSE
(SELECT COUNT(DISTINCT ex.EXTS) AS TMPCOL0
FROM CRSIDM.SUB_OPTS ex
INNER JOIN CRSIDM.SUB_OPTS_POL cg
ON cg.GROUP_ID = ex.GRP_ID
)
END AS PROPTS
FROM PR_OPTS
I am getting error 'expected CHAR got NUMBER', here EXTS,GROUP_ID & GRP_ID are numeric. Then how there is a chance of expecting CHAR?
Generally when Oracle compares different datatypes such as a NUMBER with a CHARACTER, implicit conversion kicks in and all is well (provided the data can be converted.) For example, if you have a function that expects a CHARACTER value but you pass it a NUMBER, all is well - Oracle simply converts the NUMBER to character.
E.g. a function like this:
create or replace function get_something(p_id VARCHAR2) return number ...
works if you call it with this:
get_dno(10);
or this:
get_dno('10');
and in SQL:
select * from some_table where numeric_column = '10' -- no problem.
A popular place where you see this kind of error is with the return values in CASE statements. For instance, you'll get that error if you have something like this:
SQL> SELECT CASE WHEN 1 = 1 THEN '1' ELSE 2 END
2 FROM dual
3 ;
SELECT CASE WHEN 1 = 1 THEN '1' ELSE 2 END
*
ERROR at line 1:
ORA-00932: inconsistent datatypes: expected CHAR got NUMBER
(The datatype from the first WHEN clause is what it expects in the other WHEN/ELSE clauses that follow.)
But in your case the WHEN and THEN both return counts - the datatypes are consistent. So, I think you have a red-herring in there.
As Alex mentioned above, OPTION is a keyword and if you try and create a table with that as a column name, Oracle disagrees:
SQL> create table dummy
2 (option varchar2(10)
3 );
(option varchar2(10)
*
ERROR at line 2:
ORA-00904: : invalid identifier
This works:
SQL> create table dummy
2 (option_col varchar2(10)
3 );
Table created.
or you could do it with quotes:
SQL> create table dummy
2 ("option" varchar2(10));
Table created.
But now you're in a world of hurt - you need quotes from now on:
SQL> select option from dummy;
select option from dummy
*
ERROR at line 1:
ORA-00936: missing expression
SQL> select d.option from dummy d;
select d.option from dummy d
*
ERROR at line 1:
ORA-01747: invalid user.table.column, table.column, or column specification
With quotes:
SQL> select d."option" from dummy d;
no rows selected
So, if your query is really giving you "expected CHAR, got NUMBER", it looks to me like something is off.
Essentially, it means some of the fields you are using aren't compatible with each other. It's basically a "type mismatch". Just check to see if any types of CHAR are being used with types of NUMBER. Then you can either switch the type of one, or simply use a conversion as part of the query.
The issue is OPTION = '3', the quotation marks indicate that you're looking for a string containing the solitary character 3.
Try this instead:
SELECT CASE
WHEN rs.OPTION = 3
THEN
(SELECT COUNT(DISTINCT ex.EXTS) AS TMPCOL0
FROM CRSIDM.SUB_OPTS ex
INNER JOIN CRSIDM.SUB_OPTS_GRP cg
ON cg.GROUP_ID = ex.GRP_ID)
ELSE
(SELECT COUNT(DISTINCT ex.EXTS) AS TMPCOL0
FROM CRSIDM.SUB_OPTS ex
INNER JOIN CRSIDM.SUB_OPTS_POL cg
ON cg.GROUP_ID = ex.GRP_ID)
END AS PROPTS
FROM PR_OPTS

Resources