merging two xml structure for each unique id - sql-server

Below is the XML file structure and the code that I used to generate it. I have 300 uniq_id rows in table_1. As shown below I only generated for one record i.e uniq_id = 7725. But I would like to generate 300 xml files for these id's. I'm little stumble how to generate them and update these xml files in table_2 which has foreign key uniq_id field. Thanks for your response.
----------- XML file template -----------
<Value>
<Gov_1>
<data>
<id>radio_option</id>
<value>7725</value>
<tag />
<visible>true</visible>
</data>
</Gov_1>
<Gov_2>
<data>
<id>radioType</id>
<value>7725</value>
<tag />
<visible>true</visible>
</data>
</Gov_2>
</Value>
------------------------------------------
Code that I wrote to generate it.
;WITH radio_option AS
(
Select 'radio_option' as id,
d.uniq_id as value,
'' as tag,
'true' as visible,
FROM table_1 d
where d.uniq_id = 7725
) ,
radioType AS (
Select 'radioType' as id,
d.uniq_id as value,
'' as tag,
'true' as visible,
d.uniq_id
FROM table_1 d
where d.uniq_id = 7725
)
select
(
select t1.id, t1.value, t1.tag, t1.visible
from radio_option t1
FOR XML PATH('data'),ROOT('Gov_1'), TYPE ),
(
select t2.id, t2.value, t2.tag, t2.visible
from radioType t2
FOR XML PATH('data'),ROOT('Gov_2'), TYPE
)
FOR XML PATH('Value')
----------
Table 1 (
uniq_id int, (pk)
add_name varchar(150),
contact_name varchar(150),
location varchar(150),
company name varchar(150),
date_t datetime
)
Table 2
(
table_2_rid int,
uniq_id int (fK),
perm_id int,
add_id int,
Xml_file xml,
date_t, datetime
)
Table 1
uniq_id add_name contact_name location company_name date_t
7725 abcd Victor CA XYZ 8/7/2016
7726 dfre Angelic FL FHT 8/7/2016
Table 2
table_2_rid uniq_id perm_id add_id Xml_file date_t
1 7725 3847 2345 xml_file_7725 8/7/2016
2 7726 4578 5432 xml_file_7726 8/7/2016

Related

Split XML field into multiple delimited values - SQL

