Convert SQL Server varbinary field to string? - sql-server

I have a column in a sql server 2005 database that stores xml as varbinary,
the value lookes something like:
0x3C3F54657374696E672075706C6F616 // but much longer
Is there an online conversion tool for converting this to a readable string?

select CAST(0x3C3F54657374696E672075706C6F61643F3E3C666F6F3E3C2F666F6F3E as XML)
appears to work.
Online Conversion Link
And as it seems your datatype is image...
;with t(c) as
(
select CAST(0x3C3F54657374696E672075706C6F61643F3E3C666F6F3E3C2F666F6F3E as IMAGE)
)
select CAST(CAST(c as VARBINARY(MAX)) as XML)
from t

You can use the undocumented stored procedure.
SELECT fn_varbintohexstr(#YourVarbar)
You should also be able to just cast it to a varchar(max) as well
Select CAST(#YourVarbar as Varchar(max))
Third alternative is to create an XML document out of it and use forXML
Example at the following location http://beyondrelational.com/blogs/jacob/archive/2009/06/13/converting-varbinary-to-varchar-using-for-xml.aspx
DECLARE #x VARBINARY(10)
SELECT #x = CAST('10' as VARBINARY(10))
SELECT #x AS VarBinaryValue
SELECT (
SELECT
CHAR(SUBSTRING(#x,number,1)) AS 'text()'
FROM master..spt_values
WHERE type = 'P'
AND Number BETWEEN 1 AND LEN(#x)
FOR XML PATH('')
) AS TextValue

Related

How to convert varbinary(max) to base64 SQL Server 2014

I have an Image saved as varbinary(max) in SQL Server 2014:
0xFFD8FFE115064578696600004D4D002A0000000800070...........
I want to convert it to Base64 To use it in Flutter.
I tried
SELECT CAST('' as varbinary(max)) FOR XML PATH(''), BINARY BASE64
and get :
MHhGRkQ4RkZFMTE1MDY0NTc4Njk2NjAwMDA0RDREMDAyQTAwMDAwMDA4MDAwN..........
But according to this site I should get:
/9j/4RUGRXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUAAAABAAAAYgEbAA........
So how to convert varbinary(max) to base64?
Why are you attempting to CAST() the varbinary data? You just need to select it as an element or an attribute for the varbinary value to get base64 encoded...
/*
* Data setup...
*/
if object_id('tempdb..#demo') is not null
drop table #demo;
create table #demo (
fancyImage varbinary(max)
);
insert #demo (fancyImage) values (0xFFD8FFE115064578696600004D4D002A000000080007);
/*
* Select as an element containing base64 data
*/
select fancyImage as [base64DemoElement]
from #demo
for xml path(''), binary base64;
/*
* Select as an attribute containing base64 data
*/
select fancyImage as [#base64Attribute]
from #demo
for xml path('demoElement'), binary base64;
The first select outputs the base data in an element:
<base64DemoElement>/9j/4RUGRXhpZgAATU0AKgAAAAgABw==</base64DemoElement>
The second select outputs the base64 data in an attribute:
<demoElement base64Attribute="/9j/4RUGRXhpZgAATU0AKgAAAAgABw==" />
Following comments discussion with #DaleK, a third alternative to return the bare base64 characters without any XML tags:
select (
select top 1 cast(fancyImage as varbinary(max)) as [base64DemoElement]
from #demo
for xml path(''), type, binary base64
).value('.', 'varchar(max)') as [Base64 characters];
Which outputs:
Base64 characters
/9j/4RUGRXhpZgAATU0AKgAAAAgABw==
To select a bare Bas64 value in SQL Server, without any XML node, you just need an unnamed column in FOR XML
SELECT CAST(fancyImage AS varbinary(max))
FROM #demo
FOR XML PATH(''), BINARY BASE64;
Or as a correlated subquery
SELECT
myBase64 = (
SELECT CAST(fancyImage AS varbinary(max))
FOR XML PATH(''), BINARY BASE64
)
FROM #demo;
db<>fiddle
I think it was v2008 of SQL-Server, when base64 was made the default in XML for binaries (before it was a hex string). No need to specify this explicitly.
(The option BINARY BASE64 is needed with mode AUTO...)
Just to demonstrate the back and forth I declare some text (a chain of characters) and cast it to binary (the same chain of bytes, but not a string any more):
DECLARE #someText VARCHAR(100) = 'This is just some text...';
DECLARE #binary VARBINARY(MAX) = CAST(#someText AS VARBINARY(MAX));
--In this case it's okay to rely on implicit casting: easy approach
DECLARE #base64_easy VARCHAR(100) = (SELECT #binary FOR XML PATH(''));
--Just to demonstrate that the base64 we found (VGhpcyBpcyBqdXN0IHNvbWUgdGV4dC4uLg==) is correct we reconvert it simply by casting it to XML and using .value() to retrieve it as binary:
DECLARE #reConverted VARBINARY(MAX) = (SELECT CAST(#base64_easy AS XML).value('.','varbinary(max)'));
--Casting this chain of bytes into a varchar again will show its (unchanged) content:
SELECT CAST(#reConverted AS VARCHAR(100));
All of this can be used within ad-hoc queries.
Hint:
The more explicit statement SELECTs the value into XML and reads this into text via .value()
(The ,type is needed to allow for XML methods)
DECLARE #base64 VARCHAR(100) = (SELECT #binary FOR XML PATH(''), type).value('.','nvarchar(max)'); --VGhpcyBpcyBqdXN0IHNvbWUgdGV4dC4uLg==

Retrieve specific fields of the imported to SQL Server multiple XMLs

I have multiple XML files with the same structure, I have imported them to SQL Server 2017 with the following commands:
DDL:
CREATE DATABASE xmlFiles
GO
USE xmlFiles
CREATE TABLE tblXMLFiles (IntCol int, XmlData xml);
GO
DML:
USE xmlFiles
INSERT INTO [dbo].[tblXMLFiles](XmlData) SELECT * FROM OPENROWSET(BULK 'C:\xmls\1.xml', SINGLE_BLOB) AS x;
INSERT INTO [dbo].[tblXMLFiles](XmlData) SELECT * FROM OPENROWSET(BULK 'C:\xmls\2.xml', SINGLE_BLOB) AS x;
…
INSERT INTO [dbo].[tblXMLFiles](XmlData) SELECT * FROM OPENROWSET(BULK 'C:\xmls\N.xml', SINGLE_BLOB) AS x;
Now I want to query the data:
USE xmlFiles
GO
DECLARE #XML AS XML, #hDoc AS INT, #SQL NVARCHAR (MAX)
SELECT #XML = XmLData FROM tblXMLFiles
EXEC sp_xml_preparedocument #hDoc OUTPUT, #XML
SELECT Surname , GivenNames
FROM OPENXML(#hDoc, 'article/ref-list/ref/mixed-citation')
WITH
(
Surname [varchar](100) 'string-name/surname',
GivenNames [varchar](100) 'string-name/given-names'
)
EXEC sp_xml_removedocument #hDoc
GO
The query is working, but the problem is that it returns the data only when there is only one row in a data source table — tblXMLFiles. If I add more than one row, I get empty result set.
Important:
The situation is changing if I add to the outer SELECT clause (SELECT #XML = XmLData…) the TOP statement, then it returns the queried data of the specific row number, according to the TOP value.
How can I retrieve the data not only when there is one line in the table, but many rows?
FROM OPENXML with the corresponding SPs to prepare and to remove a document is outdated and should not be used any more. Rather use the appropriate methods the XML data type provides.
Without an example of your XML it is quite difficult to offer a solution, but my magic crystal ball tells me, that it might be something like this:
SELECT f.IntCol
,mc.value('(string-name/surname)[1]','nvarchar(max)') AS Surname
,mc.value('(string-name/given-names)[1]','nvarchar(max)') AS GivenNames
FROM dbo.tblXMLFiles AS f
OUTER APPLY f.XmlData.nodes('article/ref-list/ref/mixed-citation') AS A(mc)

Creating XML from SQL Table (Unique XML formatting)

So, I'm trying to create a XML file from a SQL table. I do know of the route of using...
Select * From dbo.[db_name]
FOR XML PATH
But the issue at hand is that the XML styling/formatting is quite odd...
<ID>170607A13</ID>
<MaterialActual>
<MaterialLotID>170607A13</MaterialLotID>
<MaterialActualProperty>
<ID>CreationDate</ID>
<Value>
<ValueString>2017-06-07T12:26:27.667-05:00</ValueString>
</Value>
</MaterialActualProperty>
Therefore, I decided I could go the route of concatenating it and inserting into the XML file. Like so...
DECLARE #NAME varchar(50)
DECLARE #LOCATION varchar(50)
DECLARE #SearchXML xml
SET #SearchXML = '<Root>
<CallerInformation>
<LastName>' + #LOCATION + '</LastName>
<FirstName>' + #NAME + '</FirstName>
</CallerInformation>
</Root>'
SELECT #SearchXML
But when doing this I get returned...
If I could get pointed in the right direction or even a example that would be great!
But the issue at hand is that the XML styling/formatting is quite odd...
What is odd there? The only thing odd I can see is the attempt to solve this on string level...
Your question is missing sample data and expected output. The simple select you provide tells us nothing, the XML you provide is an inclompete fragment and the actual example is something completely different...
Just some hints:
Do not concatenate XML on string level!
please read How to ask a good SQL question
and How to create a MCVE
Your simple example should be done like this:
DECLARE #NAME varchar(50)
DECLARE #LOCATION varchar(50)
DECLARE #SearchXML xml
SET #SearchXML =
(
SELECT #LOCATION AS LastName
,#NAME AS FirstName
FOR XML PATH('CallerInformation'),ROOT('Root'),TYPE
);
SELECT #SearchXML;
This will lead to an almost empty (but valid!) XML, put any value into the variables and you will see the XML filled.
UPDATE: Your odd XML...
Try something like this:
SET #xml=
(
SELECT '170607A13' AS ID
,'170607A13' AS [MaterialActual/MaterialLot]
,'CreationDate' AS [MaterialActual/MaterialActualProperty/ID]
,GETDATE() AS [MaterialActual/MaterialActualProperty/Value/ValueString]
FOR XML PATH('')
);
SELECT #xml
UPDATE 2: Very long XPath...
This is your error: name-length more then 128
DECLARE #xml XML;
--SET #xml=
--(
-- SELECT '170607A13' AS ID
-- ,'170607A13' AS [MaterialActual1234567890/MaterialLot1234567890]
-- ,'CreationDate' AS [MaterialActual1234567890/SomeMore1234567890/EvenMore1234567890/StillMore1234567890/MaterialActualProperty1234567890/ID1234567890]
-- ,GETDATE() AS [MaterialActual1234567890/SomeMore1234567890/EvenMore1234567890/StillMore1234567890/MaterialActualProperty1234567890/ValueString1234567890]
-- FOR XML PATH('')
--);
--SELECT #xml
--This is a solution: nested sub-select:
SET #xml=
(
SELECT '170607A13' AS ID
,'170607A13' AS [MaterialActual1234567890/MaterialLot1234567890]
,(
SELECT
'CreationDate' AS [EvenMore1234567890/StillMore1234567890/MaterialActualProperty1234567890/ID1234567890]
,GETDATE() AS [EvenMore1234567890/StillMore1234567890/MaterialActualProperty1234567890/ValueString1234567890]
FOR XML PATH('SomeMore1234567890'),TYPE
) AS [MaterialActual1234567890]
FOR XML PATH('')
);
SELECT #xml;
UPDATE 3: Your follow-up question in comment
HINT: Avoid follow-up questions. Next time please add a new question!
Both return the result requested:
SELECT 'yyyy-MM-dd''T''HH:mm:ss.SSSXXX' AS [PublishedDate/#format]
,GETDATE() AS PublishedDate
FOR XML PATH('')
SELECT 'yyyy-MM-dd''T''HH:mm:ss.SSSXXX' AS [#format]
,GETDATE() AS [*]
FOR XML PATH('PublishedDate');
In my eyes there's no need for the format. Within XML a datetime should be in this format (which is ISO8601) anyway. This is the standard format...

Execute a DELETE command whilst iterating through an XML input parameter

I have a stored procedure that receives 2 parameters.
#username VARCHAR(8),
#xmlShiftDays XML
I want to delete multiple rows from the database while iterating through the XML.
I have managed to do something similar for an INSERT (see below)
INSERT INTO table(username, date)
SELECT
username = #username,
CONVERT(DATETIME,shiftDate.date.value('.','VARCHAR(10)'),103)
FROM
#xmlShiftDays.nodes('/shiftDates/date') as shiftDate(date)
This will successfully insert "x" amount of rows into my table.
I now want to re-engineer the query to DELETE "x" amount of rows. If anyone knows how or could point me in the right direction I would greatly appreciate it.
An example of what I want to achieve is:
DECLARE #username VARCHAR(8)
DECLARE #xmlShiftDays XML
SET #xmlShiftDays = '<shiftDates><date>21/01/2012</date></shiftDates>'
SET #username = 'A0123456'
DELETE FROM table
WHERE username = #username
AND date = "<b>loop through the nodes in the XML string</b>"
Assuming you're using SQL Server 2008 (or newer) for this so I can use the DATE datatype (unfortunately, you didn't specify in your question which version of SQL Server you're using).....
I would strongly recommend you use a language-independent, regional-settings-independent date format in your XML - use the ISO-8601 format of YYYYMMDD for best results.
So try something like this:
DECLARE #xmlShiftDays XML
SET #xmlShiftDays = '<shiftDates><date>20120122</date><date>20120227</date></shiftDates>'
;WITH DatesToDelete AS
(
SELECT
DeletionDate = DT.value('(.)[1]', 'date')
FROM #XmlShiftDays.nodes('/shiftDates/date') AS SD(DT)
)
SELECT * FROM DatesToDelete
This should give you the two dates combined into XML string - right?
Now, you can use this to do the deletion from your table:
DECLARE #username VARCHAR(8)
DECLARE #xmlShiftDays XML
SET #xmlShiftDays = '<shiftDates><date>20120122</date><date>20120227</date></shiftDates>'
SET #username = 'A0123456'
;WITH DatesToDelete AS
(
SELECT
DeletionDate = DT.value('(.)[1]', 'date')
FROM #XmlShiftDays.nodes('/shiftDates/date') AS SD(DT)
)
DELETE FROM dbo.Table
WHERE username = #username
AND date IN (SELECT DeletionDate FROM DatesToDelete)
Does that work for you?
You can select the date from the Xml in the same way you did for the Insert:
DELETE FROM table
WHERE username = #username
AND date IN (SELECT
CONVERT(DATETIME,shiftDate.date.value('.','VARCHAR(10)'),103)
FROM
#xmlShiftDays.nodes('/shiftDates/date') as shiftDate(date))

ms sql xml data type convert to text

in MS Sql there are data types that are not supported by delphi 7, the xml datatype is one example.
I wish to convert the XML datatype to Text datatype, so that i could handle it in delphi.
Is there a way to convert from xml to text?
A simple cast will suffice:
select cast(XMLCol as nvarchar(max)) as XMLCol
Or for non-unicode:
select cast(XMLCol as varchar(max)) as XMLCol
You can't convert explicitly to a 'text' data type.
I've added the as XMLCol to ensure that the converted data has the the same name as the column. You needn't have this, of course.
EDIT:
A few links. You are encouraged to use nvarchar(max) instead of text regardless. Microsoft have said they will be deprecating these types in future releases. nvarchar(max) ought to offer you 2GB:
http://www.petefreitag.com/item/734.cfm
http://www.teratrax.com/articles/varchar_max.html
http://msdn.microsoft.com/en-us/library/ms187752(v=SQL.90).aspx
SELECT CAST(YourXMLColumn as nvarchar(max))
FROM YourTable
I just tried the follwing solution and yes, you do need the as XMLCol
select cast(XMLCol as nvarchar(max)) as XMLCol

Resources