Extracting xmlsequence from another xmlsequance in SQL - sql

I have small problem with xmlsequence. I am codding in PL-SQL (Oracle)
Let's say, my XML looks like this:
<Row name="Row1">
<Field name="Filed1">
<Value1>
</Value1>
</Field>
<Row name="Row2inRow1">
<Field name="Filed2">
<Value1>
</Value1>
</Field>
</Row>
<Row name="Row2inRow1">
<Field name="Filed2">
<Value1>
</Value1>
</Field>
</Row>
<Row name="Row1">
<Field name="Filed1">
<Value1>
</Value1>
</Field>
<Row name="Row2inRow1">
<Field name="Filed2">
<Value1>
</Value1>
</Field>
</Row>
<Row name="Row2inRow1">
<Field name="Filed2">
<Value1>
</Value1>
</Field>
</Row>
It has 2x same "Row1" which is multiplicated, what's more inside Row1 I have multiplicated "Row2inRow1".
The problem is, I would like to select values from Ro2InRow1 and from Row1, to concat them, the effect should be:
Value1 (from 1st Row1) || Value1 (from 1st Row2inRow1)
Value1(from 1st Row1) || Value1 (from 2nd Row2InRow1)
Value1 (from 2nd Row1) || Value1 (from 3rd Row2inRow1)
Value1(from 2nd Row1) || Value1 (from 4th Row2InRow1)
I've tried to code is somehow, but I can't force my query to work right:
declare
xml_data xmldata;
begin
for rec1 in(select extractvalue(value(x),'//Field[#name="Filed1"]/Value1') ValueOfField1,
from table(xmlsequence(extract(xml_data.data,'//Row[#name="Row1"]')))x )
loop
dbms_output.put_line('1 : '|| ValueOfField1);
for rec2 in(select extractvalue(value(x),'//Field[#name="Filed2"]/Value1') ValueOfField2,
from table(xmlsequence(extract(xml_data.data,'//Row[#name="Row2inRow1"]')))k ) --? What here!
loop
dbms_output.put_line('1 : '|| ValueOfField2);
end loop;
end loop;
end;
Any ideas ? :(

Related

Update 3rd level deep field value in an XML using xQuery

I have the following sample XML and I am looking to Update:
AttendeeID to 7878 (will be a sql variable) where sequence = 1 (will be a sql variable)
Expected output is to see 7878 in the AttendeeID field's value. When I run any of the 2 options I tried, it does not yield the correct result. For Eg. Delete works but the element is not added. Replace value does not update the value.
Any inputs are highly appreciated. Thank you.
--------XML ---------------------------
DECLARE #cartXML XML =
'<OBJECT CLASS="Test1" ID="-1" FULL="FULL" VERSION="1">
<FIELD NAME="OrderDate">20220619</FIELD>
<FIELD NAME="OrderParty">Individual</FIELD>
<FIELD NAME="ShipToID">34567</FIELD>
<FIELD NAME="ShipToAddress1">123 Test Street</FIELD>
<FIELD NAME="ShipToCity">TestCity</FIELD>
<FIELD NAME="ShipToState">IL</FIELD>
<FIELD NAME="ShipTocountry">USA</FIELD>
<FIELD NAME="TaxNumber">444</FIELD>
<FIELD NAME="DiscountCode">Summer22</FIELD>
<SUBTYPE NAME="SubType1">
<OBJECT NAME="SubType111" ID="-1">
<FIELD NAME="TestID">-1</FIELD>
<FIELD NAME="Sequence">1</FIELD>
<FIELD NAME="ParentSequence">-1</FIELD>
<FIELD NAME="ExtID">-1</FIELD>
<FIELD NAME="ExtName">ABC</FIELD>
</OBJECT>
<OBJECT NAME="SubType111" ID="-1">
<FIELD NAME="TestID">-1</FIELD>
<FIELD NAME="Sequence">2</FIELD>
<FIELD NAME="ParentSequence">1</FIELD>
<FIELD NAME="ExtID">-1</FIELD>
<FIELD NAME="ExtName">DEF</FIELD>
<FIELD NAME="__ExtendedData"><OBJECT
CLASS="Meet123" ID="-1" FULL="FULL"
VERSION="1"><FIELD
NAME="OrderDetailID">-1</FIELD><FIELD
NAME="OrderID">-1</FIELD><FIELD
NAME="Sequence">0</FIELD><FIELD
NAME="AttendeeID">123</FIELD><FIELD NAME="AttendeeID_Name">Test, Mark/I
H 6</FIELD><FIELD
NAME="ShowList">1</FIELD><FIELD
NAME="BdgeName">Mark</FIELD><FIELD
NAME="BadgeCompanyName">I H 6</FIELD>
</OBJECT></FIELD>
</OBJECT>
<OBJECT NAME="SubType111" ID="-1">
<FIELD NAME="TestID">-1</FIELD>
<FIELD NAME="Sequence">3</FIELD>
<FIELD NAME="ParentSequence">1</FIELD>
<FIELD NAME="ExtID">-1</FIELD>
<FIELD NAME="ExtName">GHI</FIELD>
</OBJECT>
</SUBTYPE>
<SUBTYPE NAME="SubType2"/>
<SUBTYPE NAME="SubType3"/>
</OBJECT>';
-----------------------SQL -----------------------
select #cartXML as originalXML
DECLARE #ID as int ,#productID as int, #attendeeId as int = 7878,
#sequenceId as int, #orderLineXML as XML , #ExtendedAttrDetail as XML
SET #sequenceId = 2
select #orderlineXML = c.query('.'), #ExtendedAttrDetail = w.query('.') from
#cartXML.nodes('/OBJECT/SUBTYPE/OBJECT[FIELD[#NAME="Sequence"]/text()=sql:variable("#sequenceId")]') t1(c)
Cross APPLY (VALUES(TRY_CAST(c.query('FIELD[#NAME="__ExtendedData"]').value('.','NVARCHAR(MAX)') AS XML)))AS t2(w)
-----This works..But I am looking to alter #cartXML as it contains the entire XML
SET #ExtendedAttrDetail.modify('replace value of
(/OBJECT/FIELD[#NAME="AttendeeID"]/text())[1]
with sql:variable("#attendeeId")')
--select #ExtendedAttrDetail
------- Option 1( Preferred)---does not work--
SET #cartXML.modify ('replace value of
(/OBJECT/SUBTYPE/OBJECT[FIELD[#NAME="Sequence"]/text()=sql:variable("#sequenceId")]/FIELD[#NAME="__ExtendedData"]/OBJECT/FIELD[#NAME="AttendeeID"]/text())[1] with sql:variable("#attendeeId")')
select #cartXML as ModifiedDirectly
---Option 2 (Insert does not add correctly )
--SET #cartXML.modify('delete
--/OBJECT/SUBTYPE/OBJECT[FIELD[#NAME="Sequence"]/text()=sql:variable("#sequenceId")]
--/FIELD[#NAME="__ExtendedData"]');
--SET #cartXML.modify('insert sql:variable("#ExtendedAttrDetail") into
--(/OBJECT/SUBTYPE/OBJECT[FIELD[#NAME="Sequence"]/text()=sql:variable("#sequenceId")])
--[1]');
--SELECT #cartXML as UpdatedXL;
Please try the following solution.
The issue is that the XML fragment in question is encoded.
SQL
DECLARE #cartXML XML =
N'<OBJECT CLASS="Test1" ID="-1" FULL="FULL" VERSION="1">
<FIELD NAME="OrderDate">20220619</FIELD>
<FIELD NAME="OrderParty">Individual</FIELD>
<FIELD NAME="ShipToID">34567</FIELD>
<FIELD NAME="ShipToAddress1">123 Test Street</FIELD>
<FIELD NAME="ShipToCity">TestCity</FIELD>
<FIELD NAME="ShipToState">IL</FIELD>
<FIELD NAME="ShipTocountry">USA</FIELD>
<FIELD NAME="TaxNumber">444</FIELD>
<FIELD NAME="DiscountCode">Summer22</FIELD>
<SUBTYPE NAME="SubType1">
<OBJECT NAME="SubType111" ID="-1">
<FIELD NAME="TestID">-1</FIELD>
<FIELD NAME="Sequence">1</FIELD>
<FIELD NAME="ParentSequence">-1</FIELD>
<FIELD NAME="ExtID">-1</FIELD>
<FIELD NAME="ExtName">ABC</FIELD>
</OBJECT>
<OBJECT NAME="SubType111" ID="-1">
<FIELD NAME="TestID">-1</FIELD>
<FIELD NAME="Sequence">2</FIELD>
<FIELD NAME="ParentSequence">1</FIELD>
<FIELD NAME="ExtID">-1</FIELD>
<FIELD NAME="ExtName">DEF</FIELD>
<FIELD NAME="__ExtendedData"><OBJECT
CLASS="Meet123" ID="-1" FULL="FULL"
VERSION="1"><FIELD
NAME="OrderDetailID">-1</FIELD><FIELD
NAME="OrderID">-1</FIELD><FIELD
NAME="Sequence">0</FIELD><FIELD
NAME="AttendeeID">123</FIELD><FIELD NAME="AttendeeID_Name">Test, Mark/I
H 6</FIELD><FIELD
NAME="ShowList">1</FIELD><FIELD
NAME="BdgeName">Mark</FIELD><FIELD
NAME="BadgeCompanyName">I H 6</FIELD>
</OBJECT></FIELD>
</OBJECT>
<OBJECT NAME="SubType111" ID="-1">
<FIELD NAME="TestID">-1</FIELD>
<FIELD NAME="Sequence">3</FIELD>
<FIELD NAME="ParentSequence">1</FIELD>
<FIELD NAME="ExtID">-1</FIELD>
<FIELD NAME="ExtName">GHI</FIELD>
</OBJECT>
</SUBTYPE>
<SUBTYPE NAME="SubType2"/>
<SUBTYPE NAME="SubType3"/>
</OBJECT>';
DECLARE #ExtendedData XML
, #attendeeId INT = 770;;
-- Step #1: select XML fragment in question as real XML data type
SELECT #ExtendedData = w
FROM #cartxml.nodes('/OBJECT/SUBTYPE/OBJECT[#ID="-1"]') as t1(c)
CROSS APPLY (VALUES(TRY_CAST(c.query('FIELD[#NAME="__ExtendedData"]').value('.','NVARCHAR(MAX)') AS XML))) AS t2(w)
WHERE w.exist('/OBJECT[#CLASS="Meet123"]') = 1;
-- Step #2: remove encoded XML fragment
SET #cartXML.modify('replace value of (/OBJECT/SUBTYPE[#NAME="SubType1"]/OBJECT/FIELD[#NAME="__ExtendedData"]/text())[1]
with ""');
-- Step #3: modify AttendeeID
SET #ExtendedData.modify('replace value of
(/OBJECT/FIELD[#NAME="AttendeeID"]/text())[1]
with sql:variable("#attendeeId")');
-- Step #4: insert real XML fragment
SET #cartXML.modify('insert sql:variable("#ExtendedData") into
(/OBJECT/SUBTYPE[#NAME="SubType1"]/OBJECT/FIELD[#NAME="__ExtendedData"])[1]');
-- test
SELECT #cartXML;

Convert nested XML via XQuery to flat xml

I've a nested piece of XML i want to insert in to SQL.
Import XML:
<RECORD>
<RECID>118810</RECID>
<FIELD TYPE="C">
<NAME>proj_code</NAME>
<VALUE>118810</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>sub_nr</NAME>
<VALUE>99900</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>proj_desc</NAME>
<VALUE>Nagekomen kosten Oktober 2018</VALUE>
</FIELD>
<FIELD TYPE="N">
<NAME>pro_stat</NAME>
<VALUE>9</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>comment</NAME>
<VALUE></VALUE>
</FIELD>
</RECORD>
I want to convert via XQuery it into:
<RECORD>
<RECID>118810</RECID>
<proj_code>118810</proj_code>
<sub_nr>99900</sub_nr>
<proj_desc>Nagekomen kosten Oktober 2018</proj_desc>
<pro_stat>9</pro_stat>
<comment></comment>
</RECORD>
so i can import it into SQL.
Any thoughts?
As Martin Honnen pointed out, MS SQL Server XQuery doesn't support computed dynamic element names, just literals. Unfortunately, including even the latest SQL Server 2019. Here is an ugly solution.
SQL
DECLARE #xml XML = N'<root>
<RECORD>
<RECID>118810</RECID>
<FIELD TYPE="C">
<NAME>proj_code</NAME>
<VALUE>118810</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>sub_nr</NAME>
<VALUE>99900</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>proj_desc</NAME>
<VALUE>Nagekomen kosten Oktober 2018</VALUE>
</FIELD>
<FIELD TYPE="N">
<NAME>pro_stat</NAME>
<VALUE>9</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>comment</NAME>
<VALUE></VALUE>
</FIELD>
</RECORD>
<RECORD>
<RECID>118811</RECID>
<FIELD TYPE="C">
<NAME>proj_code</NAME>
<VALUE>118811</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>sub_nr</NAME>
<VALUE>99901</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>proj_desc</NAME>
<VALUE>Nagekomen kosten November 2019</VALUE>
</FIELD>
<FIELD TYPE="N">
<NAME>pro_stat</NAME>
<VALUE>19</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>comment</NAME>
<VALUE>wow</VALUE>
</FIELD>
</RECORD>
</root>';
DECLARE #tbl TABLE (ID INT IDENTITY(1,1) PRIMARY KEY, RECID VARCHAR(10), [col_name] VARCHAR(20), [col_value] VARCHAR(100));
INSERT INTO #tbl
SELECT c.value('(../RECID/text())[1]', 'VARCHAR(100)') AS [RECID]
, c.value('(NAME/text())[1]', 'VARCHAR(30)') AS [name]
, c.value('(VALUE/text())[1]', 'VARCHAR(100)') AS [value]
FROM #xml.nodes('root/RECORD/FIELD') AS t(c);
DECLARE #RowCount INT = (SELECT MAX(ID) FROM #tbl)
, #recID varchar(10) = (SELECT TOP(1) RECID FROM #tbl WHERE ID = 1)
, #xml_data VARCHAR(MAX) = '<root><RECORD>';
WHILE #RowCount > 0 BEGIN
SELECT #xml_data += IIF(#recID != RECID, '</RECORD><RECORD>', '') +
--'<' + [col_Name] + '>' + COALESCE([col_value],'') + '</' + [col_Name] + '>'
CONCAT('<',[col_Name],'>',[col_value],'</',[col_Name],'>')
, #recID = RECID
FROM #tbl
ORDER BY ID DESC OFFSET #RowCount - 1 ROWS FETCH NEXT 1 ROWS ONLY;
SET #RowCount -= 1;
END;
SET #xml_data += '</RECORD></root>';
SELECT CAST(#xml_data AS XML);
Simply map each RECORD to a new one where you map all FIELDs to elements with the name from NAME and the value from VALUE:
RECORD !
<RECORD>
{
RECID,
FIELD ! element { NAME } { data(VALUE) }
}
</RECORD>
https://xqueryfiddle.liberty-development.net/nbUY4kB
For XQuery 1 you would need to use for return instead of the map operator !:
for $record in //RECORD
return
<RECORD>
{
$record/RECID,
for $field in $record/FIELD
return element { $field/NAME } { data($field/VALUE) }
}
</RECORD>
https://xqueryfiddle.liberty-development.net/nbUY4kB/1
I tried this:
DECLARE #xml xml;
SET #xml =N'
<RECORD>
<RECID>118810</RECID>
<FIELD TYPE="C">
<NAME>proj_code</NAME>
<VALUE>118810</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>sub_nr</NAME>
<VALUE>99900</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>proj_desc</NAME>
<VALUE>Nagekomen kosten Oktober 2018</VALUE>
</FIELD>
<FIELD TYPE="N">
<NAME>pro_stat</NAME>
<VALUE>9</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>comment</NAME>
<VALUE></VALUE>
</FIELD>
</RECORD>
<RECORD>
<RECID>118811</RECID>
<FIELD TYPE="C">
<NAME>proj_code</NAME>
<VALUE>118811</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>sub_nr</NAME>
<VALUE>99900</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>proj_desc</NAME>
<VALUE>Nagekomen kosten November 2018</VALUE>
</FIELD>
<FIELD TYPE="N">
<NAME>pro_stat</NAME>
<VALUE>9</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>comment</NAME>
<VALUE></VALUE>
</FIELD>
</RECORD>
';
SELECT #xml.query('
for $record in //RECORD
return
<RECORD>
{
$record/RECID,
for $field in $record/FIELD
return element { $field/NAME } { data($field/VALUE) }
}
</RECORD>
' ) as result
But i get an error on the return element part:
XQuery [query()]: Only constant expressions are supported for the name expression of computed element and attribute constructors.
This is the final version with select for inserting it into SQL:
DECLARE #xml XML = N'
<AVXML>
<SIGNONMSGRS>
<DTSERVER>2019-09-10T15:54:32</DTSERVER>
<APPID>ACCOUNTVIEW</APPID>
<APPVER>0908-</APPVER>
</SIGNONMSGRS>
<EBUSMSGSRS>
<EBUSQRYRS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RECORD>
<RECID>118810</RECID>
<FIELD TYPE="C">
<NAME>proj_code</NAME>
<VALUE>118810</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>sub_nr</NAME>
<VALUE>99900</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>proj_desc</NAME>
<VALUE>Nagekomen kosten Oktober 2018</VALUE>
</FIELD>
<FIELD TYPE="N">
<NAME>pro_stat</NAME>
<VALUE>9</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>comment</NAME>
<VALUE></VALUE>
</FIELD>
</RECORD>
<RECORD>
<RECID>118811</RECID>
<FIELD TYPE="C">
<NAME>proj_code</NAME>
<VALUE>118811</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>sub_nr</NAME>
<VALUE>99901</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>proj_desc</NAME>
<VALUE>Nagekomen kosten November 2019</VALUE>
</FIELD>
<FIELD TYPE="N">
<NAME>pro_stat</NAME>
<VALUE>19</VALUE>
</FIELD>
<FIELD TYPE="C">
<NAME>comment</NAME>
<VALUE>wow</VALUE>
</FIELD>
</RECORD>
</EBUSQRYRS>
</EBUSMSGSRS>
</AVXML>
';
DECLARE #tbl TABLE (ID INT IDENTITY(1,1) PRIMARY KEY, RECID VARCHAR(10), [col_name] VARCHAR(20), [col_value] VARCHAR(100));
INSERT INTO #tbl
SELECT c.value('(../RECID/text())[1]', 'VARCHAR(100)') AS [RECID]
, c.value('(NAME/text())[1]', 'VARCHAR(30)') AS [name]
, c.value('(VALUE/text())[1]', 'VARCHAR(500)') AS [value]
FROM #xml.nodes('//RECORD/FIELD') AS t(c);
DECLARE #RowCount INT = (SELECT MAX(ID) FROM #tbl)
, #recID varchar(10) = (SELECT TOP(1) RECID FROM #tbl WHERE ID = 1)
, #xml_data VARCHAR(MAX) = '<root><RECORD>';
WHILE #RowCount > 0 BEGIN
SELECT #xml_data +=
IIF(#recID != RECID,
'<RECID>' + #recID + '</RECID>' +
'</RECORD><RECORD>',
'') +
CONCAT('<',[col_Name],'>',[col_value],'</',[col_Name],'>')
, #recID = RECID
FROM #tbl
ORDER BY ID DESC OFFSET #RowCount - 1 ROWS FETCH NEXT 1 ROWS ONLY;
SET #RowCount -= 1;
END;
SET #xml_data += '<RECID>' + #recID + '</RECID>' + '</RECORD></root>';
DECLARE #handler int;
exec sys.sp_xml_preparedocument #handler OUTPUT, #xml_data;
--print #xml_data
select *
from OPENXML(#handler,'/root/RECORD',11)
WITH
(
id nvarchar(50) 'RECID',
proj_code nvarchar(50) 'proj_code',
sub_nr nvarchar(50) 'sub_nr',
proj_desc nvarchar(1000) 'proj_desc',
pro_stat nvarchar(50) 'pro_stat',
comment nvarchar(50) 'comment'
)
exec sys.sp_xml_removedocument #handler

Append unit to a XML column value in SQL Server

I have a table with a XML column for storing the file details. Now I want to update the size node in the XML column with KB or MB according to the value.
Sample data:
<FileInfo>
<Field Name="Filename">PV_1_PV_4126_C-482N-25457-005_V1.pdf</Field>
<Field Name="Created">02/21/2017</Field>
<Field Name="Modified">02/21/2017</Field>
<Field Name="Uploaded By">2120</Field>
<Field Name="Uploaded On">02/21/2017</Field>
<Field Name="Size">755</Field>
</FileInfo>
Expected result:
<FileInfo>
<Field Name="Filename">PV_1_PV_4126_C-482N-25457-005_V1.pdf</Field>
<Field Name="Created">02/21/2017</Field>
<Field Name="Modified">02/21/2017</Field>
<Field Name="Uploaded By">2120</Field>
<Field Name="Uploaded On">02/21/2017</Field>
<Field Name="Size">755 KB</Field>
</FileInfo>
Sample data:
<FileInfo>
<Field Name="Filename">PV_1_PV_4126_C-482N-25457-005_V1.pdf</Field>
<Field Name="Created">02/21/2017</Field>
<Field Name="Modified">02/21/2017</Field>
<Field Name="Uploaded By">2120</Field>
<Field Name="Uploaded On">02/21/2017</Field>
<Field Name="Size">1024</Field>
</FileInfo>
Expected result:
<FileInfo>
<Field Name="Filename">PV_1_PV_4126_C-482N-25457-005_V1.pdf</Field>
<Field Name="Created">02/21/2017</Field>
<Field Name="Modified">02/21/2017</Field>
<Field Name="Uploaded By">2120</Field>
<Field Name="Uploaded On">02/21/2017</Field>
<Field Name="Size">1 MB</Field>
</FileInfo>
You can use an updateable CTE
DECLARE #dummy TABLE(YourXMLColumn XML);
INSERT INTO #dummy VALUES
(
N'<FileInfo>
<!--More fields-->
<Field Name="Size">755</Field>
</FileInfo> '
)
,(
N'<FileInfo>
<!--More fields-->
<Field Name="Size">1024</Field>
</FileInfo> '
);
WITH ReplaceValue AS
(
SELECT YourXMLColumn
,ca2.newSize
FROM #dummy AS d
CROSS APPLY(SELECT d.YourXMLColumn.value(N'(/FileInfo/Field[#Name="Size"]/text())[1]',N'int')) AS ca1(size)
CROSS APPLY(SELECT CASE WHEN ca1.size % 1024=0
THEN CAST(ca1.size/1024 AS VARCHAR(10)) + ' MB'
ELSE CAST(ca1.size AS VARCHAR(10)) + ' KB' END) AS ca2(newSize)
)
UPDATE ReplaceValue SET YourXMLColumn.modify(N'replace value of (/FileInfo/Field[#Name="Size"]/text())[1] with sql:column("newSize")');
SELECT * FROM #dummy;
First I read the value of the "Size" field. If it is divideable by 1024 it will be written as "MB", otherwise the value remains as "KB".
The final UPDATE will update the CTE, but this affects the tables column actually. The SELECT shows the modified table data.

How to do multiple loops through XML in PL/SQL

My XML looks like this
<data>
<row>
<id>1</id>
<name>John</name>
<name>Jack</name>
</row>
<row>
<id>2</id>
<name>Scott</name>
<name>Chuck</name>
<name>Kim</name>
</row>
</data>
I would like output:
->1
-->John
-->Jack
->2
-->Scott
-->Chuck
-->Kim
My current code looks like this:
DECLARE
X XMLTYPE := XMLTYPE('<?xml version="1.0" ?>
<data>
<row>
<id>1</id>
<name>John</name>
<name>Jack</name>
</row>
<row>
<id>2</id>
<name>Scott</name>
<name>Chuck</name>
<name>Kim</name>
</row>
</data>');
BEGIN
FOR R IN (SELECT EXTRACTVALUE(VALUE(P), '/row/id/text()') AS NAME
FROM TABLE(XMLSEQUENCE(EXTRACT(X, '//data/row'))) P)
LOOP
DBMS_OUTPUT.PUT_LINE('-->' || R.NAME);
END LOOP;
END;
I would need one more loop inside a row to loop through name tag, but I don't know how to do it.
A little help would be appreciated.
I figured it by myself:
DECLARE
X XMLTYPE := XMLTYPE('<?xml version="1.0" ?>
<data>
<row>
<id>1</id>
<promet>
<name>John</name>
<name>Jack</name>
</promet>
</row>
<row>
<id>2</id>
<promet>
<name>Scott</name>
<name>Chuck</name>
<name>Kim</name>
</promet>
</row>
</data>');
BEGIN
FOR R IN (SELECT EXTRACTVALUE(VALUE(P), '/row/id/text()') AS ID,
EXTRACT(VALUE(P), '/row/promet') AS PROMET
FROM TABLE(XMLSEQUENCE(EXTRACT(X, '//data/row'))) P)
LOOP
DBMS_OUTPUT.PUT_LINE('-->' || R.ID);
FOR R1 IN (SELECT EXTRACTVALUE(VALUE(T1), '/name/text()') AS NAME
FROM TABLE(XMLSEQUENCE(EXTRACT(R.PROMET, 'promet/name'))) T1)
LOOP
DBMS_OUTPUT.PUT_LINE('-->' || R1.NAME);
END LOOP;
END LOOP;
END;

How to parse data from a CLOB in SQL Server?

I would like to use OPENROWSET with the BULK command to load data into SQL Server as a CLOB, and as a second step to parse the CLOB and load read the data as a table.
E.g.:
SELECT BulkColumn
FROM OPENROWSET (BULK 'c:\somedir\somefile.txt', SINGLE_CLOB) TheFile
yields:
BulkColumn
Col1,Col2,Col3,1,2,3,1,2,3,1,2,3,1,2,3
I want to select this as:
Col1 Col2 Col3
1 2 3
1 2 3
1 2 3
Create a format file and use OPENROWSET or BULK INSERT to import data from text file.
Example format.xml:
<?xml version="1.0" ?>
<BCPFORMAT xmlns="http://schemas.microsoft.com/sqlserver/2004/bulkload/format" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RECORD>
<FIELD ID="1" xsi:type="CharTerm" TERMINATOR="," MAX_LENGTH="1" />
<FIELD ID="2" xsi:type="CharTerm" TERMINATOR="," MAX_LENGTH="1" />
<FIELD ID="3" xsi:type="CharTerm" TERMINATOR="," MAX_LENGTH="1" />
</RECORD>
<ROW>
<COLUMN SOURCE="1" NAME="Col1" xsi:type="SQLNVARCHAR" />
<COLUMN SOURCE="2" NAME="Col2" xsi:type="SQLNVARCHAR" />
<COLUMN SOURCE="3" NAME="Col3" xsi:type="SQLNVARCHAR" />
</ROW>
</BCPFORMAT>
This is the key line:
<FIELD ID="3" xsi:type="CharTerm" TERMINATOR="," MAX_LENGTH="1" />
where the terminator char is "," and not "\r\n", if the data is in a single line.
Example OPENROWSET:
INSERT INTO [your_table]
SELECT [text_file].[Col1],
[text_file].[Col2],
[text_file].[Col3]
FROM OPENROWSET(
BULK N'c:\somedir\somefile.txt',
FORMATFILE = N'c:\somedir\format.xml',
FIRSTROW = 1) AS [text_file]
Example BULK INSERT:
BULK INSERT [your_table]
FROM N'c:\somedir\somefile.txt'
WITH (FORMATFILE = N'c:\somedir\format.xml')
Don't import it as OPENROWSET..BULK
You can use BULK INSERT to import it as columns or OPENROWSET by itself