Cast rowversion to bigint - sql-server

In my C# program I don't want to work with byte array, therefore I cast rowversion data type to bigint:
SELECT CAST([version] AS BIGINT) FROM [dbo].[mytable]
So I receive a number instead of byte array. Is this conversion always successful and are there any possible problems with it? If so, in which data type should I cast rowversion instead?

rowversion and bigint both take 8 bytes so casting seems possible. However, the difference is that bigint is a signed integer, while rowversion is not.
This is a max value of rowversion that will cast properly to max positive bigint number (9223372036854775807):
select cast(0x7FFFFFFFFFFFFFFF as bigint)
But starting from here, you'll be getting negative numbers:
select cast(0x8000000000000000 as bigint)
I didn't check if the latter cast throws an error in C#.
You problably won't reach more than 9223372036854775807 rows in your table, but still it's something you should know about, and I personally wouldn't recommend doing this unless you are certain that this problem will never occur in your solution.

You can convert in C# also, but if you want to compare them you should be aware that rowversion is apparently stored big-endian, so you need to do something like:
byte[] timestampByteArray = ... // from datareader/linq2sql etc...
var timestampInt = BitConverter.ToInt64(timestampByteArray, 0);
timestampInt = IPAddress.NetworkToHostOrder(timestampInt);
It'd probably be more correct to convert it as ToUInt64, but then you'd have to write your own endian conversion as there's no overload on NetworkToHostOrder that takes uint64. Or just borrow one from Jon Skeet (search page for 'endian').

Related

How to insert a 12 digit number into the databaase

I am using ASP.NET MVC and SQL Server and I want to store a 12 digit value which is 221133556677.
This is where I wanted to store the value in, So Int36 can only store up to 10 digit.
So how can I change the data type into numeric(12,0) in order to store the 12 digit value.
[Display(Name = "IC")]
[Required(AllowEmptyStrings = false, ErrorMessage = "IC is required")]
public int IC { get; set; }
So Int36 can only store up to 10 digit.
In all computers in the world htat follow standard architecture, there IS NO SUCH THING AS INT36. Bytes are 8 bits, so it is 32. Not 36.
And since ages, Int64 is a thing too. Which has MUCH MUCH larger scale.
In SQL Server it is named BIGINT and has a scale that may surprise you:
2^63 (-9,223,372,036,854,775,808) to 2^63-1 (9,223,372,036,854,775,807)
Case closed?
Oh, no....
So how can I change the data type into numeric(12,0) in order to store the 12 digit
value.
Just Do It? Let's start with your C# side code using int - not long. Int is 32 bit (not 26). Just change it to - oh, you insist on using numeric (decimal)? Ah, use Decimal not int. Done. Otherwise I would go with a long and bigint on the database.
Note, though, that this "number" is likely NOT A NUMBER. It is a numeric string. Storing it as number makes little sense if you may need one day to do partial searches and never will use stuff like average, sum etc.
Now, you may want to read some documentation:
https://learn.microsoft.com/en-us/sql/t-sql/data-types/int-bigint-smallint-and-tinyint-transact-sql?view=sql-server-ver15
has all SQL Server data types. This helps you not to ignore the obvious larger scale data type.
According to the SQL Server documentation you can use BIGINT.
Its a signed 64 bit int and has a range of -2^63 (-9,223,372,036,854,775,808) to 2^63-1 (9,223,372,036,854,775,807).
https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/sql-server-data-type-mappings
From what I have been able to find specifying the size of the numeric doesn't effect the size of the number it can store in SQL Server and only affects when ZEROFILL is used
What is the size of column of int(11) in mysql in bytes?
A long can store 12 digits just fine. So use long instead of int in your C#.
long twelveDigits = 221133556677;
Console.WriteLine($"\nHere is twelve digit number, {twelveDigits}.");
Console.Write("\nPress any key to exit...");
Console.ReadKey(true);
See here: Long data type MSDocs
And SQLServer has the Data Type bigint
See here: int, bigint, smallint, and tinyint (Transact-SQL)
and: www.sqlservertutorial.net
These should get you taken care of.

Arithmetic overflow error for type int, value = 4957500001.400178

I know that similar questions have been asked again in the past, but I think my case is slightly different. I have a column which has Logarithmic values and I'm trying to invert them using the following formula:
SELECT POWER(10,CAST(9.695262723 AS NUMERIC(30,15)))
Let's say the value 9.695262723 is one of the values of that column.
When trying to run this query I get an Arithmetic overflow error for type int, value = 4957500001.400178.
On the other hand, the same query works fine for smaller values e.g. SELECT POWER(10,CAST(8.662644523 AS NUMERIC(30,15)))
How could I overcome that error and calculate the inverse values of the log10 entries I have? Just for information the greater value that exists in the table (in log10 scale) is 12.27256096.
The problem here is your first input parameter (10) which SQL server will, by default, treat as the datatype int.int has a maximum value of 2^31-1 (2,147,483,647), and the number 4,957,500,001 is far larger than this, so you need to use a bigint:
SELECT POWER(CONVERT(bigint,10),CONVERT(numeric(30,15),9.695262723));
Edit: If you need to retain the decimal places, then use a numeric with a large enough scale and precision, instead of bigint.

Microsoft T-SQL: Can I CONVERT smallint to varchar

