I am trying to parse WordPress data in our SQL Server from an Elasticsearch structure.
This is the contents of one field on one record;
<category domain="category" nicename="featured">Featured</category>
<category domain="post_tag" nicename="name1">Name 1</category>
<category domain="post_tag" nicename="name-2">Name 2</category>
<category domain="post_tag" nicename="different-name">Different Name</category>
<category domain="type" nicename="something-else">Something Else</category>
I'd like to parse this out as a table with the headers Domain, NiceName and Contents and a row for each of these nodes in the data. Something along these lines;
Domain
NiceName
Contents
category
featured
Featured
post_tag
name1
Name 1
post_tag
name-2
Name 2
post_tag
different-name
Different Name
type
something-else
Something Else
The number of nodes is different for each row in the data and can appear in any order. Currently the data is stored in a varchar data type but this can be modified if it's best to parse using something like XML.
It's recommended that you use the xml data type for storing XML data. But if you must store it in a varchar column you can use try_cast to cast it to XML (which results in null if it's not actually valid XML) and then work with it using the normal nodes(), query() and value() XML methods such as the following...
create table dbo.Records (
OneField varchar(max)
);
insert dbo.Records (OneField) values
('<category domain="category" nicename="featured">Featured</category>
<category domain="post_tag" nicename="name1">Name 1</category>
<category domain="post_tag" nicename="name-2">Name 2</category>
<category domain="post_tag" nicename="different-name">Different Name</category>
<category domain="type" nicename="something-else">Something Else</category>');
select
Category.value('#domain', 'varchar(50)') as [Domain],
Category.value('#nicename', 'varchar(50)') as [NiceName],
Category.value('(text())[1]', 'varchar(50)') as [Contents]
from dbo.Records R
cross apply (select try_cast(OneField as XML)) X(OneFieldXML)
cross apply OneFieldXML.nodes('/category') N(Category);
Domain
NiceName
Contents
category
featured
Featured
post_tag
name1
Name 1
post_tag
name-2
Name 2
post_tag
different-name
Different Name
type
something-else
Something Else
Related
I want to get the values Total and TipoDeComprobante of the tag name cfdi:Comprobante, currently in my table the column where the XML is stored is of type image so I do the following query to get the value of the XML, I tried to do some substring but I have not been successful, could you help me?
Query to obtain the xml
select cast(cast(xml as varbinary(max)) as varchar(max)) as column_name
from [tb_cfdi]
where uuid = 'f425cd6d-ed30-4a0d-8135-8dc7229b79ff' ;
Result
<?xml version="1.0" encoding="utf-8"?>
<cfdi:Comprobante xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" Version="3.3" Serie="PRUEBAS-SEBASTIAN" Folio="SEBASTIANCANCELACIONSD-27" Fecha="2022-05-23T18:42:38" Sello="dUxav04E0XcbOhMsXjXDlWbFlZdcXqOk/R8DHLd3TILZ7gg5/aw+T+gI9yMLpVLvPkeEm5+A++QWHi0I/26TVTlsx6ejFWxXTEdewmarCuSrRO24CSFPz2dLX6ojy5Eg6QGTV0EQiS3LRtLsnTyqXH2QE7Ne+Y7cqXXEcXWZ63AIAkkWY4U9uQu1/3F0jiHFfMCf4lBuSgDQ8c8LniBKoAsFoTySZmyhJv4h2koz1bE0Yl6Rvrr0NNlmYSH+SGqbkYVsYKM9fbHIDJbNXosRqIGlugOlLIT2499j3gQfTn7d3sdQLtVqn4tcqaDGx2Du2dm1XFJRwT7aB62btNVW1Q==" FormaPago="99" NoCertificado="30001000000400002325" Certificado="MIIFdjCCA16gAwIBAgIUMzAwMDEwMDAwMDA0MDAwMDIzMjUwDQYJKoZIhvcNAQELBQAwggErMQ8wDQYDVQQDDAZBQyBVQVQxLjAsBgNVBAoMJVNFUlZJQ0lPIERFIEFETUlOSVNUUkFDSU9OIFRSSUJVVEFSSUExGjAYBgNVBAsMEVNBVC1JRVMgQXV0aG9yaXR5MSgwJgYJKoZIhvcNAQkBFhlvc2Nhci5tYXJ0aW5lekBzYXQuZ29iLm14MR0wGwYDVQQJDBQzcmEgY2VycmFkYSBkZSBjYWRpejEOMAwGA1UEEQwFMDYzNzAxCzAJBgNVBAYTAk1YMRkwFwYDVQQIDBBDSVVEQUQgREUgTUVYSUNPMREwDwYDVQQHDAhDT1lPQUNBTjERMA8GA1UELRMIMi41LjQuNDUxJTAjBgkqhkiG9w0BCQITFnJlc3BvbnNhYmxlOiBBQ0RNQS1TQVQwHhcNMTkwNTI5MTgwNDM0WhcNMjMwNTI5MTgwNDM0WjCBnTEYMBYGA1UEAxMPWEFJTUUgV0VJUiBST0pPMRgwFgYDVQQpEw9YQUlNRSBXRUlSIFJPSk8xGDAWBgNVBAoTD1hBSU1FIFdFSVIgUk9KTzEWMBQGA1UELRMNV0VSWDYzMTAxNlMzMDEbMBkGA1UEBRMSV0VSWDYzMTAxNkhKQ1JKTTA4MRgwFgYDVQQLEw9YQUlNRSBXRUlSIFJPSk8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCwSjRVq5oohPioYAWcUoxVAvudA2MqKDBwX/GukHngSLtqMZ6b5I/JIhnDyqauugRYaQRW7FH+jxoijWR340zYhhgea2HYfE7WDUQNlraqtZ9re+OX5RX3KQA4sPw3pcVMcUbiCDr3vVBVaWtEaAaIsh1LxPgwWQ2egFarmMkHHEUTLkISe2WqrOFKd3PJ9vgj6h4+EF0+C3qKt55pRsLTh9r828Mo7E7AROaSJK5XG/x/5xE5sYyV2kqCFIs11xdfTn00FEmUgK+caW2lKYj9KqSuKu8UyJcOdrk2LhZlHhJO16LXrTsItJZPhJJ03FYi4+w0TNY7Eg87BC38nz5NAgMBAAGjHTAbMAwGA1UdEwEB/wQCMAAwCwYDVR0PBAQDAgbAMA0GCSqGSIb3DQEBCwUAA4ICAQCF9+3Q0bUnTVREjva/R2fNjnoksrHUwviYkRGOTfQeJbOF76gcz1aqkMpuhk9uvbnxLtNXTrpJZaW/9f7aVSIEP7x9u5XcikC5NOw4g0r/8uhCbeF41yIIAdCufg22YSMyfzAtzmW96tO1Q/PYaloCpEjtiWcufSVpmOFP/oQszWP8g4z3XG/DDPrhvO8Lk2ZghfsCuhi4KvNnBUZOn7Vm4kadt3QIfb4+gCkMn4uA0GLCIGWH/yvF4dQdc6if1ev/1FtGHe7CP54e+PuOm8JjBFkzfXNiXIZq8NdnUNnwEUl+zeXm1H4qog4WC/sceOtUVbRQy9sUYeX13+1yNtRQxGMebD+tsTvY4xtwqjMw7TeOcLe27rJsPAV62vFIsL8HlDuYNC3mZJzg40pxlPjqt+xhQAXM3MOYfQq+89t+4Cr4xaglLZ2NHAY7MZk0SN62c7f8yL4EA81Yg6LeIgDei3ZiNXcLeFKtCvDwbuIoD9Oqane7QH/jfOrIlRRxHeGb7Nmob+PXe7BN9VYqQ0/dOSPRKol0DLRRpwA/2Qn8nbq3nl0ZCbJYfC/8psh/hUAkPUXPRH2+JoWORVzKjBDZ5FaLxV9t5q3rV/YeMVuS9qqzjs1/RvM5aa4cLh3Cc6S1vojBy1QitiGwRxzy4SHkF69dyxnQbyUVOMkuBiMyWg==" SubTotal="200.0" Moneda="AMD" TipoCambio="1" Total="200.16" TipoDeComprobante="I" MetodoPago="PPD" LugarExpedicion="20000" xmlns:cfdi="http://www.sat.gob.mx/cfd/3" xsi:schemaLocation="http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv33.xsd">
<cfdi:Emisor Rfc="WERX631016S30" Nombre="XAIME WEIR ROJO" RegimenFiscal="605"/>
<cfdi:Receptor Rfc="EKU9003173C9" Nombre="ESCUELA KEMPER URGATE" UsoCFDI="G03"/>
<cfdi:Conceptos>
<cfdi:Concepto ClaveProdServ="50211503" Cantidad="1" ClaveUnidad="H87" Unidad="Pieza" Descripcion="Cigarros" ValorUnitario="200.0" Importe="200.0">
<cfdi:Impuestos>
<cfdi:Traslados>
<cfdi:Traslado Base="1" Impuesto="002" TipoFactor="Tasa" TasaOCuota="0.160000" Importe="0.16"/>
</cfdi:Traslados>
<cfdi:Retenciones>
<cfdi:Retencion Base="1" Impuesto="001" TipoFactor="Tasa" TasaOCuota="0.100000" Importe="0.00"/>
<cfdi:Retencion Base="1" Impuesto="002" TipoFactor="Tasa" TasaOCuota="0.106666" Importe="0.00"/>
</cfdi:Retenciones>
</cfdi:Impuestos>
</cfdi:Concepto>
</cfdi:Conceptos>
<cfdi:Impuestos TotalImpuestosRetenidos="0.00" TotalImpuestosTrasladados="0.16">
<cfdi:Retenciones>
<cfdi:Retencion Impuesto="001" Importe="0.00"/>
<cfdi:Retencion Impuesto="002" Importe="0.00"/>
</cfdi:Retenciones>
<cfdi:Traslados>
<cfdi:Traslado Impuesto="002" TipoFactor="Tasa" TasaOCuota="0.160000" Importe="0.16"/>
</cfdi:Traslados>
</cfdi:Impuestos>
<cfdi:Complemento>
<tfd:TimbreFiscalDigital xsi:schemaLocation="http://www.sat.gob.mx/TimbreFiscalDigital http://www.sat.gob.mx/sitio_internet/cfd/TimbreFiscalDigital/TimbreFiscalDigitalv11.xsd" Version="1.1" UUID="f425cd6d-ed30-4a0d-8135-8dc7229b79ff" FechaTimbrado="2022-05-23T18:42:50" RfcProvCertif="SPR190613I52" SelloCFD="dUxav04E0XcbOhMsXjXDlWbFlZdcXqOk/R8DHLd3TILZ7gg5/aw+T+gI9yMLpVLvPkeEm5+A++QWHi0I/26TVTlsx6ejFWxXTEdewmarCuSrRO24CSFPz2dLX6ojy5Eg6QGTV0EQiS3LRtLsnTyqXH2QE7Ne+Y7cqXXEcXWZ63AIAkkWY4U9uQu1/3F0jiHFfMCf4lBuSgDQ8c8LniBKoAsFoTySZmyhJv4h2koz1bE0Yl6Rvrr0NNlmYSH+SGqbkYVsYKM9fbHIDJbNXosRqIGlugOlLIT2499j3gQfTn7d3sdQLtVqn4tcqaDGx2Du2dm1XFJRwT7aB62btNVW1Q==" NoCertificadoSAT="30001000000400002495" SelloSAT="gfFwozFJpvd1zpwvQPCkUWBfBG72/bn1+0CwrgnPx466uzjrL0RMsoSRHplN4dpTiqfAT/+bhGA8KjDDG6p+3RvlVxx1dmUIVffRcTv2Jd1D+zZQRlt3RkHuANjCtOSVZKiW181WUyqzmH7ehL+S7lyBL7odWswW4CGr5UPrMBFaSDSR6K+3aw2nd7SJce/2+rWN4szUIE4YlUS2whPLznlOdsRrSSy6OHJLkptSJaGn86F8bcp46Idz4lDNkI1G72lN3Kmat5cTrA8f9VTj8BfCzlmKdXg/jD7/1vOHm4mF3qmaLUym84Yj370ax7dGxYb4KoNLAxuYRJjJq1wkbw==" xmlns:tfd="http://www.sat.gob.mx/TimbreFiscalDigital" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
</cfdi:Complemento>
</cfdi:Comprobante>
You can also use #marc_s's answer with your existing data type, although I agree the table should be changed if at all possible
WITH XMLNAMESPACES('http://www.sat.gob.mx/cfd/3' AS cfdi)
SELECT
Total = xc.value('#Total' , 'decimal(20,2)'),
TipoDeComprobante = xc.value('#TipoDeComprobante', 'varchar(20)')
FROM tb_cfdi c
CROSS APPLY (
SELECT CAST(CAST(xml AS varbinary(max)) AS xml) AS data
) v
CROSS APPLY v.data.nodes('/cfdi:Comprobante') AS xt(xc)
WHERE c.uuid = 'f425cd6d-ed30-4a0d-8135-8dc7229b79ff';
First of all - get rid of that Image datatype! It's deprecated and will be removed in a future version of SQL Server.
Image is also a binary type - why use that to store textual information like XML ?? Makes no sense.... use XML datatype for best results.
Once you do have your XML in a T-SQL variable #data XML, you can then use this XQuery to get the values you're interested in:
WITH XMLNAMESPACES('http://www.sat.gob.mx/cfd/3' AS cfdi)
SELECT
Total = xc.value('#Total', 'decimal(20,2)'),
TipoDeComprobante = xc.value('#TipoDeComprobante', 'varchar(20)')
FROM
#data.nodes('(/cfdi:Comprobante)') AS XT(XC)
I have a SQL Server database table with a column called XML that contains XML data which is structured like this:
<Item xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://test/data">
<Roots>
<Root>
<Name>Field Name</Name>
<Value>Field Value</Value>
</Root>
<Root>
<Name>Field Name</Name>
<Value>Field Value</Value>
</Root>
</Roots>
I want to use T-SQL to get the Value where Name = Total. I have tried the following but it isn't returning any data:
SELECT [XML]
FROM [BusinessAccount]
WHERE [XML].value('(/Root/Name)[13]', 'VARCHAR(MAX)') LIKE '%Total%'
If anyone could tell me where I've gone wrong?
You are missing the required WITH XMLNAMESPACES for your XML and the path is incorrect.
If you want to bring back rows where the 13th element consists of the text Total you can use the below.
WITH XMLNAMESPACES (DEFAULT 'http://test/data')
SELECT [XML]
FROM [BusinessAccount]
WHERE 1 = [XML].exist('(/Item/Roots/Root/Name)[13][text() = "Total"]')
Otherwise you can add the WITH XMLNAMESPACES to your original query and fix the path there too.
You need to specify namespaces. You can then match <Name> and <Value> pairs and extract the contents of <Value> like so:
SELECT NameNode.value('declare namespace x="http://test/data"; (../x:Value)[1]', 'varchar(100)')
FROM [BusinessAccount]
CROSS APPLY [XML].nodes('declare namespace x="http://test/data"; //x:Root/x:Name') AS n(NameNode)
WHERE NameNode.value('.', 'varchar(100)') = 'Total'
Demo on db<>fiddle
I have a function to insert an item into the database. It takes a lot of values as input and the values are passed as XML.
Consider a sample item XML:
<ROOT>
<Item
ItemName="CarlsApplication"
ItemTypeID="2">
<TSDefaultDescription DefaultitemDescription="C:\t.text"/>
<ItemSellers>
<ComputerObject Alias="" DisplayName="" ServiceName="" UserAccount="" />
<ComputerObject Alias="" DisplayName="" ServiceName="" UserAccount="" />
</ItemSellers>
<ItemOwners>
<ItemOwner Alias="rafchen" FirstName="Rafael" LastName="Chenkov"/>
</ItemOwners>
</Item>
</ROOT>
This has to be passed to stored procedure.
Now, each of these individual values in this XML, I have to extract from somewhere else. I can get the individual values like Item name etc, but how do I organize them into an XML that can be passed?
How do I construct this XML from the values I have?
I guess I will have to make some sort of template with this format and then put variables in that template and fill the variables to prepare the template.
Any help is greatly appreciated.
If I understand what you really want, You can use a query like this to generate that XML:
select
ItemName 'Item/#ItemName', --> Node:`Item` Attribute: `ItemName`
ItemTypeId 'Item/#ItemTypeId',
cast((
select
Alias 'ComputerObject/#Alias',
DisplayName 'ComputerObject/#DisplayName',
ServiceName 'ComputerObject/#ServiceName',
UserAccount 'ComputerObject/#UserAccount'
from
ItemSellers
where
ItemSellers.ItemId = Item.ItemId
for xml path('')) as xml) 'Item/ItemSellers', --> Node:`Item` Sub-Node:`ItemSellers`
cast((
select
Alias 'ItemOwner/#Alias',
FirstName 'ItemOwner/#FirstName',
LastName 'ItemOwner/#LastName'
from
ItemOwners
where
ItemOwners.ItemId = Item.ItemId
for xml path('')) as xml) 'Item/ItemOwners'
from
Item
for xml path('ROOT');
SQL Fiddle Demo
I have a xml file having following data
<SearchProgramsResponse xmlns="http://api.abc.com/2011-03-01/">
<page>1</page>
<items>50</items>
<total>3129</total>
<programItems>
<programItem id="7779">
<name>Coolblue NL</name>
<adrank>5.4</adrank>
<categories>
<category id="40">Cell, Phone & Fax</category>
<category id="11">Internet services</category>
</categories>
</programItem>
<programItem id="7780">
<name>ABC NL</name>
<adrank>2.4</adrank>
<categories>
<category id="42">Cell</category>
<category id="12">services</category>
</categories>
</programItem>
</programItems>
</SearchProgramsResponse>
I want to Transfer this XML data to SQL server tables. But as there are multiple categories for one ITEM.. So how do i process this XML.
I mean I want to transfer DATA to two tables
In tableA one row per record eg :
TableA(ITEM) : programItem , Name , adrank
TABLEB(Category) : ITEMID, categoryID ,CategoryName
I have gone through XML reference but all are with Single value xml attribute , HOW can I process this type of XML ?
I have tried both queries below but no success
DECLARE #xmldata XML
SET #xmldata =
N'<SearchProgramsResponse xmlns="http://api.abc.com/2011-03-01/">
<page>1</page>
<items>50</items>
<total>3129</total>
<programItems>
<programItem id="7779">
<name>Coolblue NL</name>
<adrank>5.4</adrank>
<categories>
<category id="40">Cell, Phone & Fax</category>
<category id="11">Internet services</category>
</categories>
</programItem>
<programItem id="7780">
<name>ABC NL</name>
<adrank>2.4</adrank>
<categories>
<category id="42">Cell</category>
<category id="12">services</category>
</categories>
</programItem>
</programItems>
</SearchProgramsResponse>';
SELECT
Tbl.Col.value('name[1]', 'varchar(70)')
FROM #xmldata.nodes('/SearchProgramsResponse/programItems/programItem') Tbl(Col)
SELECT
XReservering.value('#programItem', 'int'),
XOpties.value('(.)', 'varchar(50)')
FROM
#xmldata.nodes('/SearchProgramsResponse/programItems/programItem') AS XTbl1(XReservering)
CROSS APPLY
XReservering.nodes('categories/category') AS XTbl2(XOpties)
Well you can apply nodes() function twice to get all the categories with item_id:
;with xmlnamespaces(default 'http://api.abc.com/2011-03-01/')
select
t.c.value('#id', 'int') as id,
t.c.value('(name/text())[1]', 'nvarchar(max)') as name,
t.c.value('(adrank/text())[1]', 'decimal(29,10)') as adrank
from #data.nodes('SearchProgramsResponse/programItems/programItem') as t(c)
;with xmlnamespaces(default 'http://api.abc.com/2011-03-01/')
select
t.c.value('#id', 'int') as item_id,
c.c.value('#id', 'int') as category_id,
c.c.value('text()[1]', 'nvarchar(max)') as category_name
from #data.nodes('SearchProgramsResponse/programItems/programItem') as t(c)
outer apply t.c.nodes('categories/category') as c(c)
Suppose you have a TSQL query:
1 as 'Category1/#Level',
2 as 'Category2/#Level',
t.MainCat as 'Category1',
t.SubCat as 'Category2'
FOR XML PATH (''), ROOT('Taxonomy')
which generates following result:
<Taxonomy>
<Category1 Level="1">Clothing</Category1>
<Category2 Level="2">Jeans</Category2>
</Taxonomy>
The element Category1 and Category2 have unique names for the sql query to generate and convert in to xml format. That's why I used Category1 and Category2. I would like the end result to be like this:
<Taxonomy>
<Category Level="1">Clothing</Category>
<Category Level="2">Jeans</Category>
</Taxonomy>
This could be done using XML EXPLICIT like here, but since my code is much larger it becomes very cluttered and complex quite fast.
With xml.modify you can change values or attributes, but not the element itself.
Is there a way to store the first query result in a #X1 xml variable and then change the element Category1 & Category2 into Category and put it into variable #X2? Something like a search and replace used in text files, but then during the query.
sneaking a null in between elements can do the trick:
Select
1 as 'Category/#Level',
t.MainCat as "Category",
null,
2 as 'Category/#Level',
t.SubCat as "Category"
FOR XML PATH (''), ROOT('Taxonomy')
Also you may use nesting:
select
(select 1 as '#Level', 'Clothing'
for xml path('Category'), type),
(select 2 as '#Level', 'Jeans'
for xml path('Category'), type)
for xml path('Taxonomy');
or values clause to construct list of categories before forming output xml:
select Cat.Level as '#Level', Cat.Value as 'text()'
from (values
(1, 'Clothing')
,(2, 'Jeans')
) Cat(Level, Value)
for xml path('Category'), root('Taxonomy');