I'm working on migrating some codes from MSSQL to MySQL, but I don't know the equivalent of local-name()in MySQL.
The original MSSQL code is as followed:
with cte as (select convert(xml,'<Attributes>
<Map>
<entry key="trigger" value = "action">
<value>
<Map>
<entry key=" Processing">
<value>
<Boolean>true</Boolean>
</value>
</entry>
</Map>
</value>
</entry>
</Map>
</Attributes>') as attributes)
select entr.value('#key','nvarchar(100)') AS AttrKey
,entr.value('#value','nvarchar(500)') AS AttrValue
,HasValueElement.value('local-name(.)','nvarchar(100)') AS ValueType
FROM cte a1
cross apply a1.attributes.nodes(N'/Attributes/Map/entry') A(entr)
OUTER APPLY A.entr.nodes(N'value/*') B(HasValueElement)
The output is:
AttrKey ||AttrValue ||ValueType
Trigger ||Action ||Map
How we can apply similar to local-name() in MySQL to return the ValueType = "Map"? When I tried something like "//*[local-name()]" in MySQL, it returned error.
And what is the "." in "local-name(.)" meaning?
Really appreciate your support.
TIA
Related
I have an issue with filtering xpath on specified node to have only the latest record. In the example xml there s a rule that the very first record on each node is the most current information. I would like to filter all records which are not relevant (different than the first record).
The second rule is that i do not want to use date conditions to filter all job_information records after the very first one.
Normally I am using xpath tester with expression such like:
/queryCompoundEmployeeResponse/CompoundEmployee[(person/employment_information/job_information[1])]
which gives me only the first record of job information but here is does not work. Can you show me what is wrong with it?
Can you help me?
xml input with 3 job_information records
<queryCompoundEmployeeResponse>
<CompoundEmployee>
<id>11111</id>
<person>
<employment_information>
<job_information>
<end_date>9999-12-31</end_date>
<start_date>2017-05-17</start_date>
</job_information>
<job_information>
<end_date>2018-12-31</end_date>
<start_date>2017-05-17</start_date>
</job_information>
<job_information>
<end_date>2016-12-31</end_date>
<start_date>2013-05-17</start_date>
</job_information>
</employment_information>
</person>
</CompoundEmployee>
</queryCompoundEmployeeResponse>
xml output I would like to have
<queryCompoundEmployeeResponse>
<CompoundEmployee>
<id>11111</id>
<person>
<employment_information>
<job_information>
<end_date>9999-12-31</end_date>
<start_date>2017-05-17</start_date>
</job_information>
</employment_information>
</person>
</CompoundEmployee>
</queryCompoundEmployeeResponse>
Assuming you have always the same XML structure, you can try :
data=xmlParse("C:/Users/.../pathtoyourxmlfile.xml")
a=xpathSApply(data,"count(//job_information[1]/ancestor::*)+6")
b=xpathSApply(data,"count(//job_information)-1")*4+(a-1)
old=read_lines("C:/Users/.../pathtoyourxmlfile.xml")
new = old[-(a:b)]
writeLines(new,con = "new.xml")
Output (new.xml) :
<queryCompoundEmployeeResponse>
<CompoundEmployee>
<id>11111</id>
<person>
<employment_information>
<job_information>
<end_date>9999-12-31</end_date>
<start_date>2017-05-17</start_date>
</job_information>
</employment_information>
</person>
</CompoundEmployee>
</queryCompoundEmployeeResponse>
Apparently I have a field call Data which store some xml node + json inside the those node.
I can retrieve the deliveryID by using:
JSON_VALUE(ml.Data.value('(/row/value)[2]', 'NVARCHAR(MAX)'),'$.transactions[0].deliveryId') deliveryID
However, the transactions might not always be at the second node of it,
it can be on any row.
Is there any other way I can do to iterate the node and find if it has a json transactions inside then get the deliveryID from the row?
Thanks
<row>
<value id="1ae95d67-599e-4ab6-9ffd-08d4d90ab608" display-name="Cardholder_id" data-type="Int32">17</value>
<value id="1ae95d67-599e-4ab6-9ffd-08d4d90ab608" display-name="Cardholder_id" data-type="Int32">17</value>
<value id="eb71fd46-f0b2-401d-9775-08d4d90ab608" display-name="Card_Number">3083 2614 5022 21321</value>
<value id="4fc261b2-f776-4fd4-8e1d-08d4d90ab608" display-name="Email_Address">jello#anc.com</value>
<value id="c867d4e5-cc0b-4ee6-b911-08d6134132e0" display-name="BP_TRIGGERS_2.0">{"transactions":[{"BP_CommsRef":"V0001","BP_Offer_Expiry":"2018-10-01T00:00:00","deliveryId":"20320925","Job_Number":"A34F443","Send_Date":"2018-09-26T00:00:00"}]}</value>
</row>
If I get you correctly, you want to find a JSON within your <value> elements and read the deliverId from there:
Declare #XML xml = '
<row>
<value id="1ae95d67-599e-4ab6-9ffd-08d4d90ab608" display-name="Cardholder_id" data-type="Int32">17</value>
<value id="1ae95d67-599e-4ab6-9ffd-08d4d90ab608" display-name="Cardholder_id" data-type="Int32">17</value>
<value id="eb71fd46-f0b2-401d-9775-08d4d90ab608" display-name="Card_Number">3083 2614 5022 21321</value>
<value id="4fc261b2-f776-4fd4-8e1d-08d4d90ab608" display-name="Email_Address">jello#anc.com</value>
<value id="c867d4e5-cc0b-4ee6-b911-08d6134132e0" display-name="BP_TRIGGERS_2.0">{"transactions":[{"BP_CommsRef":"V0001","BP_Offer_Expiry":"2018-10-01T00:00:00","deliveryId":"20320925","Job_Number":"A34F443","Send_Date":"2018-09-26T00:00:00"}]}</value>
</row>';
--This will check for an opening { (you could search for an opening {"transactions" as well)
SELECT JSON_VALUE(
#XML.query(N'/row/value[substring(text()[1],1,1)="{"]/node()')
.value(N'text()[1]','nvarchar(max)')
,N'$.transactions[0].deliveryId');
--The same approach but looking at the attribute display-name
SELECT JSON_VALUE(
#XML.query(N'/row/value[#display-name="BP_TRIGGERS_2.0"]/node()')
.value(N'text()[1]','nvarchar(max)')
,N'$.transactions[0].deliveryId');
The idea in short: .query() the XML for a <value> below <row>, which fullfills the filter. Take this node() and read the .value() from there.
This is handed into JSON_VALUE in order to retrieve the needed deliveryId.
You can do the same with the attribute id and you can hand in the values with a declard variable (sql:variable()) or from a column in your result-set (sql:column()).
I have following xml in my table. I want to get ID of a fv node:
<fv ID="Description"> or not
<DataFormItem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="bb_appfx_dataforms">
<Values>
<fv ID="JobInterval">
<Value xsi:type="xsd:int">10</Value>
</fv>
<fv ID="JobEnabled">
<Value xsi:type="xsd:boolean">false</Value>
</fv>
<fv ID="JobName">
<Value xsi:type="xsd:string">Default transactional email process</Value>
</fv>
<fv ID="ScheduleFrequencySubDayType">
<Value xsi:type="xsd:int">2</Value>
</fv>
</Values>
</DataFormItem>
Assuming your table is called YourTable and the XML column is called XmlData (adapt and change this to meet your actual situation!), you can try this XQuery code:
-- declare the XML namespace as the DEFAULT
;WITH XMLNAMESPACES(DEFAULT 'bb_appfx_dataforms')
SELECT
-- extract the value from the <Value> subnode of the <fv> node, if found
FvValue = XC.value('(Value)[1]', 'varchar(200)')
FROM
dbo.YourTable
CROSS APPLY
-- get a list of XML fragments - one for each <fv> node
XmlData.nodes('/DataFormItem/Values/fv') AS XT(XC)
WHERE
-- find the XML fragment with the ID="Description"
XC.value('#ID', 'varchar(50)') = 'Description'
Assume having the following csv:
a,b,c
1,2,3
where a,b,c are column names and 1,2,3 are values.
Is it possible to load only columns a,b?
<loadUpdateData tableName="TABLE"
file="file.csv"
primaryKey="a">
<column name="a" header="a"/>
<column name="b" header="b"/>
</loadUpdateData>
This will generate an SQL error, because it will try to insert column c.
I am using MySQL.
Haven't tried it myself but looking at the code (for LoadDataChange) there seems to be an option to "skip" a column config:
if ("skip".equalsIgnoreCase(columnConfig.getType())) {
continue;
}
So maybe you can add a column config for 'c' and set its type to "skip":
<column name="c" header="c" type="skip" />
I need further assistance with extracting records from XML and loading it into a SQL Server table.
I have this as my #xml:
<admin submitter_id="login0" effective_date="mm/dd/yyyy">
<rec effected_id="login1" adjustment="100.00" type="foo">
<reason reason_id="1" />
<reason reason_id="2" />
</rec>
<rec effected_id="login2" adjustment="50.00" type="bar">
<reason reason_id="3" />
</rec>
</admin>
I need this from a result set:
login0, login1, mm/dd/yyyy, 100.00, foo, 1
login0, login1, mm/dd/yyyy, 100.00, foo, 2
login0, login2, mm/dd/yyyy, 50.00, bar, 3
Does that make sense? The adjustment to the reason_id is one to many. I have figured out how to extract all the values except for the second line. I can only obtain the first reason_id and then it proceeds to the next record. I think this can be beaten with a CROSS APPLY but I cannot get it to work. Please help!
oh, I may also have received bogus XML. So if that's wrong, please tell me!
How about something like
DECLARE #Xml XML
SELECT #Xml = '<admin submitter_id="login0" effective_date="mm/dd/yyyy">
<rec effected_id="login1" adjustment="100.00" type="foo">
<reason reason_id="1" />
<reason reason_id="2" />
</rec>
<rec effected_id="login2" adjustment="50.00" type="bar">
<reason reason_id="3" />
</rec>
</admin>'
SELECT #Xml,
A2.B.value('(../../#submitter_id)[1]','VARCHAR(50)'),
A2.B.value('(../#effected_id)[1]','VARCHAR(50)'),
A2.B.value('(../../#effective_date)[1]','VARCHAR(50)'),
A2.B.value('(../#adjustment)[1]','FLOAT'),
A2.B.value('(../#type)[1]','VARCHAR(50)'),
A2.B.value('(#reason_id)[1]','INT')
FROM #XML.nodes('//admin/rec/reason') A2(B)
SQL Fiddle DEMO
Try to use this T-SQL code snippet:
SELECT
Submitter = #xml.value('(/admin/#submitter_id)[1]', 'varchar(50)'),
EffectedID = Rec.value('(#effected_id)[1]', 'varchar(50)'),
DateStamp = #xml.value('(/admin/#effective_date)[1]', 'varchar(50)'),
TypeID = Rec.value('(#type)[1]', 'varchar(50)'),
ReasonID = Reason.value('(#reason_id)[1]', 'int')
FROM
#xml.nodes('/admin/rec') AS Tbl(Rec)
CROSS APPLY
Rec.nodes('reason') AS T2(Reason)
It gives me an output of:
You need to have two nested lists of nodes - the first one grabs all the <rec> nodes from inside <admin>, while the second one iterates over all the <reason> nodes inside each of the <rec> nodes. That way, you can reliably extract all information from those two nested levels of subnodes, no matter how many subnodes there are on each level.