SQL XML Output with PDFs Attached - sql

I have a SQL Server procedure written that exports data in XML format. In the database, I also have PDFs that have been stored as BLOB files that I need to export with the data. Is it possible to convert these to PDF as I export?

This is really easy...
I assume, that the BLOBs live in a table column of type VARBINARY(MAX). Including such a column into a SELECT ... FOR XML PATH will implicitly do the conversion for you.
In this example I use three tiny binary BLOBs, put them into a XML-variable and re-read them. There should be not difference with your PDF BLOBs:
DECLARE #tbl TABLE(ID INT,Content VARBINARY(MAX));
INSERT INTO #tbl VALUES
(1,0x101010101010101010101)
,(2,0x110011001100110011001100)
,(3,0x111000111000111000111000);
DECLARE #xml XML=
(
SELECT ID AS [#ID]
,Content
FROM #tbl
FOR XML PATH('myData'),ROOT('root')
);
SELECT #xml;
The result as XML (implicit conversion to base64)
<root>
<myData ID="1">
<Content>AQEBAQEBAQEBAQE=</Content>
</myData>
<myData ID="2">
<Content>EQARABEAEQARABEA</Content>
</myData>
<myData ID="3">
<Content>ERAAERAAERAAERAA</Content>
</myData>
</root>
Now I read the data from the XML
SELECT B.value('Content[1]','varbinary(max)') AS BackToVarbinary
FROM #xml.nodes('/root/myData') AS A(B)
The result
BackToVarbinary
0x0101010101010101010101
0x110011001100110011001100
0x111000111000111000111000

Related

Is it possible to insert xml as a string to varbinary and it will be similiar to be inserted as a blob?

Is it possible to insert xml as a string to varbinary and it will be similiar to be inserted as a blob? For example When i insert xml as a blob
declare #i int = 1
declare #file varchar(2000) = concat('K:\test\file',#i,'.xml');
declare #blob varbinary(max)
declare #sql nvarchar(max) = concat(N'select #blob = BulkColumn FROM
OPENROWSET(BULK ''',#file,''', SINGLE_BLOB) myfile')
exec sp_executesql #sql, N'#blob varbinary(max) output', #blob = #blob
output
select #blob
insert tab1 values (#blob)
File inserted as a blob look like this
When i insert the same xml but as a string
INSERT INTO tab1 VALUES ( Convert (varbinary(MAX), N'
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Dont forget me this weekend!</body>
</note>' ))
It looks completaly different
#Jacob
#Siyual
It is a very bad idea to store a file as VARBINARY just as you read it from disk.
Some background
DECLARE #YourThirdVarbinary VARBINARY(MAX)=0xfffe3c006e006f00740065003e003c0074006f003e00;
SELECT CAST(#YourThirdVarbinary AS NVARCHAR(MAX));
The leading FFFE points to an UTF-16 little endian encoded file with a byte order mark.
The following 3C00 6E00 6F00 ... shows clearly, that you are reading 2-byte encoded characters.
SQL-Server uses UCS-2 internally and is not capeable to read each and any UTF-16 encoding natively. I assume, that you are living in a country, where you are dealing with many characters, which are not plain latin...
But the first example you provide is a single-byte encoded string:
DECLARE #YourFirstVarbinary VARBINARY(MAX)=0x3c6e6f74653E0D0A3c746f3e546f76653c2f746f3e;
SELECT CAST(#YourFirstVarbinary AS VARCHAR(MAX));
The missing 00 between your code points shows clearly, that this is 1-byte-storage without a BOM, probably some kind of UTF-8!
UTF-8 stores plain latin with one single byte, but special characters will take more bytes, up to 4 bytes for one single letter.
SQL-Server will treat a 1-byte encoded string as VARCHAR, which is extended ascii, relying on a COLLATION (including a code page) (multi-byte-codes must lead to errors!)
You will find the same codepoints forming the word <note>:
DECLARE #PureCodePoints VARBINARY(MAX)=0x3c6e6f74653E;
SELECT CAST(#PureCodePoints AS VARCHAR(MAX));
And as 2-byte code (see the NVARCHAR):
DECLARE #PureCodePointsWide VARBINARY(MAX)=0x3c006e006f00740065003E00;
SELECT CAST(#PureCodePointsWide AS NVARCHAR(MAX));
Clear advise
Store your XML in a natively typed column! Advantage: XML is not stored as the text you see, but as a hierachy tree. This is much faster! With your approach you'd have to cast the VARBINARY to a string and parse this over and over again...
Never store data as VARBINARY, if you cannot ensure, that you know the encoding in any case and that SQL-Server will be able to deal with this format.
The way you store your XML depends on what you're going to do with this data.
if your goal is just to store and access the file, regardless of whether it is indeed an XML or not, varbinary or FILESTREAM is absolutely fine.
if you know it is a text file (including XML) but don't require any XML-specific operations with it, you'd be okay with varchar or nvarchar.
if you're going to do any kind of XML manipulations, xml would be the logical choice.
From my experience, there are some caveats in the latter:
An XML might be signed and, if you should be careful not to break it. In this case, you should consider storing the XML as a binary, but add an extra XML column.
If you have an XML that specifies an encoding that is not compatible with the one the application provides, you might have an error such as:
XML parsing: line 1, character 45, unable to switch the encoding
The following examples illustrate this scenario:
SELECT CAST(N'<?xml version="1.0" encoding="windows-1251"?><xml></xml>' AS xml)
SELECT CAST(N'<?xml version="1.0" encoding="utf-8"?><xml></xml>' AS xml)
SELECT CAST('<?xml version="1.0" encoding="utf-16"?><xml></xml>' AS xml)
while these are fine:
SELECT CAST(N'<?xml version="1.0" encoding="utf-16"?><xml></xml>' AS xml)
SELECT CAST('<?xml version="1.0" encoding="utf-8"?><xml></xml>' AS xml)
SELECT CAST('<?xml version="1.0" encoding="windows-1251"?><xml></xml>' AS xml)
SELECT CAST(N'<xml></xml>' AS xml)
SELECT CAST('<xml></xml>' AS xml)

Showing XML Data in SQL table

I have an xml file which shows data like this:
<learner>
<name>Smith</name>
<ULN>123456</ULN>
</learner>
<learner>
<name>Jones</name>
<ULN>56789</ULN>
</learner>
I have a table that stores the files as varchar (max) as I cannot upload directly as xml from my front end system.
I am able to read the file as an xml file by creating a table:
declare #ILRDATA table (Data xml)
Insert into #ILRDATA (Data)
select FileUpload from ILRDATA.dbo.ILRUpload
select * from #ILRDATA
I now want to create a #table with the columns (Name varchar (50), ULN varchar (10))
I want to then populate this with the xml data
Can someone please help me before I waste a whole day trying to figure this out.
Thanks
select
t.c.value('name[1]', 'nvarchar(50)') as name,
t.c.value('ULN[1]', 'nvarchar(10)') as ULN
from #ILRDATA as d
outer apply d.Data.nodes('learner') as t(c)

Importing XML data with a namespace into SQL Server

I have an XML document containing data that I want to import into existing SQL server tables:
<?xml version="1.0" encoding="UTF-8"?>
<geia:GEIA-STD-0007 xmlns:geia="http://www.geia_STD_0007.com/2006/schema" xmlns:xsi=`enter code here`"http://www.w3.org/2001/XMLSchema-instance">
<geia:full_file>
<geia:XA_end_item_acronym_code_data>
<geia:end_item_acronym_code>ON565</geia:end_item_acronym_code>
<geia:logistics_support_analysis_control_number_structure>32222222</geia:logistics_support_analysis_control_number_structure>
</geia:XA_end_item_acronym_code_data>
<geia:XB_logistics_support_analysis_control_number_indentured_item_data>
<geia:end_item_acronym_code>ON565</geia:end_item_acronym_code>
<geia:logistics_support_analysis_control_number>E2C06CAAE</geia:logistics_support_analysis_control_number>
<geia:alternate_logistics_support_analysis_control_number_code>06</geia:alternate_logistics_support_analysis_control_number_code>
<geia:logistics_support_analysis_control_number_type>P</geia:logistics_support_analysis_control_number_type>
<geia:logistics_support_analysis_control_number_nomenclature>CABLE ASSEMBLY W5</geia:logistics_support_analysis_control_number_nomenclature>
<geia:reliability_availability_and_maintainability_indicator>Y</geia:reliability_availability_and_maintainability_indicator>
<geia:system_end_item_identifier>N</geia:system_end_item_identifier>
<geia:technical_manual_functional_group_code>41JE150</geia:technical_manual_functional_group_code>
</geia:XB_logistics_support_analysis_control_number_indentured_item_data>
<geia:XB_logistics_support_analysis_control_number_indentured_item_data>
<geia:end_item_acronym_code>ON565</geia:end_item_acronym_code>
<geia:logistics_support_analysis_control_number>E2C06CAAMZZ</geia:logistics_support_analysis_control_number>
<geia:alternate_logistics_support_analysis_control_number_code>06</geia:alternate_logistics_support_analysis_control_number_code>
<geia:logistics_support_analysis_control_number_type>P</geia:logistics_support_analysis_control_number_type>
<geia:logistics_support_analysis_control_number_nomenclature>CONSUMABLES</geia:logistics_support_analysis_control_number_nomenclature>
<geia:system_end_item_identifier>N</geia:system_end_item_identifier>
</geia:XB_logistics_support_analysis_control_number_indentured_item_data>
</geia:full_file>
</geia:GEIA-STD-0007>
I have been looking online for code that can help me accomplish this task but have not had much luck. So far this is the code I have been trying to use:
----step 1 Import XML data from an XML file into SQL Server table using the OPENROWSET function
drop table lsa.XMLwithOpenXML
CREATE TABLE lsa.XMLwithOpenXML
(
Id INT IDENTITY PRIMARY KEY,
XMLData XML,
LoadedDateTime DATETIME
)
INSERT INTO lsa.XMLwithOpenXML(XMLData, LoadedDateTime)
SELECT CONVERT(XML, BulkColumn) AS BulkColumn, GETDATE()
FROM OPENROWSET(BULK 'D:\Temp\e2c.xml', SINGLE_CLOB) AS x;
--SELECT * FROM lsa.XMLwithOpenXML
--get xmldata to shred
-------------------------------------------------------------------------
Declare #xmlData as xml
Select #xmlData = XMLData FROM lsa.XMLwithOpenXML
------------------------------------------------------------
--create variable to hold the int id of the xmldoc created by the sp
DECLARE #XMLdocId AS INT
--procedureName, outputId, InputData
EXEC sp_xml_preparedocument #XMLdocId OUTPUT, #xmlData , '<geia:GEIA-STD-0007 xmlns:geia="http://www.geia_STD_0007.com/2006/schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
--create an OenXML query to shred the doc, or transfer it into rowsets
INSERT INTO [lsa].[XB]
(
[end_item_acronym_code])
Select end_item_acronym_code from
OpenXML(#XMLdocId, '/geia:XB_logistics_support_analysis_control_number_indentured_item_data',2)
;WITH XMLNAMESPACES ('xmlns:geia="http://www.geia_STD_0007.com/2006/schema' AS geia, DEFAULT 'http://www.w3.org/2001/XMLSchema-instance' )
SELECT
x.c( '.' ) AS result
FROM #xmlData.nodes('geia:GEIA-STD-0007/geia:full_file/geia:XB_logistics_support_analysis_control_number_indentured_item_data') x(c)
EXEC sp_xml_removedocument #XMLdocId
I realize that this code is very wrong. The path that I am passing to the OpenXML() function is wrong, but I have tried many iterations of it and none have been successful. I am also not 100% certain how to go about pulling out the different table data (ie XA, XB) but my plan is to pull from one table then reiterate the code for each additional table. This code will be used to import large amounts of data (I only posted a part of the xml file) with many different tables. If anyone has a better idea, then I would welcome it, as I am still learning.

How to read XML values in SQL Server

I have a list of strings as:
List<string> list = new List<string>();
list.Add("912-123898493");
list.Add("021-36574864");
list.Add("021-36513264");
I want to convert it in XML and then send it as a parameter to Stored procedure, so that this could be read.
How to read this XML in sql server so that each and every string can be placed in different cell? Please help!!
It depends of what structure your xml will have.
Here's example of how you can read elements xml:
declare #Data xml
select #Data = '
<root>
<value>912-123898493</value>
<value>021-36574864</value>
<value>021-36513264</value>
</root>'
select T.C.value('data(.)', 'nvarchar(128)') as [Data]
from #Data.nodes('/root/value') as T(C)

Parse and Import XML into Table in SQL Server

I've written a CLR assembly that exports a table's data to an XML file. Now I want to import this data into a temp table on another instance.
The XML file structure is like this:
<row>
<SystemInformationID>1</SystemInformationID>
<Database_x0020_Version>10.00.80404.00</Database_x0020_Version>
<VersionDate>2008-04-04T00:00:00</VersionDate>
<ModifiedDate>2008-04-04T00:00:00</ModifiedDate>
</row>
I want the XML to be parsed in the destination location and imported into a temp table. I have the main table there too, so I can get the table structure from there.
Is there a way? I use OPENXML but it seems not to be working correctly. I can read the XML file into a table, which will be stored in a column with XML data type. My problem is parsing the data in that column.
This is a temp attempt:
CREATE TABLE ##T (IntCol int, XmlCol xml)
GO
INSERT INTO ##T(XmlCol)
SELECT * FROM OPENROWSET(
BULK 'c:\HISOutput.xml',
SINGLE_CLOB) AS x
--works correctly up to this point
DECLARE #x xml
DECLARE #id int
SELECT #x=XmlCol FROM ##T
EXEC sp_xml_preparedocument #id OUTPUT, #x
SELECT *
FROM OPENXML (#id,'/row',2)
WITH
dbo.awbuildversion
--I used dbo.awbuildversion table from AdventureWorks DB for testing
this doesn't show the first column no matter how I change the OPENXML instruction.
tx in advance
I'm not quite sure what you want, because your comment to OMG Ponies' answer is different to your question. What is the problem with temp table/table structure?
Anyway, I wouldn't use OPENXML or sp_xml_preparedocument on SQL Server 2050 and above (which you have I assume because you mentioned CLR) because of the memory leak risk.
Also, if you need the table stucture then you could use INTO #tempTable
DECLARE #foo xml
SET #foo = '<row>
<SystemInformationID>1</SystemInformationID>
<Database_x0020_Version>10.00.80404.00</Database_x0020_Version>
<VersionDate>2008-04-04T00:00:00</VersionDate>
<ModifiedDate>2008-04-04T00:00:00</ModifiedDate>
</row>'
SELECT
bar.value('./SystemInformationID[1]','INT') AS 'SystemInformationID',
bar.value('./Database_x0020_Version[1]','VARCHAR(14)') AS 'Database_x0020_Version',
bar.value('./VersionDate[1]','DATETIME') AS 'VersionDate',
bar.value('./ModifiedDate[1]','DATETIME') AS 'ModifiedDate'
INTO #tempTable -- This?
FROM
#foo.nodes('/row') AS foo(bar) --use nodes not OPENXML