varChar and Char behave different on cast - sql-server

Why the output is different of this query
SELECT DATALENGTH(CAST('test' AS VARCHAR)), DATALENGTH(CAST('test' AS CHAR))
outPut:
4,30

VarChar always adjusts to the length of the string passed. hence the output is 4.
CHAR has default length of 30 and hence the output is 30.

Because "When n is not specified when using the CAST and CONVERT functions, the default length is 30". But when DataLength is applied to a varchar field, it ignores trailing spaces, while for a char field the length is just the size of the field itself.

Related

Do we need to remove some charaters from SUBSTRING length if start is not from 0?

I came across this sentence and thing what the difference between
DECLARE #MyStr nvarchar(max) = 'This is a sentence'
SELECT SUBSTRING(#MyStr, 6, LEN(#MyStr)**-5**)
and
DECLARE #MyStr nvarchar(max) = 'This is a sentence'
SELECT SUBSTRING(#MyStr, 6, LEN(#MyStr))
I ran both and the latter doesn't add any spaces or anything.
The third parameter to SUBSTRING is the length of substring to take. In the first example, the length covers exactly the remainder of the string. In the second example, the length exceeds the actual available length of the string, by 5 characters. Regarding what happens when the length is greater than the available length, we can turn to the documentation for SUBSTRING:
length
Is a positive integer or bigint expression that specifies how many characters of the expression will be returned. If length is negative, an error is generated and the statement is terminated. If the sum of start and length is greater than the number of characters in expression, the whole value expression beginning at start is returned.
In other words, if the length parameter plus the start passed is greater than what is available, then SUBSTRING just returns as much as is available.

Sql: Casting INT to string

TableA
OFIPS int null,
DFIPS int null
Query below returns a record.
SELECT OFIPS from TableA Where OFIPS = 01077
But this query doesn't.
SELECT OFIPS from TableA Where CAST(OFIPS as nvarchar(5)) = '01077'
Not sure what the problem is. Please help.
Because in int column leading zero's will be ignored, 01077 will be stored as 1077 and when you query like
Where OFIPS = 01077
It will be parsed as
Where OFIPS = 1077
There will be a record stored as 1077 so you are getting result.
But when you query like
Where CAST(OFIPS as nvarchar(5)) = '01077'
It checks for the records with 01077 thats why you are not getting result in second query
Interestingly if you remove the CAST in Where clause again it will work. Even though you query with leading zero in string format.
Where OFIPS = '01077'
Because LHS OFIPS has INT datatype which has higher precedense than the RHS Varchar. Implicitly string in the RHS(01077) will be converted to int 1077
Implicit Conversion
When an operator combines two expressions of different data types, the rules for data type precedence specify that the data type with the lower precedence is converted to the data type with the higher precedence.
https://learn.microsoft.com/en-us/sql/t-sql/data-types/data-type-precedence-transact-sql
Meaning, that '01234' = 1234 will result to TRUE, since '01234' will be converted to INT. INT has a higher precdence.
Explicit conversion
Converting INT to VARCHAR - like CONVERT(VARCHAR(5), 1234) - will not add leading zeros therefore '01234' not equals to CONVERT(VARCHAR(5), 1234).
You can forcibly add the leading zeros if you have a fixed length: RIGHT(CONCAT('00000', CONVERT(CHAR(5), 1234)), 5)
Remarks
Consider to keep the INT-INT comparison, force convert the input values to INT instead of converting the column values.
If the above is not possible, consider to store the values in the database as fixed length character values (CHAR(5)) and make sure, that the INSERT and UPDATE statements are transforming the values to their desired format.
Your column is int and the only int that can have a leading 0 is 0.
Other numbers have no leading 0 because they are not strings but numbers.
When you search for Where OFIPS = 01077 01077 is implicitly converted to 1077,
and this number exists in your table.
When you do CAST(OFIPS as nvarchar(5)) no leading 0 can appear so no one number will be casted to '01077'
You can use this because OFIPS of type is int. Int type is not '01077'. I hope that it help you.
SELECT OFIPS from TableA Where CAST(OFIPS as nvarchar(5)) = '1077'

What exactly is the meaning of nvarchar(n)

The documentation isn't super clear: https://msdn.microsoft.com/en-us/library/ms186939.aspx
What happens if I try to store a 20 character length string in a column defined as nvarchar(10)? Is 10 the max length the field could be or is it the expected length? If I can exceed n characters in the string, what are the performance implications of doing that?
The maximum number of characters you can store in a column or variable typed as nvarchar(n) is n. If you try to store more your string will be truncated, or in case of an insert into a table, the insert would be disallowed with a warning about possible truncation:
String or binary data would be truncated. The statement has been
terminated.
declare #n nvarchar(10)
set #n = N'more than ten chars'
select #n
Result:
----------
more than
(1 row(s) affected)
From my understanding, nvarchar will only only store the provided characters up to the amount defined. Nchar will actually fill in the unused characters with whitespace.

SQL server Varchar(max) and space taken

If varchar(max) is used as the datatype and the inserted data is less than the full allocation, i.e. only 200 chars, then will SQL Server always take the full space of varchar(max) or just the 200 chars' space?
Further, what are the other data types that will take the max space even if lesser data is inserted?
Are there any documents that specify this?
From MS DOCS on char and varchar (Transact-SQL):
char [ ( n ) ]
Fixed-length, non-Unicode string data. n defines the string length and must be a value from 1 through 8,000. The storage size is n bytes. The ISO synonym for char is character.
varchar [ ( n | max ) ]
Variable-length, non-Unicode string data. n defines the string length and can be a value from 1 through 8,000. max indicates that the maximum storage size is 2^31-1 bytes (2 GB). The storage size is the actual length of the data entered + 2 bytes. The ISO synonyms for varchar are char varying or character varying.
So for varchar, including max - the storage will depend on actual data length, while char is always fixed size even when entire space is not used.
Use CHAR only for strings
whose length you know to be fixed. For example, if you define a domain
whose values are restricted to 'T' and 'F', you should probably make
that CHAR[1]. If you're storing US social security numbers, make the
domain CHAR[9] (or CHAR[11] if you want punctuation).
Use VARCHAR for strings that can vary in length, like names, short
descriptions, etc. Use VARCHAR when you don't want to worry about
stripping trailing blanks. Use VARCHAR unless there's a good reason
not to.
varchar size depends on the length of the data. So in your case, it will just take 200 chars.

PQgetvalue real field size

I'm reading info from a pqsql database (and changed my engine from mysql)
there is something weird in the string data returned,
if the field length in the db is 50 chars the returned value has 50 chars length, so
even if the value in the db is inserted with fewer elements the returned value size is 50.
in mysql the returned value size was the same as it was inserted in the db.
example
create table values(data char(50))
insert into table values('info');
when i pick up this data with PQgetvalue
res=PQexec(conn,"select * from values");
printf(" the value has the lenght of %d chars",strlen(PQgetvalue(res,0,0)));
it will display
the value has the lenght of 50
im kinda surprised of this because now i need to store o calculate in some way the real size of the field, no the max field size
I'm doing something wrong?
(sorry for the typos)
The field is declared as char, not varchar. A char field's value will always have the declared length, probably after padding the value from the right with spaces. From your description, I'd consider changing it to varchar.
See http://www.postgresql.org/docs/8.2/static/datatype-character.html

Resources