Varbinary and image conversion - sql

I have an Access front end that links to a SQL Server backend.
There are 3 fields in a table that I am trying to convert to text from the backend:
o_name varbinary(2000)
O_PropertyBinary1 varbinary(2000)
O_PropertyBinary2 image
I can convert the o_name field using:
convert(varchar([max]),[O_Name])
and that works fine.
e.g. 4153534554 = ASSET
However, what can I use for the other two fields, as it seems I can't convert an image field and converting the O_PropertyBinary1 comes out with garbage characters.

The output is depended on the stored data an the appropriate conversion.
If the stored data is binary e.g. Bitmaps, converting to text will never give a usable result.
If data stored is text, it could be Varchar or NVarchar and kind conversion is depending.
in the example below VC_VB2NVarchar and VC_IMG2NVarchar would display your described garbage characters
Declare #tab Table(nvc NVarchar(100),vc Varchar(100)
,img image,vb VarBinary(200),img2 image,vb2 VarBinary(200))
Insert into #tab (nvc,vc) Values ('123456789','123456789')
Update #tab set vb=Convert(VarBinary(200),nvc),img=Convert(Image,Convert(Varbinary(max),nvc))
,vb2=Convert(VarBinary(200),vc),img2=Convert(Image,Convert(Varbinary(max),vc))
Select nvc,vc
,CONVERT(Nvarchar(100),vb) as NVC_VB2NVarchar
,CONVERT(Varchar(200),vb) as NVC_VB2Varchar
,CONVERT(Nvarchar(100),Convert(VarBinary(max),img)) as NVC_IMG2NVarchar
,CONVERT(Varchar(200),Convert(VarBinary(max),img)) as NVC_IMG2Varchar
,CONVERT(Nvarchar(100),vb2) as VC_VB2NVarchar
,CONVERT(Varchar(200),vb2) as VC_VB2Varchar
,CONVERT(Nvarchar(100),Convert(VarBinary(max),img2)) as VC_IMG2NVarchar
,CONVERT(Varchar(200),Convert(VarBinary(max),img2)) as VC_IMG2Varchar
from #Tab

Related

Encrypting and Decrypting String Using SQL's EncryptByPassPhrase