It may just be me, but... Despite the fact that most sql developers may consider cast & convert to be very basic stuff, and that may be true, I find Microsoft's documentation page on CAST & CONVERT to be one of the most hideous, not-intuitively-laid-out, hard to understand things I have ever seen. Much of their documentation is great. Like constantly trying to blend the entire page into a mix of both cast and convert, jumping back and forth in each sentence... rather than dealing with them separately. And who puts the target_type as the first argument? Putting the expression as the first argument would be more intuitive - and follow the other 99% of numerous programming languages' syntax. UH
MS says that I can only convert to 3 data types: (well actually I'm not really sure if this applies to both CAST and CONVERT, since they ARE, in fact, different... But according to the layout of that webpage, it apparently applies equally to both - even though I already know for a fact that it is not true for CAST, which I use much more frequently).
It says: "Is the target data type. This includes xml, bigint, and sql_variant"
Putting aside for the moment the fact that I CAST things as many other datatypes all the time (date, varchar),
My immediate question is: if I can only CONVERT to those data types, then why does this work?
select CONVERT(varchar(200), cast(50 as smallint))
And finally, I'd like to run an INSERT that will be getting a smallint and putting it into a varchar(200) column.
All I'm trying to do is avoid any failures, so maybe I don't really "need" to convert or cast over to varchar, but any commments on
answer on what is my apparent misunderstanding about the CONVERT documentation
or
how to safely convert it to insert to varchar
are welcome. As long as you're not just overly unpleasant, since there are always those MS fans who get hot under the collar at all critiques of MS .. :|
Yes, you can convert from smallint to varchar.
1) answer on what is my apparent misunderstanding about the CONVERT
documentation
This may be product of general lack of understanding on what data types are, how can they be converted from one type to another and equally important; what styles are when it comes to the aesthetic representation of a data type.
CAST is an explicit cast operation with no style options.
CONVERT is also an explicit cast that gives you the ability to specify a style for the output.
The documentation clearly states:
Implicit Conversions
Implicit conversions are those conversions that occur without
specifying either the CAST or CONVERT function. Explicit conversions
are those conversions that require the CAST or CONVERT function to be
specified. The following illustration shows all explicit and implicit
data type conversions that are allowed for SQL Server system-supplied
data types. These include xml, bigint, and sql_variant. There is no
implicit conversion on assignment from the sql_variant data type, but
there is implicit conversion to sql_variant.
For your second question
2) how to safely convert it to insert to varchar
Depending of what you mean by safe. Converting to varchar is the convertion that most likely succeed. But whenever to cast to any toher datatype you are intrinsically changing the very nature of the data and will lose precision when casting to smaller types (or applying styles).
The documentation clearly states:
Truncating and Rounding Results
When you convert character or binary expressions (char, nchar,
nvarchar, varchar, binary, or varbinary) to an expression of a
different data type, data can be truncated, only partially displayed,
or an error is returned because the result is too short to display.
Conversions to char, varchar, nchar, nvarchar, binary, and varbinary
are truncated, except for the conversions shown in the following
table.
in other words, casting is never safe.
Numbers always get silently truncated for me. I would propose:
Option 1
Compare the converted value with the original value.
DECLARE #ORIGINAL DECIMAL(13,2) = -99999999999.99 --
DECLARE #EXPECTED VARCHAR(15) = ''
SELECT #EXPECTED = CONVERT(VARCHAR(15),#ORIGINAL)
IF CONVERT(DECIMAL(13,2),#EXPECTED) != #ORIGINAL SELECT 'Ooops'
Option 2
Make sure that all possible values will fit in target varchar.
Decimal(13,2). Widest number possible will be "-99999999999.99" needs varchar(15):
13 chars for digits
1 char for decimal separator
1 char for minus sign
Smallint stores 2 bytes, from "-32768" to "32767", needs varchar(6):
- 5 chars for digits
- 1 char for minus sign
Not sure if you need chars for thousands separators, or if you can change it via settings.

Create Unique Number from Two Values; Bit Shifting?

I have a table with IDs and locales. The same ID can be listed more than once with a different locale:
ID Locale
123456 EN_US
234567 EN_US
234567 EN_CA
345678 EN_US
I need to create an unique identifier in the form of an numeric ID (Integer) for each record, while maintaining the ability to reverse engineer the original components.
I was thinking bit shifting might work: assign a numerical value to each locale, but I'm not quite sure how to implement. Has anyone faced this challenge before? Also, I have 75 locales so I'm not sure if that would be an issue with bit shifting.
Lastly, I'm using SQL Server with a Linked Server connection to Teradata (that's my data source). I don't think Teradata supports bitwise out-of-the-box so I'm assuming I'll have to do it in MSSQL.
Thank you.
You can create a composite numeric key, mapping your 75 unique values into the last 2 digits of the numeric key. You can parse into components with simple modulus 100 arithmetic or just a substring. If you will ever exceed 100 values, use 3 digits instead. 9 digits total will fit int an int, 10-18 will fit in a bigint.
Converting 234567-EN_US into an integer is easy. Just use CHECKSUM on the concatenated string value. It would not be reversible, however.
You could store this CHECKSUM value on the original table, however, and then use it to backtrack from whatever table you're going to store the integer in.
Another solution would be to assign each locale an Integer value (as Marc B suggested). Call that X. Then call your existing integer ID (234567) as Y. Your final key would be (X * 1,000,000) + Y. You could then reverse the formula to get the values back. This would only work, of course, if your existing integer IDs are well below 1,000,000, and also if your final integer can be a BigInt.

Best way to store UInt32 in Sql Server

I'm working on an application that uses a third-party component, and this component returns a value that is of type UInt32.
I need to store this UInt32 in a Sql Server table. I was thinking about just use a simple int column and insert the value like this:
int value = (int)(cs - int.MaxValue);
But I'm not sure if this is the best way for such task.
Use a bigint or decimal(10,0) column and defined a check constraint to ensure it's between 0 and 4 billion.
Defines a CLR datatype
I suggest you store it in a bigint column.
You should probably take + int.MinValue. As max is 2147483647 and min is -2147483648 for 32 bit signed integer. The zero steals one value from the positive side.

Resources