Postive Integers and Unsigned in SQL Server 2012 - sql-server

I have read that SQL Server has the ability to create an unsigned integer column and I also read that SQL Server does not allow creation of integer unsigned column. So I'm confused as to which is actually correct.
I need to create a new column in my table called QuantityonHand. This column should be an integer of 5 characters and only accept positive numbers.
So do I create the column as;
(1) QuantityonHand [unsigned] int (5) which means the number can only be positive OR
(2) QuantityonHand int (5) default 0 - which means the number cannot be less than zero, the default 0 being the condition in the column.
I am leaning towards the second one, but I was hoping to get some guidance before I add the column and mess up my table.
Thanks everyone
Josie

There are no unsigned data types, but you can use a check constraint to allow only certain range of values. You can find information for example from here.

First of all there is no UNSIGNED version of INT see: UNSIGNED INTEGER Data Type
I need to create a new column in my table called QuantityonHand. This
column should be an integer of 5 characters and only accept positive
numbers.
Use standard INT and add CHECK constraint.
QuantityonHand INT CHECK (QuantityonHand >= 0 AND QuantityonHand <= 99999)
LiveDemo

Related

Generate integer number 1,2,3 in SQL Server

I used this query:
SELECT FLOOR(3 * RAND(CONVERT(varbinary, NEWID())))
Can someone please explain how it works? I know all the functions used, but I'm unable to link them.
Tne newid() function doesn't actually generate a string, it generates a uniqueidentifier, also known as a "globally unique identifier", or "GUID". This is a pseudo-random value.
The rand(#seed) function generates a value >= 0 and < 1.
Rand doesn't generate a seed, it accepts the seed as an input parameter. The result depends on the seed. If you pass the same seed value as the input parameter, the result of rand() is always the same. If rand() is called without any seed value, SQL server itself will produce a psuedo-random seed.
Now, this probably seems confusing already. Obvious questions are:
If newid() is already pseudo-random, why do we need rand()?
In the code presented in your question, rand() isn't actually being used to generate random values, that job is really being done by newid(). What rand() is doing is mapping the newid() value to a floating point value between zero and one.
OK then, if rand() with no input seed is already psuedo-random, why do we need newid()??
In the specific sample code in your question, where we are only working with a single scalar value, there's actually no need. The same thing could be accomplished with:
select floor(3 * RAND() + 1)
However, when you are working with multiple rows of data, rand() doesn't get re-seeded by SQL Server for every row, it only gets seeded once. So if you do something like this:
select rand() from sys.objects
Then every row in the result set will have the same value.
The newid() function is different. SQL will generate a different uniqueidentifier for every single row (it sort of "has to by law" - part of the definition of a GUID is that the same GUID should never be generated twice).
So the newid() function is providing a psuedo-random seed value to rand(), and then rand() is mapping that to some floating point value between 0 and 1 (excluding 1).
What is the convert to varbinary doing?
If an argument is passed to rand(), the argument has to be an integer. A uniqueidentifier cannot be implicitly converted to an integer. But a uniqueidentifier can be converted to a varbinary, and then the varbinary can be implicitly converted to an integer. If we make that conversion explicit, it looks like this:
select convert(int, convert(varbinary, newid()))
In your sample code, the integer conversion is being done implicitly. A uniqueidentifier is 16 bytes long, so it gets converted to a 16 byte varbinary. 12 of those bytes then get silently truncated (thrown away), because an integer is only 4 bytes long. The remaining 4 bytes are implicitly converted to the integer.
Note that this truncation could theoretically weaken the randomness of the result. People often use checksum() to convert to an integer rather than casting through a varbinary, because checksum will make use of all of the bytes in the GUID.
what is the multiplication by 3 doing?
Since the rand() function returns a value between 0 and 1, but you want a value "between" 1 and 3, we have to multiply the result of rand():
Values >= 0 and < 1/3 will map to values >= 0 and < 1.
Values >= 1/3 and < 2/3 will map to values >= 1 and < 2.
Values >= 2/3 and < 1 will map to values >= 2 and < 3.
What is floor() doing?
The value we have right now is some floating point value anywhere between 0 and 3 (excluding 3). But you want only the integer values 1 or 2 or 3. So we have to add 1 and shave off the decimal. This is what the + 1 and floor() are doing. You could also get rid of the + 1 and replace floor() with ceiling().
I used this query:
select floor(3 * RAND(convert(varbinary, newid())))+1
RAND() : returns some seed decimal number like 0.405615055347678
newid(): returns some string: 29CADAD4-F9F5-4B79-98F0-33DE745954FC
varbinary : converting data from a string data type to a binary or varbinary data type of unequal length :
eg:
select convert(varbinary, newid())
output:
0x321A7CBE6FBACC41B1EE5BC3C5219B2C
We can generate a random number, using the NEWID() function of SQL
Server. Random number generated by NEWID() method will be a 32 byte
Hexadecimal number, which is unique for your whole system.
The unique identifier generated by the NEWID() can be converted to
VARBINARY using CONVERT() which in turn can be converted to an integer
number USING FLOOR().
select rand()-result will be a random decimal
The FLOOR() function returns the largest integer value that is smaller
than or equal to a number.
select floor(rand()*N) —The generated number is like this: 12.0
The number range of method: 0 to n-1, such as cast (floor (rand() *100)
will generate any integer between 0 and 99.So here our N=3 ... we
will be generating an integer between 0 and 3.
SO, the link is NEWID()>CONVERT()>RAND()>FLOOR>SELECT

How to convert VARCHAR columns to DECIMAL without rounding in SQL Server?

In my SQL class, I'm working with a table that is all VARCHAR. I'm trying to convert each column to a more correct data type.
For example. I have a column called Item_Cost that has a value like:
1.25000000000000000000
I tried to run this query:
ALTER TABLE <table>
ALTER COLUMN Item_Cost DECIMAL
This query does run successfully, but it turns it into 1 instead of 1.25.
How do I prevent the rounding?
Check out the documentation for the data type decimal. The type is defined by optional parameters p (precision) and s (scale). The latter determines the numbers to the right of the decimal point.
Extract from the documentation (I highlighted the important bit in bold):
s (scale)
The number of decimal digits that are stored to the right of
the decimal point. This number is subtracted from p to determine the
maximum number of digits to the left of the decimal point. Scale must
be a value from 0 through p, and can only be specified if precision is
specified. The default scale is 0 and so 0 <= s <= p. Maximum storage
sizes vary, based on the precision.
Defining a suitable precision and scale fixes your issue.
Sample data
create table MyData
(
Item_Cost nvarchar(100)
);
insert into MyData (Item_Cost) values ('1.25000000000000000000');
Solution
ALTER TABLE MyData Alter Column Item_Cost DECIMAL(10, 3);
Result
Item_Cost
---------
1.250
Fiddle

On Insert: Arithmetic overflow error converting expression to data type int

I tried creating my third table of phone numbers, I wrote the following commands:
CREATE TABLE MYPHONE (EMPLOYEE_ID INT, PHONE_NUMBER INT)
INSERT INTO MYPHONE
VALUES (1 , 7894561230)
But when I tried executing this previous INSERT command, I got an error:
Msg 8115, Level 16, State 2, Line 46
Arithmetic overflow error converting expression to data type int.
An int probably isn't the best data type for a phone number - you don't need to do any arithmetic on phone numbers, so why use a numerical data type? Store it as a string (or varchar in SQL).
Also, if you did need to store a value as an int, 2,147,483,647 is the maximum - anything higher would "overflow", hence the error you're getting. A long (or bigint in SQL) would allow values up to 9,223,372,036,854,775,808.
Allowed range of INT datatype is -2,147,483,648 to 2,147,483,647
You can get more details on the allowed range here
You are trying to insert beyond that range. For phone number better choose VARCHAR data type. If you still want to go for number, in that case use BIGINT instead of INT.

how does SQL Server actually store russian symbols in char?

I have a column NAME, which is CHAR(50).
It contains the value 'Рулон комбинированный СТЕРИТ 50мм ? 200 м'
which integer representation is:
'1056,1091,1083,1086,1085,32,1082,1086,1084,1073,1080,1085,1080,1088,1086,1074,1072,1085,1085,1099,1081,32,1057,1058,1045,1056,1048,1058,32,53,48,1084,1084,32,63,32,50,48,48,32,1084'
but CHAR implies that it contains 8 bit. How does SQL Server store values like '1056,1091,1083,1086,1085' which are UNICODE symbols?
OK, and also ? symbol is actually × (215) (Multiplication Sign)
If SQL Server can represent '1056' why it can't represent '215'?
What the 255 values in a char mean is determined by the database collation. For Russia this is typically Cyrillic_General_CI_AS (where CI means Case Insentitive and AS means Accent Sensitive.)
There's a good chance this matches Windows code page 1251, so л is stored as hex EB or decimal 235. You can verify this with T-SQL:
create database d1 collate Cyrillic_General_CI_AS;
use d1
select ascii('л')
-->
235
In the Cyrillic code page, decimal 215 means Ч, not the multiplication sign. Because SQL Server can't match the multiplication sign to the Cyrillic code page, it replaces it with a question mark:
select ascii('×'), ascii('?')
-->
63 63
In the Cyrillic code page, the char 8-bit representation of the multiplication sign and the question mark are both decimal 63, the question mark.
I have a column NAME, which is CHAR(50).
It contains the value 'Рулон комбинированный СТЕРИТ 50мм ? 200 м'
which integer representation is:
'1056,1091,1083,1086,1085,32,1082,1086,1084,1073,1080,1085,1080,1088,1086,1074,1072,1085,1085,1099,1081,32,1057,1058,1045,1056,1048,1058,32,53,48,1084,1084,32,63,32,50,48,48,32,1084'
Cyted above is wrong.
I make a test within a database with Cyrillic collation and integer representation is different from what you showed us, so or your data type is not char, or your integer representation is wrong, and yes, "but CHAR implies that it contains 8 bit" is correct and here is how you can prove it to youerself:
--create table dbo.t (name char(50));
--insert into dbo.t values ('Рулон комбинированный СТЕРИТ 50мм ? 200 м')
select cast (name as binary(50))
from dbo.t;
select substring(cast (name as binary(50)), n, 1) as bin_substr,
cast(substring(cast (name as binary(50)), n, 1) as int) as int_,
char(substring(cast (name as binary(50)), n, 1)) as cyr_char
from dbo.t cross join nums.dbo.nums;
Here dbo.Nums is an auxiliary table containig integers. I just convert your string from char field into binary, split it byte per byte and convert into int and char.

SQLServer choosing primary key type

I have a list of objects each of its own id and I need to create a table for them in a database. It's a good idea to use their ids(since they are unique) as a primary key in the table but there's one problem. All ids are integers except for the one object - it has 2 subobjects with ids 142.1 and 142.2, so the id list is 140, 141, 142.1, 142.2, 143...
Now if I choose a double as a type of primary key then it will store unnecessary 6 bytes(since double is 8 bytes and INT is 2) to only support two double numbers and I can't choose INT. So what type should I use if I cannot change the list of objects?
The math for double is imprecise, you shouldn't use it for discrete numbers like money or object id's. Consider using decimal(p,s) instead. Where p is the total number of digits, and s is the number of digits behind the dot. For example, a decimal(5,2) could store 123.45, but not 1234 or 12.345.
Another option is a composite primary key for two integers n1, n2:
alter table YourTable add constraint PK_YourTable primary key (n1, n2)
An int is four bytes, not two, so the size difference to a double is not so big.
However, you should definitely not use a floating point number as key, as a floating point number isn't stored as an exact values, but as an approximation.
You can use a decimal with one fractional digit, like decimal(5,1), to store a value like that. A decimal is a fixed point number, so it's stored as an exact value, not an approximation.
Choose VARCHAR of an appropriate length, with CHECK constraints to ensure the data conforms to your domain rules e.g. based on the small sample data you posted:
CREATE TABLE Ids
(
id VARCHAR(5) NOT NULL UNIQUE
CONSTRAINT id__pattern
CHECK (
id LIKE '[0-9][0-9][0-9]'
OR id LIKE '[0-9][0-9][0-9].[1-9]'
)
);

Resources