I have some XML content in a single field; I want to split each xml field in multiple rows.
The XML is something like that:
<env>
<id>id1<\id>
<DailyProperties>
<date>01/01/2022<\date>
<value>1<\value>
<\DailyProperties>
<DailyProperties>
<date>05/05/2022<\date>
<value>2<\value>
<\DailyProperties>
<\env>
I want to put everything in a table as:
ID DATE VALUE
id1 01/01/2022 1
id1 05/05/2022 2
For now I managed to parse the xml value, and I have found something online to get a string into multiple rows (like this), but my string should have some kind of delimiter. I did this:
SELECT
ID,
XMLDATA.X.query('/env/DailyProperties/date').value('.', 'varchar(100)') as r_date,
XMLDATA.X.query('/env/DailyProperties/value').value('.', 'varchar(100)') as r_value
from tableX
outer apply xmlData.nodes('.') as XMLDATA(X)
WHERE ID = 'id1'
but I get all values without a delimiter, as such:
01/10/202202/10/202203/10/202204/10/202205/10/202206/10/202207/10/202208/10/202209/10/202210/10/2022
Or, as in my example:
ID R_DATE R_VALUE
id01 01/01/202205/05/2022 12
I have found out that XQuery has a last() function that return the last value parsed; in my xml example it will return only 05/05/2022, so it should exists something for address the adding of a delimiter. The number of rows could vary, as it could vary the number of days of which I have a value.
Please try the following solution.
I had to fix your XML to make it well-formed.
SQL
DECLARE #tbl TABLE (id INT IDENTITY PRIMARY KEY, xmldata XML);
INSERT INTO #tbl (xmldata) VALUES
(N'<env>
<id>id1</id>
<DailyProperties>
<date>01/01/2022</date>
<value>1</value>
</DailyProperties>
<DailyProperties>
<date>05/05/2022</date>
<value>2</value>
</DailyProperties>
</env>');
SELECT p.value('(id/text())[1]','VARCHAR(20)') AS id
, c.value('(date/text())[1]','VARCHAR(10)') AS [date]
, c.value('(value/text())[1]','INT') AS [value]
FROM #tbl
CROSS APPLY xmldata.nodes('/env') AS t1(p)
OUTER APPLY t1.p.nodes('DailyProperties') AS t2(c);
Output
id
date
value
id1
01/01/2022
1
id1
05/05/2022
2
Yitzhak beat me to it by 2 min. Nonetheless, here's what I have:
--==== XML Data:
DECLARE #xml XML =
'<env>
<id>id1</id>
<DailyProperties>
<date>01/01/2022</date>
<value>1</value>
</DailyProperties>
<DailyProperties>
<date>05/05/2022</date>
<value>2</value>
</DailyProperties>
</env>';
--==== Solution:
SELECT
ID = ff2.xx.value('(text())[1]','varchar(20)'),
[Date] = ff.xx.value('(date/text())[1]', 'date'),
[Value] = ff.xx.value('(value/text())[1]', 'int')
FROM (VALUES(#xml)) AS f(X)
CROSS APPLY f.X.nodes('env/DailyProperties') AS ff(xx)
CROSS APPLY f.X.nodes('env/id') AS ff2(xx);
Returns:
ID Date Value
-------------------- ---------- -----------
id1 2022-01-01 1
id1 2022-05-05 2

oracle database, insert data

I'm using Oracle 11g table:
create or replace type address as object (
street varchar2(20),
city varchar2(10),
p_code varchar2(8)
) not final;
/
create or replace type name as object (
title varchar2(5),
firstName varchar2(8),
surname varchar2(8)
) not final;
/
create or replace type phone as object
(
homePhone int,
mobile1 int,
mobile2 int
) not final;
/
create or replace type person as object (
pname name,
pAddress address,
Pphone phone
) not final;
/
create or replace type employee under person (
empId varchar2(5),
position varchar2(16),
salary int,
joinDate date,
supervisor ref employee);
/
create table tb_employee of employee
(
primary key(empID)
)
/
data I insert
insert into tb_employee values
(
person(name('mr','jone','smith'),address('street','city','post
code'),phone('11111111111','22222222222','33333333333')),
position('head'),
salary(1111),
joinDate(12-Feb-1994),
empID('001')
)
insert into tb_employee values
(
person(name('mr','jane','smith'),address('street','city','post
code'),phone('11111111111','22222222222','33333333333')),
position('accountant'),
salary(2222,
joinDate(13-Feb-1995),
empID('002')
)
insert into tb_employee values
(
person(name('miss','ross','smith'),address('street','city','post
code'),phone('11111111111','22222222222','33333333333')),
position(manager),
salary(333),
joinDate(14-Feb-1996),
empID('003')
)
I would like to insert supervisor to data by using reference function,
for example:
for head (jone smith) is a supervisor or a manager (miss ross smith),
manager(miss ross smith) is a supervisor of account(Mr jane smith),
thanks!
You are inserting records of employee type: that applies to the whole record so you need to write a VALUES clause which matches the projection of that type.
To populate the REF clause you need to select the reference of the pertinent object. Your first record doesn't have a supervisor, so we pass NULL in this case:
insert into tb_employee values
( employee(
name('mr','jone','smith')
, address('street','city','postcode')
, phone('11111111111','22222222222','33333333333')
, '001' -- emp id
, 'head' -- position
, 11111 -- salary
, to_date('12-Feb-1994','dd-mon-yyyy') -- joinDate
, null-- supervisor
))
/
For the other records we use the INSERT ... SELECT ... FROM syntax:
insert into tb_employee
select
employee(
name('mr','jane','smith')
, address('street','city','postcode')
, phone('11111111111','22222222222','33333333333')
, '002' -- emp id
, 'accountant' -- position
, 2222 -- salary
, to_date('13-Feb-1995','dd-mon-yyyy') -- joinDate
, ref (m) -- supervisor
)
from tb_employee m
where m.empid = '001'
/
insert into tb_employee
select
employee(
name('miss','ross','smith')
, address('street','city','postcode')
, phone('11111111111','22222222222','33333333333')
, '003' -- emp id
, 'manager' -- position
, 333 -- salary
, to_date('14-Feb-1996','dd-mon-yyyy') -- joinDate
, ref (m) -- supervisor
)
from tb_employee m
where m.empid = '002'
/
Here is a Oracle LiveSQL demo (free OTN account required). (It's a shame that Oracle's developer Cloud can't handle user-defined types nicely.)

how to add a xml node to xml DataColumn and return Xml Datacolumn as string in SQL

I have a table like below. ID column should be added into XML tag as Value with respective ID Column value and return as one XML tag
Ex:
Specification | ID
<car><Name>BMW</Name></car> | 245
<car><Name>Audi</Name></car> | 290
<car><Name>Skoda</Name></car>| 295
Output Should be as
| Specification |
| <car><Name>BMW</Name><ID>245</ID></car><car><Name>Audi</Name><ID>290</ID></car><car><Name>Audi</Name><ID>295</ID></car> |
You could use modify() and insert xml like this
DECLARE #SampleData AS TABLE
(
Specification xml,
Id int
)
INSERT INTO #SampleData
VALUES
('<car><Name>BMW</Name></car>', 245),
('<car><Name>Audi</Name></car>', 290),
('<car><Name>Skoda</Name></car>', 295)
Update #SampleData SET Specification.modify('insert <Id>{sql:column("sd.Id")}</Id> into (/car)[1]')
FROM #SampleData sd
SELECT sd.* FROM #SampleData sd
Demo link: Rextester
Some reference links:
modify xml
insert xml
this is one way I can think of. You can strip the value of the car name using the .node, and reconstruct the XML. Something like,
CREATE TABLE #Temp
(
Specification XML,
ID INT
)
INSERT #Temp ( Specification, ID )
VALUES
('<car><Name>BMW</Name></car>', 245),
('<car><Name>Audi</Name></car>', 290),
('<car><Name>Skoda</Name></car>', 295)
SELECT * FROM
(
SELECT
Val.value('(text())[1]', 'varchar(32)') AS Name,
T.ID
FROM #Temp AS T
CROSS APPLY Specification.nodes('car/Name') AS Id(Val)
) X
FOR XML PATH('Name'), ROOT ('Car')
DROP TABLE #Temp

Skip NULL parameters in XML generated from SQL

What i'm trying to do?: generate XML from SQL Server 2014
Problem: some columns contain NULL - these columns act like attributes in my XML. My Validator does not accept an attribute if its value its empty/null.
Example:
number Type Trat Frecv
----------- ----------- ---------- -----------
31301879 NULL 1 2
73229903 2 NULL 2
73229903 2 1 2
Desired result
<polita number="31301879" Trat="1" Frecv="2"></polita>
<polita number="73229903" Type="2" Frecv="2"></polita>
<polita number="73229903" Type="2" Trat="1" Frecv="2"></polita>
!!! Disclaimer: i've read here the method of a variable table, but unfortunately it does not work for me because my columns need to be ATTRIBUTES and i get the duplicate attribute key
It looked like this
declare #t table
(
col1,
col2
)
SELECT
col1,
'' as col1,
col2,
'' as col2
FROM #t
This is my code
WITH Inreg
AS ( SELECT DISTINCT
*
FROM dbo.C1_UE C1
INNER JOIN dbo.C2_UE C2 ON C1.nrp = C2.ContractNumber
ORDER BY C1.nrp
OFFSET #Page * #PageSize ROWS FETCH NEXT #PageSize
ROWS ONLY
),
TotalP
AS ( SELECT COUNT(ContractNumber) AS Nr_pers
FROM dbo.C2_UE
),
TotalS
AS ( SELECT REPLACE(ROUND(SUM(C1.Val_capital)
+ SUM(C3.Suma3), 0), '.00', '') AS total
FROM dbo.C1_UE C1
LEFT JOIN dbo.C3_UE C3 ON C1.nrp = C3.ContractNumber
)
SELECT REPLACE(( SELECT '' as 1
( SELECT TotalP.Nr_pers
FROM TotalP
) AS '#nr_pers' ,
( SELECT TotalS.total
FROM TotalS
) AS '#total' ,
( SELECT *
--pers
( SELECT
*
FROM #C2 C
INNER JOIN #C1 CC ON CC.nrp = C.ContractNumber
WHERE CC.nrp = C1.nrp
FOR
XML PATH('pers') ,
TYPE
) ,
--acc
( SELECT *
FROM #C3 c
INNER JOIN #C1 CC ON CC.nrp = c.ContractNumber
WHERE CC.nrp = C1.nrp
FOR
XML PATH('even') ,
TYPE
)
FROM #C1 C1
FOR
XML PATH('poli') ,
TYPE
)
FOR
XML PATH('decl400')
), '<decl400',
'<decl400 xmlns="mfp:aa:dd:d403:dec:v1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="mfp:mfp:aa:dd:d403:dec:v1 file:/C:/Users/a/Desktop/dec.xsd" ');
#C1, #C2 and #C3 are tables that are declared above, also #pageSize and #pageNumber are fixed values.
What you need - if I got this right - is the standard behaviour:
DECLARE #Dummy TABLE(number INT,Type INT,Trat INT,Frecv INT);
INSERT INTO #Dummy VALUES
(31301879,NULL,1,2)
,(73229903,2,NULL,2)
,(73229903,2,1,2);
SELECT number AS [#number]
,Type AS [#Type]
,Trat AS [#Trat]
,Frecv AS [#Frecv]
FROM #Dummy
FOR XML PATH('polita')
--The result
<polita number="31301879" Trat="1" Frecv="2" />
<polita number="73229903" Type="2" Frecv="2" />
<polita number="73229903" Type="2" Trat="1" Frecv="2" />
If you need NULLs instead of empty strings you can use NULLIF().
This answer might help you to understand how XML deals with empty vs. NULL
Shnugo's was my first answer (+1), but another alternative if you don't want to specify all the fields is to use XML RAW. For example
Declare #YourTable table (number int,[Type] int,Trat int,Frecv int)
Insert Into #YourTable values
(31301879, NULL,1 , 2)
,(73229903, 2 ,NULL, 2)
,(73229903, 2 ,1 , 2)
Select * from #YourTable for XML RAW('polita')
Returns
<polita number="31301879" Trat="1" Frecv="2" />
<polita number="73229903" Type="2" Frecv="2" />
<polita number="73229903" Type="2" Trat="1" Frecv="2" />
EDIT - Thanks Shnugo for the RAW('polita')

XML Query Attach appropriate ID

I seem struggle with XML. I am looking to get appropriate ID attached to each row
Declare #User table (id int,First_Name varchar(50),Last_Name varchar(50),EMail varchar(50))
Insert into #User values
(1,'John','Smith','john.smith#gmail.com'),
(2,'Jane','Doe' ,'jane.doe#gmail.com')
Declare #XML xml
Set #XML = (Select * from #User for XML RAW)
Select ID = 1 -- < dummy need actual id
,Item = cast(x.v.query('local-name(.)') as varchar(100))
,Value = x.v.value('.','varchar(150)')
From #xml.nodes('//#*') x(v)
My current result is.
ID Item Value
1 id 1
1 First_Name John
1 Last_Name Smith
1 EMail john.smith#gmail.com
1 id 2
1 First_Name Jane
1 Last_Name Doe
1 EMail jane.doe#gmail.com
My Desired result would be.
ID Item Value
1 id 1
1 First_Name John
1 Last_Name Smith
1 EMail john.smith#gmail.com
2 id 2
2 First_Name Jane
2 Last_Name Doe
2 EMail jane.doe#gmail.com
Try it like this:
Btw: You were pretty close!
Declare #User table (id int,First_Name varchar(50),Last_Name varchar(50),EMail varchar(50))
Insert into #User values
(1,'John','Smith','john.smith#gmail.com'),
(2,'Jane','Doe' ,'jane.doe#gmail.com')
Declare #XML xml
Set #XML = (Select * from #User for XML RAW)
SELECT #XML;
/*
<row id="1" First_Name="John" Last_Name="Smith" EMail="john.smith#gmail.com" />
<row id="2" First_Name="Jane" Last_Name="Doe" EMail="jane.doe#gmail.com" />
*/
The first .nodes() will return with all row elements in single rows
The CROSS APPLY .nodes(./#*) will do a row based search for all attributes and deliver them as single rows.
Select r.value('#id','int') AS ID
,Attr.value('local-name(.)','varchar(max)') AS Item
,Attr.value('.','varchar(max)') AS Value
FROM #XML.nodes('/row') AS A(r)
CROSS APPLY A.r.nodes('./#*') AS B(Attr)
Just came across this question. Though answer to this question was already given, thought to answer it with different approach without using xquery.
You can achieve the same result using CROSS APPLY and Table Value Constructor like this -
Declare #User table (id int,First_Name varchar(50),Last_Name varchar(50),EMail varchar(50))
Insert into #User values
(1,'John','Smith','john.smith#gmail.com'),
(2,'Jane','Doe' ,'jane.doe#gmail.com')
SELECT r.ID, t.* FROM #User r
CROSS APPLY (
VALUES ('ID', cast(id as varchar)),
('First_Name', First_Name),
('Last_Name', Last_Name),
('EMail', EMail)
) t(Item, Value)
Result
ID Item Value
---------------------
1 ID 1
1 First_Name John
1 Last_Name Smith
1 EMail john.smith#gmail.com
2 ID 2
2 First_Name Jane
2 Last_Name Doe
2 EMail jane.doe#gmail.com

Resources