David Medina
David Medina

Reputation: 3

SQL Server insert from a XML file

I'm trying to insert info from a XML file to a temporal table in SQL Server, but I can't get it.

First I declare a table variable, then I make an insert into this table, and the values come from an XML file, at the end I select data from the table variable that should have the info inserted before, but the select just returns an empty result without errors.

Any ideas?

This is the XML

<?xml version="1.0" encoding="UTF-8"?>
<cfdi:Comprobante Moneda="MXN" NumCtaPago="3746" LugarExpedicion="something" metodoDePago="03" tipoDeComprobante="ingreso" total="434.30" descuento="0.00" subTotal="402.14" 
 noCertificado="00001000000403736552" formaDePago="pago en una sola exhibición" sello="something" fecha="something" folio="something" serie="something" version="3.2" xsi:schemaLocation="http://something http://something" xmlns:xsi="http://something" xmlns:cfdi="http://something">

<cfdi:Addenda xsi:schemaLocation="https://something" xmlns:xsi="http://something" xmlns="https://something">
<ADDENDABENAVIDES>
<HEADERFACTURA INTNOTAENTRADA="something" STRREMISIONID="something" STRCLAVEFACTREM= "something" FLTIEPSFACTURA="something" FLTIVADESCUENTO="something" FLTDESCUENTOFACTURA="something" FLTBRUTOFACTURA="something" FLTIVAFACTURA="something" FLTNETOFACTURA="something" STRALMACENID="something" STRCENTROLOGISTICOID="something" DTMFECHAFACTURA="something" INTNOREGISTRO="something" STRFOLIO="something" STRSERIE="something" INTBODEGAID="something" INTMAYORISTAID="something" STRNUMEROPROVEEDOR="something"/>
<DETALLEFACTURA>
  <DETALLEPRODUCTO />
</DETALLEFACTURA>
</ADDENDABENAVIDES>
</cfdi:Addenda>
</cfdi:Comprobante>   

And this is from SQL

DECLARE @HEADERFACTURA TABLE
(
     Id int IDENTITY(1,1),
     [INTNOTAENTRADA] int,
     [STRREMISIONID] NVARCHAR(max),
     [STRCLAVEFACTREM] NVARCHAR(max), 
     [FLTIEPSFACTURA] decimal(10,2),
     [FLTIVADESCUENTO] decimal(10,2),
     [FLTDESCUENTOFACTURA] decimal(10,2),
     [FLTBRUTOFACTURA] decimal(10,2),
     [FLTIVAFACTURA] decimal(10,2),
     [FLTNETOFACTURA] decimal(10,2),
     [STRALMACENID] int,
     [STRCENTROLOGISTICOID] NVARCHAR(max),
     [DTMFECHAFACTURA] NVARCHAR(max),
     [INTNOREGISTRO] int,
     [STRFOLIO] int,
     [STRSERIE] NVARCHAR(max),
     [INTBODEGAID] int,
     [INTMAYORISTAID] int,
     [STRNUMEROPROVEEDOR] NVARCHAR(max)
)

;with xmlnamespaces('http://something' as cfdi)
INSERT INTO @HEADERFACTURA ([INTNOTAENTRADA], [STRREMISIONID],
                            [STRCLAVEFACTREM], [FLTIEPSFACTURA],
                            [FLTIVADESCUENTO], [FLTDESCUENTOFACTURA],
                            [FLTBRUTOFACTURA], [FLTIVAFACTURA],
                            [FLTNETOFACTURA], [STRALMACENID],
                            [STRCENTROLOGISTICOID], [DTMFECHAFACTURA],
                            [INTNOREGISTRO], [STRFOLIO],
                            [STRSERIE], [INTBODEGAID],
                            [INTMAYORISTAID], [STRNUMEROPROVEEDOR])
