Best method for storing a decimal number with varying number of decimal places
Two soutions I can think of:
As you've already mentioned, store it in text
Store it in
decimal(19,6)
- Store the number of decimals in another field, i.e.
3
- Use a calculated column to render the format, i.e.
FORMAT()
- Store the number of decimals in another field, i.e.
You'd need to reverse engineer the number of decimals though.
This is more complicated but at least you can store the number in a numeric field and have SSMS render what you want.
CREATE TABLE MyTable (
NumericValue DECIMAL(19,6) NOT NULL,
Decimals TINYINT NOT NULL,
Formatted AS (FORMAT(NumericValue,'#.' + LEFT('00000000',Decimals)))
)
INSERT INTO MyTable (NumericValue, Decimals)
SELECT 10.2,3 UNION ALL
SELECT 1.2,1 UNION ALL
SELECT 1,3
SELECT * FROM MyTable
How does SQL Server store decimal type values internally?
Martin's Smith comment gives you the clue. SQL Server does not use BCD.
It stores the data as a whole number, without the decimal place (which it can do because the decimal place is stored in the metadata for the column). So 5.7456
is stored as 57456
, or 0xE070
. After SQL's infamous byte swapping this is transformed to 70 E0 00 00
.
The leading 01
is the sign. 01
is used for positive numbers; 00
for negatives.
(However, I must ask - why do you need this? In typical use, you should never need to bother with SQL Server's internals)
Save decimal values in SQL Server Management Studio
Several issues here:
You need to change the datatype of the
[ProductName]
field toVARCHAR(50)
or some other number if 50 is too few characters for a name. But thetext
datatype was deprecated when SQL Server 2005 came out and even if you are still on SQL Server 2000, I highly doubt you need more than 8000 characters for a product name ;-). The replacement forTEXT
isVARCHAR(MAX)
, for when a situation actually needs more than 8000 characters.You need to parameterize your query because in the current form, your code is susceptible to SQL Injection.
You cannot save decimals in SQL Server Management Studio (SSMS). You can save queries and you can save results, but SSMS is an IDE. You are probably meaning that you cannot save the decimal values to SQL Server using .NET.
While not required by an INSERT statement, specifying the column list is always a good idea because the order of the columns might not be what you expect, and if you add columns then this INSERT will fail. Meaning, instead of:
INSERT INTO dbo.NCAProduct VALUES(...);
do:
INSERT INTO dbo.NCAProduct
(ProductCode, ProductName, SupplierCode, Cost, RetailPrice, Quantity)
VALUES(...);Without seeing what values you are trying to insert (which would help narrow down the issue), I would say that this is the most likely cause of the issue, assuming that the order of columns in your initial "/// Columns" list is the actual order. If you look at the order of how the fields are inserted,
txtRetail.Text
andtxtQuantity.Text
are switched as the table appears to haveQuantity
and thenRetailPrice
. Specifying the field list in the INSERT eliminates this issue, even if it isn't the actual problem here.
If #4 is not the problem, then you need to debug and step through to see the values of txtRetail.Text
and txtQuantity.Text
as they exist when they are concatenated into the SqlCommand
.
Why are my decimal values being rounded to integers in SQL insertions?
You did not define a scale/precision for your decimal. If you want 3 digits after the decimal you should define it as DECIMAL(9,3) which would give you 6 places before the decimal and a decimal of up to 3 places. You need to analyze the expected data and based on what you expect specify the correct precision and scale for your column definition.
CREATE TABLE tmp(
id int NOT NULL IDENTITY(1,1)PRIMARY KEY,
toleranceRegion DECIMAL(9,3)
)
See the Sql Server documentation for decimal here.
Why would someone store a DECIMAL as an INT in a SQL Server database and then do the math in the software?
FLOAT
is terrible because it has precision and conversion issues, but I think you're more focused on why INT
was used instead of DECIMAL
or NUMERIC
There are a few possible reasons I can think of:
INT
is (negligibly) smaller:DECIMAL
andNUMERIC
are5-17 bytes
depending on precisionINT
is4 bytes
Some people believe
INT
is faster, but good luck proving thatYou mention this is used globally, so it may make more sense for the format of a decimal value to be handled by the front end anyway. For instance,
12.89
in the US is12,89
in many European countries.
How to store decimal in MySQL?
The first parameter of the DECIMAL
declaration is the total digits. You probably want to use DECIMAL (4, 2)
. This allows for up to two digits before the decimal and two after.
Documentation: https://dev.mysql.com/doc/refman/5.7/en/precision-math-decimal-characteristics.html
Related Topics
Get Unique Values Using String_Agg in SQL Server
How to Get the Next Number in a Sequence
Why am I Getting a "[Sql0802] Data Conversion of Data Mapping Error" Exception
Column Does Not Exist in the in Clause, But SQL Runs
Pls-00201: Identifier 'User Input' Must Be Declared
SQL in Query Produces Strange Result
Truncate Timestamp to Arbitrary Intervals
Why Does the Following Join Increase the Query Time Significantly
Using Start Date and End Date in Access Query
Sample Query to Show Cardinality Estimation Error in Postgresql
Column Reference Is Ambiguous in Postgresql Function
How to Build a Summary by Joining to a Single Table with SQL Server
Query JSON Dictionary Data in SQL
What Did Mongodb Not Being Acid Compliant Before V4 Really Mean
How to Check for Is Not Null and Is Not Empty String in SQL Server
How to Drop a Foreign Key Constraint Only If It Exists in SQL Server
Select Rows with Maximum Column Value Group by Another Column