How to decode nvarchar to text (SQL Server 2008 R2)? - sql-server

I have a SQL Server 2008 R2 table with nvarchar(4000) field.
Data that stores this table look like
'696D616765206D61726B65643A5472'
or
'303131' ("011").
I see that each char is encoding to hex.
How can I read those data from table? I don't want write decoding function, I mean that simpler way exists.
P.S. Sorry for my English.

SQL Server 2008 actually has a built-in hex-encoding and decoding feature!
Sample (note the third parameter with value "1" when converting your string to VarBinary):
DECLARE #ProblemString VarChar(4000) = '54657374'
SELECT Convert(VarChar, Convert(VarBinary, '0x' + #ProblemString, 1))
Ref: http://blogs.msdn.com/b/sqltips/archive/2008/07/02/converting-from-hex-string-to-varbinary-and-vice-versa.aspx
The advantage of this approach is that you don't need the "Exec" call, which you generally try to avoid, for fear of injection among other things. The disadvantage is that it only works in SQL Server 2008 and later.

You will need a decoding function I think, the simplest:
declare #fld nvarchar(4000) = '696D616765206D61726B65643A5472'
exec('SELECT CONVERT(varchar(max),0x' + #fld + ')')
---------------
image marked:Tr

Related

How to ensure specific character encoding in Microsoft SQL Server?

What I need is to ensure that a string gets encoded in a known character encoding. So far, my research and testing with MS SQL Server has revealed that the documented encoding is 'UCS-2', however the actual encoding (on the server in question) is 'UCS-2LE'.
Which doesn't seem very reliable. What I would love is an ENCODE function as found in PERL, Node, or most anything, so that regardless of upgrades or settings changes, my hash function will be working on known input.
We can limit the hashing string to HEX, so at worst, we could manually map the 16 possible input characters to the proper bytes. Anyone have a recommendation on this?
Here's the PERL I'm using:
use Digest::SHA qw/sha256/;
use Encode qw/encode/;
$seed = 'DDFF5D36-F14D-495D-BAA6-3688786D6CFA';
$string = '123456789';
$target = '57392CD6A5192B6185C5999EB23D240BB7CEFD26E377D904F6FEF262ED176F97';
$encoded = encode('UCS-2LE', $seed.$string);
$sha256 = uc(unpack("H*", sha256($encoded)));
print "$target\n$sha256\n";
Which matches MS SQL:
HASHBYTES('SHA_256', 'DDFF5D36-F14D-495D-BAA6-3688786D6CFA123456789')
But what I really want is:
HASHBYTES('SHA_256', ENCODE('UCS2-LE', 'DDFF5D36-F14D-495D-BAA6-3688786D6CFA123456789'))
So that no matter what MS SQL happens to be encoding the input string as, the HASHBYTES will always operate on a known byte array.
SQL Server uses UCS-2 only on columns, variables and literals that were declared as nvarchar. In all other cases it uses 8-bit ASCII with the encoding of the current database, unless specified otherwise (using the collate clause, for example).
So, you either have to specify a Unicode literal:
select HASHBYTES('SHA_256', N'DDFF5D36-F14D-495D-BAA6-3688786D6CFA123456789');
Or, you can use a variable or table column of the nvarchar data type:
-- Variable
declare #var nvarchar(128) = N'DDFF5D36-F14D-495D-BAA6-3688786D6CFA123456789';
select HASHBYTES('SHA_256', #var);
-- Table column
declare #t table(
Value nvarchar(128)
);
insert into #t
select #var;
select HASHBYTES('SHA_256', t.Value)
from #t t;
P.S. Of course, since Wintel is a little-endian platform, SQL Server uses the same version of the encoding as the OS / hardware. Unless something new will come out in SQL Server 2017, there is no way to get big-endian representation in this universe natively.

SQL: what's an efficient way to turn data of money type into data with dollar format?

Using SQL Server 2008, how can I display data stored as varchar(25) as money?
Sample data sets:
36839.20000
4560.00000
Desired data:
$36,839.20
$4,560.00
What SQL statement can help us to achieve the above? Thanks.
Use format if it is sql server 2012 and above
declare #cur numeric(10,2) = 8.28
select format(#cur, 'C', 'en-us') as USCurrency
Please check CONVERT() function
For your case, you may use the following code,
SELECT '$' + CONVERT(VARCHAR(25),amt,1)
FROM yourtable

SQL Server varchar(MAX) datatype in delphi using RemObjects

Got a request to change comment field max size in application. Before had it set to varchar(500), so after reading documentation i have decided to change data type of the field from varchar(500) to varchar(max). Database accepted changes without any problems (using Microsoft SQL Server Management Studio 2005 and Microsoft SQL Server Management Studio 2008 for database management).
Then i went on changing the software. Software is written in Delphi with RemObjects to communication with database. So I changed the TDASchema for the server, it mapped my new varchar(max) field as String(65536) data type (got me a little worried there about such an explicit static size, but I went on). Then I Retrieved DataTable Schema for my TDAMemDataTable object, which updated all the fields.
I started the application and decided to see whether my database will accept changes on this specific changed field. I have edited one of the records and clicked the button to synchronize the DataSet with server and got such a fail message:
The data types varchar(max) and text are incompatible in the equal to operator
I interpret it as that my server object (the one that maps database fields with RemObjects objects) have mapped field data types to wrong data types in RemObjects.
How can this be resolved? What are the alternatives?
P.S. In this release Build .1267 logs from RemObjects it clearly states that:
fixed: DataSnap: fails to post updates to MSSQL 2005 VARCHAR(MAX)
I am using build version .1067. Wonder if update will fix the problem
P.P.S. After update to the latest version of RemObjects, the problem persists.
This error message usually happens when trying to compare a varchar(n) and text using an equality operator (usually in a where clause in sql but possible elsewhere). there was an article on MSDN which covered a few points which might relate to this.
when you store data to a VARCHAR(N) column, the values are physically stored in the same way. But when you store it to a VARCHAR(MAX) column, behind the screen the data is handled as a TEXT value. So there is some additional processing needed when dealing with a VARCHAR(MAX) value. (only if the size exceeds 8000)
You mentioned that the TDASchema had mapped your new field as String(65536) which, although never having used RemObjects before, i would assume somewhere in it's own code (or yours) is trying to do a comparison of some kind hence the error message.
Try using VARCHAR(8000) instead of MAX and see if that fixes the issue.
The other option if you can find where in the code it is doing this equality check, is to try doing a cast()
As you suspected, I think the root of your problems is that the fields haven't come into the TDASchema as the correct types. I've just tried it here and varchar(max) and nvarchar(max) fields come through to my schema as Memo and WideMemo respectively, not String(65536).
I'm using Delphi XE6 and SQL Server 2008 R2 via FireDAC.
This suggests an issue retrieving the metadata from the database. What database driver are you using? Can you try FireDAC (if available) or another driver to see if the problem persists?
Resolution for Delphi 7 and MS SQL Server 2008 R2 (SP2)
Delphi:
with TADOStoredProc.Create(Self) do
try
Connection := AConnection;
ProcedureName := ASPName;
Parameters.Refresh;
Parameters.ParamByName('#XML').Value := AXML;
try
ExecProc;
...
MS SQL Server:
ALTER PROCEDURE dbo.StoredProcName
#XML NVARCHAR(MAX)
,#ErrMsgOut NVARCHAR(MAX) = NULL OUT
AS BEGIN
SET NOCOUNT ON
DECLARE #RETURN INT = 0
,#idoc INT
BEGIN TRY
-- Prepare XML
DECLARE #XML_TEXT VARCHAR(MAX)
SET #XML_TEXT = CONVERT(VARCHAR(MAX), #XML)
EXEC sp_xml_preparedocument #idoc OUTPUT, #XML_TEXT
-- Open XML
SELECT *
FROM OPENXML (#idoc, '/ServicesList/ServicesItem', 2)
WITH
(
YourFields AndTypes
)
...

sp_generate_inserts for SQL Server 2008

I've been using Narayana Vyas Kondreddi's excellent stored procedure sp_generate_inserts http://vyaskn.tripod.com/code/generate_inserts.txt in a SQL Server 2005 database.
But after moving to SQL Server 2008 I get weird results where a long whitespace is inserted after UNIQUEIDENTIFIER values:
INSERT INTO [BannerGroups]([Id], [DescriptionText], [Width], [Height])
VALUES('BFCD0173-9432-47D1-84DF-8AB3FB40BF76 ', 'Example', 145, NULL)
Anyone know how to fix this?
Appears to be this section, just over half way down:
WHEN #Data_Type IN ('uniqueidentifier')
THEN
'COALESCE('''''''' + REPLACE(CONVERT(char(255),RTRIM(' + #Column_Name + ')),'''''''','''''''''''')+'''''''',''NULL'')'
See it's converting to a CHAR(255) which means the value is being padded out to 255 characters. Change that to VARCHAR instead and it should be fine as that will not pad the values out with spaces.
Since SQL Server 2008 we can generate the INSERT scripts via Generate Script utility itself.
For more detailed answer check out - What is the best way to auto-generate INSERT statements for a SQL Server table?

SQL Server Text Datatype Maxlength = 65,535?

Software I'm working with uses a text field to store XML. From my searches online, the text datatype is supposed to hold 2^31 - 1 characters. Currently SQL Server is truncating the XML at 65,535 characters every time. I know this is caused by SQL Server, because if I add a 65,536th character to the column directly in Management Studio, it states that it will not update because characters will be truncated.
Is the max length really 65,535 or could this be because the database was designed in an earlier version of SQL Server (2000) and it's using the legacy text datatype instead of 2005's?
If this is the case, will altering the datatype to Text in SQL Server 2005 fix this issue?
that is a limitation of SSMS not of the text field, but you should use varchar(max) since text is deprecated
Here is also a quick test
create table TestLen (bla text)
insert TestLen values (replicate(convert(varchar(max),'a'), 100000))
select datalength(bla)
from TestLen
Returns 100000 for me
MSSQL 2000 should allow up to 2^31 - 1 characters (non unicode) in a text field, which is over 2 billion. Don't know what's causing this limitation but you might wanna try using varchar(max) or nvarchar(max). These store as many characters but allow also the regular string T-SQL functions (like LEN, SUBSTRING, REPLACE, RTRIM,...).
If you're able to convert the column, you might as well, since the text data type will be removed in a future version of SQL Server. See here.
The recommendation is to use varchar(MAX) or nvarchar(MAX). In your case, you could also use the XML data type, but that may tie you to certain database engines (if that's a consideration).
You should have a look at
XML Support in Microsoft SQL Server
2005
Beginning SQL Server 2005 XML
Programming
So I would rather try to use the data type appropriate for the use. Not make a datatype fit your use from a previous version.
Here's a little script I wrote for getting out all data
SELECT #data = N'huge data';
DECLARE #readSentence NVARCHAR (MAX) = N'';
DECLARE #dataLength INT = ( SELECT LEN (#data));
DECLARE #currIndex INT = 0;
WHILE #data <> #readSentence
BEGIN
DECLARE #temp NVARCHAR (MAX) = N'';
SET #temp = ( SELECT SUBSTRING (#data, #currIndex, 65535));
SELECT #temp;
SET #readSentence += #temp;
SET #currIndex += 65535;
END;

Resources