I'm doing my transition from T-SQL TO PL/SQL, in my first attempt I'm trying to create a stored procedure (PL/SQL) to load data into a table, but I'm getting an error:
PL/SQL: SQL Statement ignored
ORA-06550: line 29, column 4:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
Code:
declare
v_str VARCHAR2(32767) := '<ns0:ConnCustomerOrgServiceCreateRequest xmlns:ns0="http://tempuri.org" xmlns:ns6="http://schemas.microsoft.com/dynamics/2008/01/documents/ConnItemSvc" xmlns:ns4="http://schemas.microsoft.com/dynamics/2011/02/documents/DocumentPaging" xmlns:ns7="http://schemas.microsoft.com/dynamics/2011/02/documents/EntityKeyPage" xmlns:ns5="http://schemas.microsoft.com/dynamics/2006/02/documents/EntityKey" xmlns:ns1="http://schemas.microsoft.com/dynamics/2008/01/sharedtypes" xmlns:ns3="http://schemas.microsoft.com/dynamics/2006/02/documents/QueryCriteria" xmlns:ns8="http://schemas.microsoft.com/dynamics/2006/02/documents/EntityKeyList" xmlns:ns2="http://schemas.microsoft.com/dynamics/2008/01/documents/ConnCustomerOrg" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns2:ConnCustomerOrg>
<ns2:CustTable class="entity">
<ns2:AccountNum xsi:nil="true" />
<ns2:CreditMax>0</ns2:CreditMax>
<ns2:CustGroup>10</ns2:CustGroup>
<ns2:Organization class="entity">
<ns2:NumberOfEmployees xsi:nil="true" />
<ns2:OrganizationName class="entity">
<ns2:Name>PRUEBA</ns2:Name>
</ns2:OrganizationName>
</ns2:Organization>
</ns2:CustTable>
</ns2:ConnCustomerOrg>
</ns0:ConnCustomerOrgServiceCreateRequest>
';
v_xml XMLTYPE := XMLTYPE(v_str);
begin
select x.AccountNum, x.CreditMax
from t
,XMLTABLE('/ConnCustomerOrgServiceCreateRequest/ConnCustomerOrg/CustTable'
PASSING t.xml
COLUMNS AccountNum NUMBER PATH '/CustTable/AccountNum'
,CreditMax NUMBER PATH '/REC/CreditMax'
) x
end;
You must have an INTO clause when you are using a SELECT statement in a PL/SQL. INTO clause lets you store the values in a declared variable/s so you can access them inside the block whenever you want. Try this:
declare
v_str VARCHAR2(32767) := '<ns0:ConnCustomerOrgServiceCreateRequest xmlns:ns0="http://tempuri.org" xmlns:ns6="http://schemas.microsoft.com/dynamics/2008/01/documents/ConnItemSvc" xmlns:ns4="http://schemas.microsoft.com/dynamics/2011/02/documents/DocumentPaging" xmlns:ns7="http://schemas.microsoft.com/dynamics/2011/02/documents/EntityKeyPage" xmlns:ns5="http://schemas.microsoft.com/dynamics/2006/02/documents/EntityKey" xmlns:ns1="http://schemas.microsoft.com/dynamics/2008/01/sharedtypes" xmlns:ns3="http://schemas.microsoft.com/dynamics/2006/02/documents/QueryCriteria" xmlns:ns8="http://schemas.microsoft.com/dynamics/2006/02/documents/EntityKeyList" xmlns:ns2="http://schemas.microsoft.com/dynamics/2008/01/documents/ConnCustomerOrg" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns2:ConnCustomerOrg>
<ns2:CustTable class="entity">
<ns2:AccountNum xsi:nil="true" />
<ns2:CreditMax>0</ns2:CreditMax>
<ns2:CustGroup>10</ns2:CustGroup>
<ns2:Organization class="entity">
<ns2:NumberOfEmployees xsi:nil="true" />
<ns2:OrganizationName class="entity">
<ns2:Name>PRUEBA</ns2:Name>
</ns2:OrganizationName>
</ns2:Organization>
</ns2:CustTable>
</ns2:ConnCustomerOrg>
</ns0:ConnCustomerOrgServiceCreateRequest>
';
v_xml XMLTYPE := XMLTYPE(v_str);
v_accountnum VARCHAR2(2000);
v_creditmax VARCHAR2(2000);--i just assumed their datatypes since i cannot use %TYPE in here because i dont know what table accountnum and creditmax came from
BEGIN
SELECT x.AccountNum, x.CreditMax
INTO v_accountnum, v_creditmax
FROM t
,XMLTABLE('/ConnCustomerOrgServiceCreateRequest/ConnCustomerOrg/CustTable'
PASSING t.xml
COLUMNS AccountNum NUMBER PATH '/CustTable/AccountNum'
,CreditMax NUMBER PATH '/REC/CreditMax'
) x;
END;
Hope this helps.
You are missing a semicolon ; after your select statement. Every statement must be terminated with a ;.
declare
v_str VARCHAR2(32767) := '<ns0:ConnCustomerOrgServiceCreateRequest xmlns:ns0="http://tempuri.org" xmlns:ns6="http://schemas.microsoft.com/dynamics/2008/01/documents/ConnItemSvc" xmlns:ns4="http://schemas.microsoft.com/dynamics/2011/02/documents/DocumentPaging" xmlns:ns7="http://schemas.microsoft.com/dynamics/2011/02/documents/EntityKeyPage" xmlns:ns5="http://schemas.microsoft.com/dynamics/2006/02/documents/EntityKey" xmlns:ns1="http://schemas.microsoft.com/dynamics/2008/01/sharedtypes" xmlns:ns3="http://schemas.microsoft.com/dynamics/2006/02/documents/QueryCriteria" xmlns:ns8="http://schemas.microsoft.com/dynamics/2006/02/documents/EntityKeyList" xmlns:ns2="http://schemas.microsoft.com/dynamics/2008/01/documents/ConnCustomerOrg" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns2:ConnCustomerOrg>
<ns2:CustTable class="entity">
<ns2:AccountNum xsi:nil="true" />
<ns2:CreditMax>0</ns2:CreditMax>
<ns2:CustGroup>10</ns2:CustGroup>
<ns2:Organization class="entity">
<ns2:NumberOfEmployees xsi:nil="true" />
<ns2:OrganizationName class="entity">
<ns2:Name>PRUEBA</ns2:Name>
</ns2:OrganizationName>
</ns2:Organization>
</ns2:CustTable>
</ns2:ConnCustomerOrg>
</ns0:ConnCustomerOrgServiceCreateRequest>
';
v_xml XMLTYPE := XMLTYPE(v_str);
begin
select x.AccountNum, x.CreditMax
from t
,XMLTABLE('/ConnCustomerOrgServiceCreateRequest/ConnCustomerOrg/CustTable'
PASSING t.xml
COLUMNS AccountNum NUMBER PATH '/CustTable/AccountNum'
,CreditMax NUMBER PATH '/REC/CreditMax'
) x;
end;
Related
So I am trying to compile this trigger that prints some lines as outputs ( have the variables declared because i will be building onto this trigger using these variables later on). There's an existing trigger in the same database that does the same exact thing with a different table passing the same data, but my trigger seems to throw an error saying that 'new.PROCESSED is an invalid identifier'. What am I doing wrong? I may just not know what is fully going on here in my code... (thanks in advance!) value_value_id_se and cALCULATION_VALUE_CALCULATI329 are both functions in the system...
create or replace TRIGGER CAL_VAL
AFTER INSERT
ON XML_HOURS_LOAD
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
WHEN (
NEW.processed = 'N'
)
DECLARE
Value_ID Number;
pValue_ID Number;
pCalculation_ID NUMBER;
Calculation_ID Number;
Calculation_Value_ID Number;
p_Entity_Address_ID Varchar2(50);
New_Value_ID Number;
New_Calculation_ID Number;
New_Calculation_Value_ID Number;
BEGIN
Value_ID := value_value_id_seq.NEXTVAL;
New_Value_ID := Value_id ;
Calculation_Value_ID:=CALCULATION_VALUE_CALCULATI329.NEXTVAL;
calculation_id := Calculation_Calculation_ID_SEQ.NEXTVAL;
p_Entity_Address_ID := :New.EIA_ID_TX;
DBMS_OUTPUT.PUT_LINE(Get_energy_product_id(:NEW.Product_Name_Cd));
DBMS_OUTPUT.PUT_LINE(Get_Data_Source_Id(:NEW.Data_Source_Tx));
DBMS_OUTPUT.PUT_LINE(Get_Supply_Type_Id(:NEW.Supply_Type_Tx));
DBMS_OUTPUT.PUT_LINE(Get_State_CD(Get_entity_Id(p_Entity_Address_ID)));
DBMS_OUTPUT.PUT_LINE(Get_Entity_Address_ID(Get_Entity_ID(p_Entity_Address_ID)));
DBMS_OUTPUT.PUT_LINE('Value_ID' || Value_ID);
END;
In my stored procedure:
declare
v_xml xmltype;
begin
open v_cur for
Select xmlelement('el',xmlagg(xmlelement('el2'))) from table;
loop
fetch v_cur into v_xml; -- line where the error
*.....additional logic to parse v_xml*
end loop;
end;
I'm getting a "character string buffer too small" error when the record to be fetched into v_xml has a length > 4000. Do you guys have any idea on how to go about this? Thanks
If you use xmlagg(), you'll have to add .getclobval() to the surrounding xmlelement() since the char limit is 4000 on xmlagg(). Obviously this means you'll be using clobs instead of xmltype but you have no choice, you'll have to cast back to xmltype later if needed. Example below:
declare
v_xml clob; -- Use CLOB
begin
open v_cur for
Select xmlelement("el",xmlagg(xmlelement("el2", tab_col))).getclobval() from table; -- add .getclobval()
loop
fetch v_cur into v_xml; -- line where the error
*.....additional logic to parse v_xml*
end loop;
end;
Maybe you're using old Oracle version? There have been some limitations in past. For me it works with 10 000 000 rows:
declare
v_xml xmltype;
begin
select xmlelement("el", xmlagg(xmlelement("el2")))
into v_xml from (select 1 from dual connect by level <= 10000000);
end;
I have XML file that's stored in the clob column of the table in DB.
<?xml version="1.0" encoding="UTF-8"?>
<document>
<row>
<organization>asdklfjas;kldfj;LASKJFAS</organization>
<phones>sjhdfhjaghjskfg</phones>
<persons>hkjg</persons>
</row>
</document>
I'm using DBMS_XMLDOM package for parse it.
declare
v_clob clob;
v_doc dbms_xmldom.domdocument;
begin
...
v_doc := dbms_xmldom.newdomdocument(v_clob);
v_domelement := dbms_xmldom.getdocumentelement(v_doc);
...
end;
I need simply to get value from some element, for example <persons>. How can I do it?
There is also the option to use XslProcessor functions together with XPath:
DECLARE
v_Clob CLOB;
v_Doc XmlDom.DomDocument;
v_RootNode XmlDom.DomNode;
v_Value VARCHAR2(128);
BEGIN
...
v_Doc := XmlDom.NewDomDocument(v_Clob);
v_RootNode := XmlDom.MakeNode(XmlDom.GetDocumentElement(v_Doc));
v_Value := XmlDom.GetNodeValue(
XslProcessor.SelectSingleNode(v_RootNode, '/document/row[1]/persons/text()'));
...
END;
I found what I was searching:
...
v_doc := dbms_xmldom.newdomdocument(v_clob);
v_nodelist := dbms_xmldom.getelementsbytagname(v_doc, 'persons');
v_node := dbms_xmldom.getfirstchild(dbms_xmldom.item(v_nodelist, 0));
v_person := dbms_xmldom.getnodevalue(v_node);
...
To get XML Element value you can use either DBMS_XMLDOM or XslProcessor packages.
Refer to my answer here to construct and DBMS_XMLDOM.DOMDocument from CLOB column. Then use the below method to extract element value.
FUNCTION Get_Node_Value_From_Doc(
v_Doc IN DBMS_XMLDOM.DomDocument) RETURN VARCHAR2
IS
v_Clob CLOB;
v_RootNode DBMS_XMLDOM.DomNode;
v_Value VARCHAR2(2000);
BEGIN
v_RootNode := DBMS_XMLDOM.MakeNode(XmlDom.GetDocumentElement(v_Doc));
v_Value := DBMS_XMLDOM.GetNodeValue(XslProcessor.SelectSingleNode(v_RootNode,
'/soap:Envelope/soap:Body/GetLiveAnalysisIDSResponse[1]/AnalysisIDs[1]/guid[1]/text()'
,'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns="https://www.testkid.net/"'));
RETURN v_Value;
END Get_Node_Value_From_Doc;
Providing correct namespace is important when dealing with SOAP XML messages.
This is the code I am currently using:
SET serveroutput ON
CREATE OR REPLACE
PROCEDURE test_proc(i_xml varchar2)
IS
l_name VARCHAR2(20);
l_age NUMBER;
l_xml xmltype;
BEGIN
l_xml := xmltype(i_xml);
FOR x IN
(SELECT VALUE(p) col_val
FROM TABLE(XMLSEQUENCE(EXTRACT(l_xml, '/ROWSET/ROW'))) p
)
LOOP
IF x.col_val.existSNode('/ROW/name/text()') > 0 THEN
l_name:= x.col_val.EXTRACT('/ROW/name/text()').getstringVal();
END IF;
IF x.col_val.existSNode('/ROW/age/text()') > 0 THEN
l_age := x.col_val.EXTRACT('/ROW/age/text()').getstringVal();
END IF;
end loop;
end;
/
BEGIN
test_proc('<ROWSET>
<ROW>
<name>aa</name>
<age>20</age>
</ROW>
<ROW>
<name>bbb</name>
<age>25</age>
</ROW>
</ROWSET>');
END;
/
The above code uses xml to extract and save the existing node values to particular local variables. It is been used in the case for multiple sets of data and is working fine. I just wanted to know whether can I able to use the same without "for x loop", because I will only have one data in the i_xml from now onwards and I will only have either
name or age tags .
The following code should be used to save into l_name or l_age without the "loop" method like I used above:
<ROWSET>
<ROW>
<name>aa</name>
</ROW>
</ROWSET>
or
<ROWSET>
<ROW>
<age>18</age>
</ROW>
</ROWSET>
/
And I've tried using the following:
SELECT
CASE
WHEN VALUE(p).existsNode('/ROW/name/text()') = 1
THEN p.EXTRACT('/ROW/name/text()').getstringVal()
WHEN VALUE(P).existsNode('/ROW/age/text()') = 1
THEN p.EXTRACT('/ROW/age/text()').getstringVal()
END
INTO l_new
FROM TABLE(xmlsequence(EXTRACT(l_xml, '/ROWSET/ROW'))) p;
/
Any better way is appreciated.. Thanks
If you're really sure you'll only have one ROW then you can do:
begin
l_xml := xmltype(i_xml);
if l_xml.existsnode('/ROWSET/ROW/name') > 0 then
l_name := l_xml.extract('/ROWSET/ROW/name/text()').getstringval();
end if;
if l_xml.existsnode('/ROWSET/ROW/age') > 0 then
l_age := l_xml.extract('/ROWSET/ROW/age/text()').getnumberval();
end if;
end;
That will work if you have name or age, or both, or neither (where 'work' means doesn't error, at least). If you did have more than one row it would concatenate the results, so with your original data, l_name would be aabbb, and l_age would be 2025. Which might not be what you expect.
I am trying to insert records into a table using insert....select...stmt in a oracle stored procedure. How do find the number of records inserted using SQLERRD?
recIn number;
Insert into t1 ....Select.....;
recIn := SQLCA.SQLERRD(3);
....
....
PLS-00201: identifier 'SQLCA.SQLERRD' must be declared
is the error message thrown. How do you declare SQLCA.SQLERRD?
using Oracle 9.2
bcs
Are you using PL/SQL? Or are you using Pro*C/C++? SQLCA.SQLERRD would be defined in Pro*C/C++, it would not be defined in PL/SQL. Since you didn't tag the question for Pro*C, I'm guessing that you're just using PL/SQL.
In PL/SQL, you simply reference SQL%ROWCOUNT after running a SQL statement to get the row count. Something like
DECLARE
l_num_rows INTEGER;
BEGIN
INSERT INTO t1( <<list of columns>> )
SELECT <<list of columns>>
FROM <<some tables>>
WHERE <<some predicates>>
l_num_rows := sql%rowcount;
dbms_output.put_line( 'The statement inserted ' || l_num_rows || ' rows.';
END;