SELECT
    X.Solicitud.query('INTNOTAENTRADA').value('.', 'int'),
    X.Solicitud.query('STRREMISIONID').value('.', 'nvarchar(50)'),
    X.Solicitud.query('STRCLAVEFACTREM').value('.', 'nvarchar(50)'),
    X.Solicitud.query('FLTIEPSFACTURA').value('.', 'decimal(10,2)'),
    X.Solicitud.query('FLTIVADESCUENTO').value('.', 'decimal(10,2)'),
    X.Solicitud.query('FLTDESCUENTOFACTURA').value('.', 'decimal(10,2)'),
    X.Solicitud.query('FLTBRUTOFACTURA').value('.', 'decimal(10,2)'),
    X.Solicitud.query('FLTIVAFACTURA').value('.', 'decimal(10,2)'),
    X.Solicitud.query('FLTNETOFACTURA').value('.', 'decimal(10,2)'),
    X.Solicitud.query('STRALMACENID').value('.', 'int'),
    X.Solicitud.query('STRCENTROLOGISTICOID').value('.', 'nvarchar(50)'),
    X.Solicitud.query('DTMFECHAFACTURA').value('.', 'nvarchar(50)'),
    X.Solicitud.query('INTNOREGISTRO').value('.', 'int'),
    X.Solicitud.query('STRFOLIO').value('.', 'int'),
    X.Solicitud.query('STRSERIE').value('.', 'nvarchar(50)'),
    X.Solicitud.query('INTBODEGAID').value('.', 'int'),
    X.Solicitud.query('INTMAYORISTAID').value('.', 'int'),
    X.Solicitud.query('STRNUMEROPROVEEDOR').value('.', 'nvarchar(50)')
 FROM  
     (SELECT 
          CAST (X AS XML)
      FROM 
          OPENROWSET (BULK 'C:\aa.xml', SINGLE_BLOB) AS T(X)
     ) AS T(X)
CROSS APPLY 
     x.nodes('/cfdi:Comprobante/cfdi:Addenda/ADDENDABENAVIDES/HEADERFACTURA') AS X(Solicitud);

SELECT *
FROM @HEADERFACTURA

Thanks in advance.

Upvotes: 0

Views: 196

Answers (2)

Gottfried Lesigang
Gottfried Lesigang

Reputation: 67321

In your attempt to provide an XML with cleaned data you went much to far...

Values, which should be numeric (e.g. int) show up as "Something", actually everything shows up as "something"...

Another problem is, that your namespaces are all set to the same URL.

Look at this (highly condensed) sample of your XML (the default namespace is in the second level!):

<?xml version="1.0" encoding="UTF-8"?>  
<cfdi:Comprobante xmlns:cfdi="http://something" Moneda="MXN">
  <cfdi:Addenda xmlns="https://Default">
    <ADDENDABENAVIDES>
      <HEADERFACTURA INTNOTAENTRADA="123" STRREMISIONID="something" />
      <DETALLEFACTURA>
        <DETALLEPRODUCTO />
      </DETALLEFACTURA>
    </ADDENDABENAVIDES>
  </cfdi:Addenda>
</cfdi:Comprobante>

One more problem is, that your XML-file starts with a declaration with encoding="utf-8", but your content includes special characters. This declaration will be ommitted by SQL Server in any case, but you cannot read UTF-8 via NVARCHAR into XML. Therefore I read this into NVARCHAR(MAX), call REPLACE to introduce utf-16 and cast this to XML.

The next point is, that you want to read attributes, but you try to find them as elements.

You would query this like here:

;WITH XMLNAMESPACES(DEFAULT 'https://Default'
                           ,'http://something' AS cfdi)

SELECT
    --An attribute from <cfdi:Comprobante>
    T.X.value('(/cfdi:Comprobante/@Moneda)[1]','nvarchar(max)') AS Moneda,
    --Many attributes in <HEADERFACTURA>
    X.Solicitud.value('@INTNOTAENTRADA', 'int') AS INTNOTAENTRADA,
    X.Solicitud.value('@STRREMISIONID', 'nvarchar(50)') AS STRREMISIONID
 FROM  
     (SELECT 
          CAST(REPLACE(CAST (X AS NVARCHAR(MAX)),'utf-8','utf-16') AS XML)
      FROM 
          OPENROWSET (BULK 'C:\aa.xml', SINGLE_CLOB) AS T(X)
     ) AS T(X)
CROSS APPLY 
     x.nodes('/cfdi:Comprobante/cfdi:Addenda/ADDENDABENAVIDES/HEADERFACTURA') AS X(Solicitud);

Upvotes: 0

Jim
Jim

Reputation: 962

You have a specific namespace and default namespace in your input xml. Fix the following line and you will get results:

CROSS APPLY x.nodes('//cfdi:Comprobante/cfdi:Addenda/*:ADDENDABENAVIDES/*:HEADERFACTURA') AS X(Solicitud);

Take note that your query will still fail from your example because all of the attributes you are querying are strings and your query is casting them into types.

Also note, you can simplify each of your attribute statements as per this example: X.Solicitud.query('STRNUMEROPROVEEDOR').value('.', 'nvarchar(50)') becomes X.Solicitud.value('@STRNUMEROPROVEEDOR', 'nvarchar(50)')

Lastly, notice your xml is <?xml version="1.0" encoding="UTF-8"?>; I believe it should be <?xml version="1.0" encoding="UTF-16"?> since you are using accented characters. Your XML file may fail to parse.

Upvotes: 1

Related Questions