I have a need to Encrypt text, transmit the encrypted text, and decrypt the text ... using SQL.
I tried EncryptByPassPhrase which returns a VARBINARY. I convert it to VARCHAR (for easier transmitting), and when I try to convert it back to VARBINARY, it fails. From what I can see, the CONVERT from VarBinary to VarChar, truncates the string, appears like the second half of the VarBinary value gets dropped when converting to VarChar. So when converting back from that VarChar value, it is incomplete and fails.
Here is sample code:
DECLARE #binEncryptedText VARBINARY(MAX) = EncryptByPassPhrase('Password', 'My Text')
DECLARE #strEncryptedText VARCHAR(MAX) = CONVERT(VARCHAR, #binEncryptedText, 2)
DECLARE #binDecryptedText VARBINARY(MAX) = CONVERT(VARBINARY, #strEncryptedText, 2)
DECLARE #strDecryptedText VARCHAR(MAX) = CONVERT(VARCHAR, DecryptByPassPhrase('Password', #binDecryptedText))
SELECT 1 As RowNumber,
#binEncryptedText AS EncryptedBinary,
#strEncryptedText AS EncryptedBinaryAsText
UNION
SELECT 2 As RowNumber,
#binDecryptedText AS EncryptedBinary,
#strDecryptedText AS EncryptedBinaryAsText
As you can see in the screenshot of my results above... In Row #1, the Binary that was converted to Text ... is shorter than the original Binary (truncated roughly halfway). So when converting that truncated text back to Binary, it fails to return the complete value ... which then causes the Decrypt to fail.
How can I get the encrypted text's VarBinary converted to "text" and then have the "text" converted back to the correct VarBinary value so it can be decrypted?
MSSQL has a well hidden Base64 encoder and decoder - within the XML subsystem. Convert the encrypted varbinary to Base64 for transmission, it will become an ASCII string, transmit the string, then decode back to a varbinary. The encoder/decoder is an XPath function, so you need an XML context to run it, but you can provide a dummy one. So the code for encoding goes:
cast('' as xml).value('xs:base64Binary(sql:variable("#b"))', 'varchar(max)')
where #b is your varbinary.
To decode:
cast('' as xml).value('xs:base64Binary(sql:variable("#s"))', 'varbinary(max)')
where #s is the Base64 string.
It's kind of funky that the encoder and the decoder is the same function, but I guess it knows what to do by the datatype of the argument. I haven't used this technique extensively myself, but I've tried it and it worked as expected. MSSQL 2019.
You can also use xs:hexBinary to encode the binary data as hex. Base64 representation is smaller, though; 4 characters for 3 bytes vs. 2 for 1.
So I actually ended up figuring out what my problem was. In SQL, some of my commands were "incomplete" ... in a manner of speaking.
DECLARE #binEncryptedText VARBINARY(MAX) = EncryptByPassPhrase('Password', 'My Text')
DECLARE #strEncryptedText VARCHAR(MAX) = CONVERT(VARCHAR(MAX), #binEncryptedText, 2)
DECLARE #binDecryptedText VARBINARY(MAX) = CONVERT(VARBINARY(MAX), #strEncryptedText, 2)
DECLARE #strDecryptedText VARCHAR(MAX) = CONVERT(VARCHAR(MAX), DecryptByPassPhrase('Password', #binDecryptedText))
SELECT 1 As RowNumber,
#binEncryptedText AS EncryptedBinary,
#strEncryptedText AS EncryptedBinaryAsText
UNION
SELECT 2 As RowNumber,
#binDecryptedText AS EncryptedBinary,
#strDecryptedText AS EncryptedBinaryAsText
As you can see in the code above, in the CONVERT statements ... I needed to add the additional "size" of the returning VARCHAR I was converting to. Previously my convert commands said ...
...CONVERT(VARCHAR, ...
... when they should have said ...
...CONVERT(VARCHAR(MAX), ...
Once I made that change, the returning HEX String was no longer being truncated.

How can I get rid of having to prefix a WHERE query with 'N' for Unicode strings?

When searching for a string in our database where the column is of type nvarchar, specifying the 'N' prefix in the query nets some results. Leaving it out does not. I am trying the search for a Simplified Chinese string in a database that previously did not store any Chinese strings yet.
The EntityFramework application that uses the database, correctly retrieves the strings and the LINQ queries also work in the application. However, in SQL Server 2014 Management Studio, when I do a an SQL query for the string it does not show up unless I specify the 'N' prefix for unicode. (Even though the column is nvarchar type)
Works:
var text = from asd in Translations.TranslationStrings
where asd.Text == "嗄法吖无上几"
select asd;
MessageBox.Show(text.FirstOrDefault().Text);
Does not work:
SELECT *
FROM TranslationStrings
where Text = '嗄法吖无上几'
If I prefix the Chinese characters with 'N' it works.
Works:
SELECT *
FROM TranslationStrings
where Text = N'嗄法吖无上几'
Please excuse the Chinese characters, I just typed something random. My question is, is there something I can do to not have to include the 'N' prefix when doing a query?
Thank you very much!
As #sworkalot has mentioned below:
The default for .Net is Unicode, that's why you don't need to specify
it. This is not the case for Sql Manager.
If not specified Sql will assume that you work with asci according to
the collation specified in your DB.
Hence, when working from Sql Server you need to use N'
https://sqlquantumleap.com/2018/09/28/native-utf-8-support-in-sql-server-2019-savior-false-prophet-or-both/
Check out these examples, pay close attention to the data types and the values being assigned:
DECLARE #Varchar VARCHAR(100) = '嗄'
DECLARE #VarcharWithN VARCHAR(100) = N'嗄' -- Has N prefix
DECLARE #NVarchar NVARCHAR(100) = '嗄'
DECLARE #NVarcharWithN NVARCHAR(100) = N'嗄' -- Has N prefix
SELECT
Varchar = #Varchar,
VarcharWithN = #VarcharWithN,
NVarchar = #NVarchar,
NVarcharWithN = #NVarcharWithN
SELECT
Varchar = CONVERT(VARBINARY, #Varchar),
VarcharWithN = CONVERT(VARBINARY, #VarcharWithN),
NVarchar = CONVERT(VARBINARY, #NVarchar),
NVarcharWithN = CONVERT(VARBINARY, #NVarcharWithN)
Results:
Varchar VarcharWithN NVarchar NVarcharWithN
? ? ? 嗄
Varchar VarcharWithN NVarchar NVarcharWithN
0x3F 0x3F 0x3F00 0xC455
NVARCHAR data type stores 2 bytes for each character while VARCHAR only stores 1 (you can see this on the VARBINARY cast on the 2nd SELECT). Since chinese characters representation need 2 bytes to be stored, you have to use NVARCHAR to store them. If you try to stuff them in a VARCHAR it will be stored as ? and you will lose the original character information. This also happens on the 3rd example, because the literal doesn't have the N so it's converted to VARCHAR before actually assigning the value to the variable.
It's because of this that you need to add the N prefix when typing these characters as literals, so the SQL engine knows that you are typing characters that need 2 byte representation. So if you are doing a comparison against a NVARCHAR column always add the N prefix. You can change the database collation, but it's recommended to always use the proper data type independent of the collation so you don't have problems when using coding on different databases.
If you could explain the reason why you want to omit the N prefix we might address that, although I believe there is no work around in this particular case.
The default for .Net is Unicode, that's why you don't need to specify it.
This is not the case for Sql Manager.
If not specified Sql will assume that you work with asci according to the collation specified in your DB.
Hence, when working from Sql Server you need to use N'
https://sqlquantumleap.com/2018/09/28/native-utf-8-support-in-sql-server-2019-savior-false-prophet-or-both/

Conversion failed when converting the nvarchar value 'AAAR78509883' to data type int

I have a nvarchar column in one of my tables that I have imported from Access. I am trying to change to an int. To move to a new table.
The original query:
insert into members_exams_answer
select
ua.members_exams_id, ua.exams_questions_id,
ua.members_exams_answers_value, ua.members_exams_answers_timestamp
from
members_exams as me
full join
UserAnswers1 as ua on me.members_exams_username = ua.members_exams_id
full join
exams_questions as eq on eq.exams_questions_id = ua.exams_questions_id
This throws an error:
Conversion failed when converting the nvarchar value 'AAAR78509883' to data type int.
I have tired:
select convert (int, UserAnswers1.members_exams_id)
from UserAnswers1
and
select cast(members_exams_id as integer) int_members_exams_id
from UserAnswers1
and
select cast (members_exams_id as int)
from UserAnswers1
All result in the same error
Conversion failed when converting the nvarchar value 'AAAR78509883' to data type int.
Clearly you are trying to convert data that is alphanumeric to an int and that cannot be done.
Looking at your data why are you insisting on converting it to an int when it cannot be an int? Why not just process it as an nvarchar?
Your problem could be systemic where all data has a leading alpha characters that you need to strip out (and hopefully the same number of alpha characters)
In that case use a substring to strip off the alphas (this assumes the name number of alphabetic characters in each record). Or use a varchar or nvarchar field instead of an int. If the number of leading characters varies or if they can be leading or trailing or some other combination, it will much more complex to fix than we can probably describe on the Internet.
The other possibility is that you simply have some bad data. In which case identify the records which are not numeric and fix them or null the value out if they cannot be fixed. This happens frequently when you have stored the data in an incorrect datatype.

How to Perform a Replace on Varbinary data in SQL

I've never had to do this before but I'm looking to do a SQL replace on varbinary data. I'm trying this but it's not successfully replacing, I think because it's treating the data as varchar and then cast back to varbinary. This stemmed from blank spaces at the end of these values but are not actual 'spaces' so RTRIM doesn't work in this scenario (bold below).
Example of Data trying to change:
0x457874656368203430304120414320636C616D70206D657465722C2041432063757272656E74206D6F64656C20746F206D65657420796F7572206170706C69636174696F6E206E656564732E20203230303020636F756E74204C434420646973706C61792E20204869676820616363757261637920666F722063757272656E74206D6561737572656D656E74732E2020302E3922202832336D6D29206A61772073697A65206163636F6D6D6F646174657320636F6E647563746F727320757020746F203330304D434D2E2020436F6E74696E756974792062656570657220616E642064696F646520746573742E20204461746120686F6C6420616E64206D617820686F6C642E20204F7665726C6F61642070726F74656374696F6E20666F7220616C6C2072616E6765732E20204F76657272616E676520616E64206C6F77206261747465727920696E64696361746F72732E20204175746F72616E67696E672077697468206175746F20706F776572206F66662E0D0A090909090909090909090D0A090909090909090909090D0A090909090909090909090D0A09090909090909090909
Script:
update digitalassetcontent
set content = (CAST(REPLACE(content, '0D0A09090909090909090909', '') as varbinary(MAX)))
update digitalassetcontent
set content = REPLACE(content,0x0D0A09090909090909090909,0x)

Display hindi data store in nvarchar datatype without N prefix

SQL Server 2008 - Table contains nvarchar(max) datatype and store hindi & english data without N' prefix. like - "मांगलिक welcome" but in table store as "×梻çÜ·¤ welcome".
Please guide how to display the data from SQL server in .net.
The N prefix only denotes the string is NVARCHAR as opposed to VARCHAR
See this for more info
C# is Unicode by default so your data will be ok.
In fact re-reading your question I'm not sure what you are asking.
Are you saying you store the data in the database WITHOUT the N prefix ? Is this done via .net ?
Can you please make your question clearer ?
** EDIT
I'm not sure you can. The data outside of the non Unicode code page will be lost.
Check this page here for further details
First try to create a table as shown:
Create table TestLang (strText nvarchar(max))
Next try to insert values
insert into TestLang values ( N'मांगलिक')
insert into TestLang values ( N'Welcome')
Now try to search the name as shown:
SELECT * FROM TestLang WHERE strText LIKE N'मां%'
UPDATE:
If you want to display the data try this way:
string input = "0928;0940;0932;092E;";
Regex rx = new Regex(#"([0-9A-Fa-f]{4});");
string output = rx.Replace(input, match => ((char)Int32.Parse(match.Groups[1].Value, NumberStyles.HexNumber)).ToString());
Output: "नीलम"
Took from here