I have the following xml data in a xml column (not typed) called xml_response
<SEIContent>
<Request>
<eq:Charge>
<v:Type>MaintCharge</v:Type>
<v:Term>0</v:Term>
<v:StartMonth>0</v:StartMonth>
<v:EndMonth>0</v:EndMonth>
<v:Rate>0</v:Rate>
<v:RebateRatio>0</v:RebateRatio>
<v:MaxRebate>0</v:MaxRebate>
<v:TieredCharge>
<v:Term>0</v:Term>
<v:Rate>0.75</v:Rate>
<v:LowerBand>0</v:LowerBand>
<v:UpperBand>249999.99</v:UpperBand>
<v:BandCurrency>GBP</v:BandCurrency>
</v:TieredCharge>
<v:TieredCharge>
<v:Term>0</v:Term>
<v:Rate>0.7</v:Rate>
<v:LowerBand>250000</v:LowerBand>
<v:UpperBand>499999.99</v:UpperBand>
<v:BandCurrency>GBP</v:BandCurrency>
</v:TieredCharge>
<v:TieredCharge>
<v:Term>0</v:Term>
<v:Rate>0.6</v:Rate>
<v:LowerBand>500000</v:LowerBand>
<v:UpperBand>999999.99</v:UpperBand>
<v:BandCurrency>GBP</v:BandCurrency>
</v:TieredCharge>
<v:TieredCharge>
<v:Term>0</v:Term>
<v:Rate>0.5</v:Rate>
<v:LowerBand>1000000</v:LowerBand>
<v:UpperBand>9999999.99</v:UpperBand>
<v:BandCurrency>GBP</v:BandCurrency>
</v:TieredCharge>
</eq:Charge>
<eq:Charge>
<v:Type>MaintCharge</v:Type>
<v:Term>0</v:Term>
<v:StartMonth>0</v:StartMonth>
<v:EndMonth>59</v:EndMonth>
<v:Rate>1.5</v:Rate>
<v:RebateRatio>0</v:RebateRatio>
<v:MaxRebate>0</v:MaxRebate>
</eq:Charge>
<eq:Charge>
<v:Type>MaintCharge</v:Type>
<v:Term>0</v:Term>
<v:StartMonth>60</v:StartMonth>
<v:EndMonth>0</v:EndMonth>
<v:Rate>0.5</v:Rate>
<v:RebateRatio>0</v:RebateRatio>
<v:MaxRebate>0</v:MaxRebate>
</eq:Charge>
<eq:Charge>
<v:Type>QAC</v:Type>
<v:Basis>FixedAmount</v:Basis>
<v:Term>0</v:Term>
<v:StartMonth>0</v:StartMonth>
<v:EndMonth>0</v:EndMonth>
<v:Rate>105</v:Rate>
<v:RebateRatio>0</v:RebateRatio>
<v:MaxRebate>0</v:MaxRebate>
</eq:Charge>
</Request>
<Response>
<eq:Ref>QV00000393</eq:Ref>
</Response>
</SEIContent>
So you'll notice that some charges contain a repeating element TieredCharge and some don't
I've written the following query:
WITH XMLNAMESPACES('http://lu/blah' AS eq, 'http://lu/blah2' AS v,
DEFAULT 'http://lu/blah3'
SELECT
nref.value('Response[1]/eqRef[1]', 'nvarchar(200)') Ref,
ncharge.value('v:Type[1]', 'nvarchar(50)') ChargeType,
ncharge.value('v:Basis[1]', 'nvarchar(50)') ChargeBasis,
ncharge.value('v:Term[1]', 'int') Term,
ncharge.value('v:StartMonth[1]', 'int') StartMonth,
ncharge.value('v:EndMonth[1]', 'int') EndMonth,
ncharge.value('v:Rate[1]', 'money') Rate,
ncharge.value('v:RebateRatio[1]', 'money') RebateRatio,
ncharge.value('v:MaxRebate[1]', 'money') MaxRebate,
tcharge.value('v:Term[1]', 'int') TieredTerm,
tcharge.value('v:Rate[1]', 'money') TieredRate,
tcharge.value('v:LowerBand[1]', 'money') TieredLowerBand,
tcharge.value('v:UpperBand[1]', 'money') TieredUpperBand
INTO #TempCharges
FROM xml_response CROSS APPLY response_body.nodes('//SEIContent') AS Quote(nref)
CROSS APPLY response_body.nodes('//Request//eq:Charge') AS Charge(ncharge)
CROSS APPLY response_body.nodes('//Request//eq:Charge//v:TieredCharge') AS TieredCharge(tcharge)
WHERE nref.value('Request[1]/eq:Product[1]', 'nvarchar(60)') <> 'AVL'
select * from #TempCharges
So although this flattens the xml, what I'm getting is repeated rows even if the eq:Charge element doesn't contain a v:TieredCharge repeating element?
For example I get 4 rows where the charge type is QAC even though there is only one element with that type?
How do I query this so that I only get one row for each Charge element, unless there are repeating child elements below it, in which case I'll only get the rows repeated for each element?
So I should get something like this:
MaintChange TieredCharge1 row
MaintChange TieredCharge2 row
MaintChange TieredCharge3 row
MaintChange TieredCharge4 row
MaintCharge
MaintCharge
QAC
So the trick is to use OUTER APPLY in the last bit of the query - its kind of like an inner join. Then it works.
Related
I have XML data that comes in from a third party (so I cannot change the XML format) and gets stored in a table.
An example XML message format
<MedicalAidMessage xmlns="test.co.za/messaging" version="6.0">
<BenefitCheckResponseMessage>
<FinancialResponseDetails>
<FinancialResponseLines>
<FinancialResponseLine>
<LineIdentifier>1</LineIdentifier>
<RequestedAmount>1000</RequestedAmount>
<AmountToProvider>800</AmountToProvider>
<AmountToMember>0</AmountToMember>
<MemberLiableAmount>200</MemberLiableAmount>
<MemberNotLiableAmount>0</MemberNotLiableAmount>
<TariffCode>12345</TariffCode>
<LineResponseCodes>
<LineResponseCode>
<Sequence>1</Sequence>
<Code>274</Code>
<Description>We have not paid the amount claimed because the funds in the Medical Savings are used up.</Description>
<Type>Info</Type>
</LineResponseCode>
<LineResponseCode>
<Sequence>2</Sequence>
<Code>1239</Code>
<Description>We have applied a co-payment on this claim, in line with the member’s plan benefit for MRI and CT scans.</Description>
<Type>Info</Type>
</LineResponseCode>
</LineResponseCodes>
</FinancialResponseLine>
</FinancialResponseLines>
</FinancialResponseDetails>
</BenefitCheckResponseMessage>
</MedicalAidMessage>
I have tried the following code to get the Tariffcode, RequestedAmount, AmountToProvider and AmountToMember
DECLARE #XMLData XML = (select top 1 replace(br.xmlmessage,'<?xml version="1.0" encoding="UTF-8"?>','')
from benefitcheckresponse br
inner join benefitcheck bc on bc.id = br.BenefitCheckId
where bc.id =1562
order by bc.id desc)
SELECT
[TariffCode] = Node.Data.value('TariffCode', 'vacrhar(50)'),
[RequestedAmount] = Node.Data.value('RequestedAmount', 'float)'),
[AmountToProvider] = Node.Data.value('AmountToProvider', 'float)'),
[AmountToMember] = Node.Data.value('AmountToMember', 'float)')
FROM #XMLData.nodes('/*/FinancialResponseLine/') Node(Data)
The problem I am getting is that it is giving me the following error message
Msg 9341, Level 16, State 1, Line 12 XQuery [nodes()]: Syntax error
near '', expected a step expression.
How do I resolve that error?
How would I include the results for multiple lines when there multiple line responses?
How would I include the values from the sub nodes to the line response nodes?
You would be better off with syntax like this, if I am honest. I wasn't able to complete the ORDER BY clause for you, as I don't know what column to order by, but as you have a TOP (1) you need one. You also need to define your XML namespace, which you have not, which would have resulted in no rows being returned:
WITH XMLNAMESPACES(DEFAULT 'test.co.za/messaging')
SELECT TOP (1)
FRL.FRL.value('(TariffCode/text())[1]','int') AS TariffCode,
FRL.FRL.value('(RequestedAmount/text())[1]','int') AS RequestedAmount, --I doubt float is the correct data type here
FRL.FRL.value('(AmountToProvider/text())[1]','int') AS AmountToProvider, --I doubt float is the correct data type here
FRL.FRL.value('(AmountToMember/text())[1]','int') AS AmountToMember --I doubt float is the correct data type here
FROM dbo.benefitcheckresponse br
INNER JOIN benefitcheck bc ON bc.id = br.BenefitCheckId
CROSS APPLY br.xmlmessage.nodes('MedicalAidMessage/BenefitCheckResponseMessage/FinancialResponseDetails/FinancialResponseLines/FinancialResponseLine') FRL(FRL)
WHERE bc.id = 1562
ORDER BY {Column Name(s)};
I have the following XML:
<Envelope format="ProceedoOrderTransaction2.1">
<Sender>SENDER</Sender>
<Receiver>RECEIVER</Receiver>
<EnvelopeID>xxxxx</EnvelopeID>
<Date>2021-05-06</Date>
<Time>11:59:46</Time>
<NumberOfOrder>1</NumberOfOrder>
<Order>
<Header>
<OrderNumber>POXXXXX</OrderNumber>
</Header>
<Lines>
<Line>
<LineNumber>1</LineNumber>
<ItemName>Ipsum Lorum</ItemName>
<SupplierArticleNumber>999999</SupplierArticleNumber>
<UnitPrice vatRate="25.0">50</UnitPrice>
<UnitPriceBasis>1</UnitPriceBasis>
<OrderedQuantity unit="Styck">200</OrderedQuantity>
<AdditionalItemProperty Key="ARTIKELNUMMER" Description="Unik ordermärkning (artikelnummer):" />
<Value>999999</Value>
<AdditionalItemProperty Key="BESKRIVNING" Description="Kort beskrivning:" />
<Value>Ipsum Lorum</Value>
<AdditionalItemProperty Key="BSKRIVNING" Description="Beskrivning:" />
<Value>Ipsum Lorum</Value>
<AdditionalItemProperty Key="ENHET" Description="Enhet:" />
<Value>Styck</Value>
<AdditionalItemProperty Key="KVANTITET" Description="Kvantitet:" />
<Value>200</Value>
<AdditionalItemProperty Key="PRIS" Description="Pris/Enhet (ex. moms):" />
<Value>50</Value>
<AdditionalItemProperty Key="VALUTA" Description="Valuta:" />
<Value>SEK</Value>
<Accounting>
<AccountingLine amount="10000">
<AccountingValue dimensionPosition="001" dimensionExternalID="ACCOUNT">xxx</AccountingValue>
<AccountingValue dimensionPosition="002" dimensionExternalID="F1">Ipsum Lorum</AccountingValue>
<AccountingValue dimensionPosition="005" dimensionExternalID="F3">1</AccountingValue>
<AccountingValue dimensionPosition="010" dimensionExternalID="F2">9999</AccountingValue>
</AccountingLine>
</Accounting>
</Line>
</Lines>
</Order>
</Envelope>
I am able to parse out all values correctly to table structure except for 1 value in a way that ensures its it associated with its tag. So where I stumble is that I am correctly getting 1 row per AdditionalItemProperty and I am able to get the Key and Description tag values, for example BESKRIVNING and Kort beskrivning:, but I can't (in a reasonable way) get the value between <Value> </Value> brackets that is also associated with each tag value. So for tag key value BESKRIVNING the associated value is 99999 which seem to be on same hierarchy level (insane I know) as the AdditionalItemProperty it is associated with. Seems like they use logic that value for a AdditionalItemProperty will be following the AdditionalItemProperty tag.
I am using SQL Server 2019. I have gotten this far:
-- Purchaseorderrowattributes
select top(10)
i.value(N'(./Header/OrderNumber/text())[1]', 'nvarchar(30)') as OrderNumber,
ap.value(N'(../LineNumber/text())[1]', 'nvarchar(30)') as LineNumber,
ap.value(N'(#Description)', 'nvarchar(50)') property_description
from
load.proceedo_orders t
outer apply
t.xml_data.nodes('Envelope/Order') AS i(i)
outer apply
i.nodes('Lines/Line/AdditionalItemProperty') as ap(ap)
where
file_name = #filename
Which produces the following output:
OrderNumber LineNumber property_description
--------------------------------------------
PO170006416 1 Antal timmar
PO170006416 1 Beskrivning
PO170006416 1 Kompetensområde
PO170006416 1 Roll
PO170006416 1 Ordernummer
PO170006416 1 Timpris
I can't find a way to add the value for each property in a correct way. Since the ordering of the values will always be same as the ordering of the AdditionalItemProperty i found solution to get ordering of the AdditionalItemProperty and then i could use rownumber and i was then hoping to input the rownumber value into the bracket in
ap.value(N'(../Value/text())[1]', 'nvarchar(50)') property_description
but SQL Server throws exception that it has to be string literal.
So to be clear what I tried doing with something like:
ap.value(CONCAT( N'(../Value/text())[', CAST(ROWNUMBER as varchar) ,']'), 'nvarchar(50)') property_description
SQL Server uses XQuery 1.0.
You can make use of the >> Node Comparison operator to find the Value sibling node with code similar to the following:
-- Purchaseorderrowattributes
select top(10)
i.value(N'(./Header/OrderNumber/text())[1]', 'nvarchar(30)') as OrderNumber
,ap.value(N'(../LineNumber/text())[1]', 'nvarchar(30)') as LineNumber
,ap.value(N'(#Description)', 'nvarchar(50)') property_description
,ap.query('
let $property := .
return (../Value[. >> $property][1])/text()
').value('.[1]', 'varchar(20)') as property_value
from load.proceedo_orders t
outer apply t.xml_data.nodes('Envelope/Order') AS i(i)
outer apply i.nodes('Lines/Line/AdditionalItemProperty') as ap(ap)
where file_name = #filename
So what's going on here?
let $property := . is creating a reference to the current AdditionalItemProperty node.
../Value[. >> $property] is ascending to the parent node, Line, and descending again to find Value nodes after the AditionalItemProperty node reference in document order, with [1] selecting the first one of those nodes.
See the 3.5.3 Node Comparisons section for a little more detail.
I am trying to add attributes and xmlns using WITH XMLNAMESPACES under same root, but could not make it work. Please help.
The following SQL query throws an error
Msg 6852, Level 16, State 1, Line 17
Attribute-centric column '#encounter_number' must not come after a non-attribute-centric sibling in XML hierarchy in FOR XML PATH.
for this line
'HMSXML' AS "pbrc/#source" , URNumber AS "pbrc/#messageHash", 'xmlResult01' AS "pbrc/#integration_info"
Full code:
DECLARE #xml XML;
WITH XMLNAMESPACES (
'http://www.w3.org/2001/XMLSchema-instance' as xsi
,'http://java.sun.com/xml/ns/jaxb/xjc' as xjc
,'http://www.powerhealthsolutions.com/pbrc/jaxb/ext' as [pbrc-jaxb]
,'http://java.sun.com/xml/ns/jaxb' AS jaxb
,DEFAULT 'http://www.powerhealthsolutions.com/pbrc')
SELECT
#xml = (SELECT
'HMSXML' AS "pbrc/#source",
URNumber AS "pbrc/#messageHash",
'xmlResult01' AS "pbrc/#integration_info",
AdmissionID AS "#encounter_number",
'NDIS' AS organisation_code,
'NDIS' AS encounter_type,
(SELECT
'true' AS "#delete",
(SELECT 'NDIS' AS class_type, AdmissionDate AS start_date_time
FOR XML PATH ('financial_class'), TYPE)
FOR XML PATH('financial_classes'), TYPE),
(SELECT
URNumber AS "#entity_number",
(SELECT 'NDIS ID' AS name, NDISNumber AS value
FOR XML PATH ('extra'), ROOT('extras'), TYPE)
FOR XML PATH ('recipient'), TYPE),
'H' AS referral_source,
'H' AS separation_status,
AdmissionDate AS start_date_time
FROM
Episode
FOR XML PATH('encounter'), ROOT('pbrc'), TYPE)
select #xml
I want to get output as shown here, but I'm failing to achieve those last 3 attributes integration_info="xmlResult03", messageHash="4208151" and source="HMSXML". These will come from SQL select query.
<?xml version="1.0"?>
-<pbrc xmlns="http://www.powerhealthsolutions.com/pbrc" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:pbrc-jaxb="http://www.powerhealthsolutions.com/pbrc/jaxb/ext" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" integration_info="xmlResult03" messageHash="4208151" source="HMSXML">
-<encounter encounter_number="525241">
<organisation_code>NDIS</organisation_code>
<encounter_type>NDIS</encounter_type>
-<financial_classes delete="true">
-<financial_class>
<class_type>NDIS</class_type>
<start_date_time>2018-06-26T00:00:00</start_date_time>
</financial_class>
</financial_classes>
-<payors>
-<payor>
<payor entity_number="4208151"> </payor>
<slot>Patient</slot>
<start_date>2018-06-26</start_date>
</payor>
</payors>
-<recipient entity_number="4208151">
-<extras>
-<extra>
<name>NDIS ID</name>
<value>430392519</value>
</extra>
</extras>
</recipient>
<referral_source>H</referral_source>
<separation_status>H</separation_status>
-<services>
-<service>
<source_system_code>HMSXML</source_system_code>
<organisation_code>NDIS</organisation_code>
<actual_charge>179.26</actual_charge>
<description1>Arnold Sch - Occupational Therapist</description1>
<quantity>1</quantity>
<service_code>15_048_0128_1_3</service_code>
<start_time>2019-03-27T15:00:00</start_time>
</service>
-<service>
<source_system_code>HMSXML</source_system_code>
<organisation_code>NDIS</organisation_code>
<actual_charge>193.99</actual_charge>
<description1>Arnold Sch - Occupational Therapist</description1>
<quantity>1</quantity>
<service_code>15_056_0128_1_3</service_code>
<start_time>2019-07-30T15:00:00</start_time>
</service>
</services>
<start_date_time>2018-06-26T00:00:00</start_date_time>
</encounter>
</pbrc>
I have the following xml which I want to query to turn into a flat table structure.
<RiskBoundReportProcess>
<RiskBoundReport>
<Policy key="Pol126446">
<LineOfBusinessCode>ISR</LineOfBusinessCode>
<AssignedIdentifier>
<RoleCode>Insured</RoleCode>
<Id>BP-1438</Id>
</AssignedIdentifier>
<RiskParticipationPercentIndicator>true</RiskParticipationPercentIndicator>
<PolicySection>
<PolicyProducer>
<RoleCode>Coverholder</RoleCode>
<Producer>
<OrganizationReferences organizationReference="Coverholder"/>
</Producer>
</PolicyProducer>
<PolicyProducer>
<RoleCode>Underwriter</RoleCode>
<Producer>
<Contact>
<PersonReferences>
<PersonName>
<FullName>Name</FullName>
</PersonName>
</PersonReferences>
</Contact>
</Producer>
</PolicyProducer>
<PolicyProducer>
<RoleCode>Broker</RoleCode>
<AssignedIdentifier>
<RoleCode>Broker</RoleCode>
<Id>112</Id>
</AssignedIdentifier>
<Producer>
<OrganizationReferences organizationReference="BrokerOrg112"/>
</Producer>
</PolicyProducer>
<PolicyProducer>
<RoleCode>LondonBroker</RoleCode>
<ProducerReferences producerReference="Binder1">
<ExternalIdentifier>
<TypeCode>UniqueMarketReference</TypeCode>
<Id>UMRGoesHere</Id>
</ExternalIdentifier>
<OrganizationReferences>
<OrganizationName>
<FullName>Partners Ltd</FullName>
</OrganizationName>
</OrganizationReferences>
<BindingAuthorityPeriod>
<StartDate>2014-05-01</StartDate>
<EndDate>2015-04-30</EndDate>
</BindingAuthorityPeriod>
</ProducerReferences>
<RiskParticipationPercent>1.0000</RiskParticipationPercent>
</PolicyProducer>
</PolicySection>
</Policy>
</RiskBoundReport>
</RiskBoundReportProcess>
So far I have two columns. I now want to create a column for UniqueMarketReference which is found in the following node
RiskBoundReportProcess/RiskBoundReport/Policy/PolicySection/PolicyProducer[RoleCode="LondonBroker"]/ProducerReferences/ExternalIdentifier/[TypeCode="UniqueMarketReference"]/Id
How do I modifiy the SQL below to include this?
SELECT
Policy.value('#key', 'VARCHAR(50)') AS PolicyId,
Policy.value('LineOfBusinessCode[1]', 'VARCHAR(50)') AS LineOfBusinessCode
FROM #ACORDXML.nodes('/RiskBoundReportProcess/RiskBoundReport') AS RiskBoundReport(Nodes)
CROSS APPLY RiskBoundReport.Nodes.nodes('Policy') AS Policies(Policy)
I will eventually return The Insured, Coverholer and Underwriter as columns too.
You were very close... The XPath you provided has just one / before [TypeCode ...], which is to much.
Try it like this:
SELECT
Policy.value(N'#key', N'VARCHAR(50)') AS PolicyId
,Policy.value(N'LineOfBusinessCode[1]', N'VARCHAR(50)') AS LineOfBusinessCode
,Policy.value(N'(/RiskBoundReportProcess/RiskBoundReport/Policy/PolicySection
/PolicyProducer[RoleCode="LondonBroker"]
/ProducerReferences/ExternalIdentifier[TypeCode="UniqueMarketReference"]/Id/text())[1]','VARCHAR(50)') AS LondonBroker
,Policy.value(N'(/RiskBoundReportProcess/RiskBoundReport/Policy/PolicySection
/PolicyProducer[RoleCode="Underwriter"]
/Producer/Contact/PersonReferences/PersonName/FullName/text())[1]','VARCHAR(50)') AS Underwriter
FROM #ACORDXML.nodes('/RiskBoundReportProcess/RiskBoundReport') AS RiskBoundReport(Nodes)
CROSS APPLY RiskBoundReport.Nodes.nodes('Policy') AS Policies(Policy);
Some of your nodes look like 1:n-related (<PersonReferences><PersonName>...). This might need some extra effort (.nodes())...
I create some XML in SQL Server with:
select
1 as Tag,
NULL as Parent,
a.Start as [EventItem!1!StartTime!Element],
a.[End] as [EventItem!1!EndTime!Element],
a.ResId as [EventItem!1!ResourceId!Element],
from
Activity a
for xml explicit, root('ArrayOfEventItem')
The result is:
<EventItem>
<StartTime>2012-08-16T08:00:00</StartTime>
<EndTime>2012-08-16T17:00:00</EndTime>
<ResourceId>3</ResourceId>
</EventItem>
<EventItem>
<StartTime>2013-06-06T08:00:00</StartTime>
<EndTime>2013-06-06T17:00:00</EndTime>
<ResourceId>4</ResourceId>
</EventItem>
But I also need the type information in the result - it should be:
<EventItem>
<StartTime xsi:type="xsd:dateTime">2012-08-16T08:00:00</StartTime>
<EndTime xsi:type="xsd:dateTime">2012-08-16T17:00:00</EndTime>
<ResourceId xsi:type="xsd:int">3</ResourceId>
</EventItem>
<EventItem>
<StartTime xsi:type="xsd:dateTime">2013-06-06T08:00:00</StartTime>
<EndTime xsi:type="xsd:dateTime">2013-06-06T17:00:00</EndTime>
<ResourceId xsi:type="xsd:int">4</ResourceId>
</EventItem>
How can I add this (the xsi:type="") to my select statement?
;WITH XMLNAMESPACES ('http://www.w3.org/2001/XMLSchema-instance' AS xsi )
select
1 as "Tag",
NULL as "Parent",
'xsd:dateTime' AS "StartTime/#xsi:type",
a.Start as "StartTime",
'xsd:dateTime' AS "EndTime/#xsi:type",
a.[End] as "EndTime",
'xsd:int' AS "ResourceId/#xsi:type",
a.ResId as "ResourceId"
FROM
Activity a
FOR XML PATH('EventItem'), ROOT('ArrayOfEventItem')