SQLServer choosing primary key type - sql-server

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]'
)
);

Related

confuse SQL Server datatype decimal over 15 digit after comma

I have table with structure as follow :
Table1 (
id int NULL,
description varchar(50) null,
rate decimal(18,15) NULL
)
and when I test insert data into the table problem value like this :
insert into Table1 (id, description, rate)
values (1, 'My Room Upstair', 38397.0893181818)
and the error like this :
Msg 8115, Level 16, State 8, Line 1 Arithmetic overflow error
converting numeric to data type numeric.
But when I use Float data type the data inserted successful. But the rate value change to different value.
need advice please...
solution of decimal data type problem
The problem is that you are not using the decimal data type correctly.
The data type is defined like this decimal(a, b).
a is used to specify the amount of digits in the value. The default value is 18, but you can choose whatever number between 1, which is the minimum and 38, which is the maximum.
b is used for the amount of digits after the decimal point. The default value is 0 but you can specify choosing between the minimum and maximum, which are the same 1 and 38. b can only be specified if a is also specified. It needs to be equal or less than a.
In your example decimal(18,15), you can insert a number that is 18 digits long, 3 before and 15 after the decimal point. 38397.0893181818 has 5 digits before the decimal point, which is why you get the error. So if you need to add 38397.0893181818, you need decimal(15,10), since the number has 15 digits, 10 of which are after the decimal point.
The problem is that the decimal(a,b) parameters work according to what you need, a defines the number of total digits and b defines the number of digits of that total that will go after the decimal point.
https://learn.microsoft.com/es-es/sql/t-sql/data-types/decimal-and-numeric-transact-sql?view=sql-server-ver16

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.

Postive Integers and Unsigned in SQL Server 2012

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

Appropriate datatype for holding percent values?

What is the best datatype for holding percent values ranging from 0.00% to 100.00%?
Assuming two decimal places on your percentages, the data type you use depends on how you plan to store your percentages:
If you are going to store their fractional equivalent (e.g. 100.00% stored as 1.0000), I would store the data in a decimal(5,4) data type with a CHECK constraint that ensures that the values never exceed 1.0000 (assuming that is the cap) and never go below 0 (assuming that is the floor).
If you are going to store their face value (e.g. 100.00% is stored as 100.00), then you should use decimal(5,2) with an appropriate CHECK constraint.
Combined with a good column name, it makes it clear to other developers what the data is and how the data is stored in the column.
Hold as a decimal.
Add check constraints if you want to limit the range (e.g. between 0 to 100%; in some cases there may be valid reasons to go beyond 100% or potentially even into the negatives).
Treat value 1 as 100%, 0.5 as 50%, etc. This will allow any math operations to function as expected (i.e. as opposed to using value 100 as 100%).
Amend precision and scale as required (these are the two values in brackets columnName decimal(precision, scale). Precision says the total number of digits that can be held in the number, scale says how many of those are after the decimal place, so decimal(3,2) is a number which can be represented as #.##; decimal(5,3) would be ##.###.
decimal and numeric are essentially the same thing. However decimal is ANSI compliant, so always use that unless told otherwise (e.g. by your company's coding standards).
Example Scenarios
For your case (0.00% to 100.00%) you'd want decimal(5,4).
For the most common case (0% to 100%) you'd want decimal(3,2).
In both of the above, the check constraints would be the same
Example:
if object_id('Demo') is null
create table Demo
(
Id bigint not null identity(1,1) constraint pk_Demo primary key
, Name nvarchar(256) not null constraint uk_Demo unique
, SomePercentValue decimal(3,2) constraint chk_Demo_SomePercentValue check (SomePercentValue between 0 and 1)
, SomePrecisionPercentValue decimal(5,2) constraint chk_Demo_SomePrecisionPercentValue check (SomePrecisionPercentValue between 0 and 1)
)
Further Reading:
Decimal Scale & Precision: http://msdn.microsoft.com/en-us/library/aa258832%28SQL.80%29.aspx
0 to 1 vs 0 to 100: C#: Storing percentages, 50 or 0.50?
Decimal vs Numeric: Is there any difference between DECIMAL and NUMERIC in SQL Server?
I agree with Thomas and I would choose the DECIMAL(5,4) solution at least for WPF applications.
Have a look to the MSDN Numeric Format String to know why :
http://msdn.microsoft.com/en-us/library/dwhawy9k#PFormatString
The percent ("P") format specifier multiplies a number by 100 and converts it to a string that represents a percentage.
Then you would be able to use this in your XAML code:
DataFormatString="{}{0:P}"
If 2 decimal places is your level of precision, then a "smallint" would handle this in the smallest space (2-bytes). You store the percent multiplied by 100.
EDIT: The decimal type is probably a better match. Then you don't need to manually scale. It takes 5 bytes per value.
Use numeric(n,n) where n has enough resolution to round to 1.00. For instance:
declare #discount numeric(9,9)
, #quantity int
select #discount = 0.999999999
, #quantity = 10000
select convert(money, #discount * #quantity)

Resources