[英]SQL round to the nearest hundredth
UPDATE prodfeatures2 SET featureprice = featureprice * 0.6316;
I am trying to setup a round of to the nearest hundredth. 我想设置一轮到最接近的百分之一。 HELP!
救命!
I do not want the answer to be 104.7648, I would want it to be 104.76. 我不希望答案是104.7648,我希望它是104.76。
I do not want the answer to be 104.7668, I would want it to be 104.77. 我不希望答案是104.7668,我希望它是104.77。
UPDATE prodfeatures2 SET featureprice = ROUND(featureprice * 0.6316,2)
I don't think you have provided enough data to deduce which rounding algorithm you require. 我认为您没有提供足够的数据来推断出您需要哪种舍入算法 。
If your spec tells you which rounding algorithm to use then please post it. 如果您的规范告诉您使用哪种舍入算法,请发布它。
If your spec fails to tell you which rounding algorithm then raise the issue with the designer. 如果您的规范未能告诉您哪种舍入算法,那么请向设计人员提出问题。
Generally speaking, SQL isn't designed for math calculations. 一般来说,SQL不是为数学计算而设计的。 Consider doing rounding in another tier.
考虑在另一层进行舍入。 If you do, be sure to store values using
DECIMAL
with an additional decimal place than required in the front end. 如果这样做,请确保使用
DECIMAL
存储值,并在前端添加小数位。
Please see: How to Round in MS Access, VBA 请参阅: 如何在MS Access中进行回合,VBA
To quote an excerpt: 引用一段摘录:
"The Round function performs round to even, which is different from round to larger." “Round函数执行round到even,这不同于round到large。” --Microsoft
- 微软
Format always rounds up. 格式总是向上舍入。
Debug.Print Round(19.955, 2)
'Answer: 19.95
Debug.Print Format(19.955, "#.00")
'Answer: 19.96
In this case: 在这种情况下:
UPDATE prodfeatures2 SET featureprice = CCUR(Format(featureprice * 0.6316,'#.00'))
SELECT ROUND(强制转换(104.7668为十进制(6,2)),2)为roundof;
ROUND(TheValue, 2)
Here's my MS-Access specific answer: there's something fishy about the question! 这是我的MS-Access特定答案:这个问题有些可疑!
Unless featureprice
is an extremely large or extremely large small amount, and the metadata suggests that it is not, multiplying by a decimal literal such as 0.6316
will coerse the result to type DECIMAL
.Now, by nature, the DECIMAL
type in Access (ACE, Jet, whatever), rounds by truncation eg if you could do this: 除非
featureprice
是一个非常大或非常大的小数量,并且元数据表明它不是,否则乘以十进制文字(如0.6316
会将结果0.6316
转换为DECIMAL
。现在,在Access中的DECIMAL
类型(ACE, Jet,无论如何),通过截断进行舍入,例如,如果你能做到这一点:
SELECT CAST(104.7668 AS DECIMAL(17, 2)
it would round to 104.76
... of course you can't do this in Access because it doesn't support the SQL Standard syntax and its own proprietary syntax CDEC()
was broken from day one and still hasn't been fixed in ACE (rolls eyes). 它会转到
104.76
...当然你不能在Access中执行此操作,因为它不支持SQL标准语法,并且它自己的专有语法CDEC()
从第一天开始就被破坏,但仍然没有在ACE中修复(转动眼球)。 But what you can do is this: 但你能做的就是:
CREATE TABLE TestDecimal
(
dec_col DECIMAL(17, 2) NOT NULL UNIQUE
);
INSERT INTO TestDecimal (dec_col)
VALUES (104.7668);
SELECT dec_col FROM TestDecimal;
-- 104.76 -- truncated
I'm going to guess that your prodfeatures2
column is type CURRENCY
and I suggest that if don't want your result to be cast as a DECIMAL
, and what we can tell from your algorithm you do not, then your SQL is missing a cast. 我猜你的
prodfeatures2
列是CURRENCY
类型,我建议如果不希望你的结果被转换为DECIMAL
,我们可以从你的算法中判断出你没有,那么你的SQL缺少一个强制转换。
Further, you want the result to be two decimal places, yet the original values are not to two decimal places. 此外,您希望结果是两位小数,但原始值不是两位小数。 For example:
例如:
SELECT CCUR(CCUR(165.87) * 0.6316)
-- 104.7635 -- too low
SELECT CCUR(CCUR(165.88) * 0.6316)
-- 104.7698 -- too high
SELECT CCUR(CCUR(165.872) * 0.6316)
-- 104.7648 -- spot on
So the values are failing to be rounded to two dp by an earlier process but needs to be two dp after this process? 所以这个值不能通过早期的过程四舍五入到两个dp,但在这个过程之后需要两个dp? As I say, something may smell here and you have bugs you haven't yet tracked down... or there's more to this than you are revealing here.
正如我所说的,这里可能会有一些东西闻到你的臭虫还有你尚未追踪到的东西......或者还有更多的东西比你在这里透露的还要多。
What is the basis for your assertion that multipying by a decimal coerces the result to a decimal data type?
断言乘以十进制将结果强制为十进制数据类型的基础是什么?
(Tongue in cheek) Why, I read it in the user manual for ACE/Jet of course. (舌头在脸上)为什么,我当然在ACE / Jet的用户手册中读到它。 Only joking, there isn't one.
只是在开玩笑,没有一个。 Like anything in Jet 4.0, you just have experiment.
像Jet 4.0中的任何东西一样,你只需要进行实验。
Decimal literals (with exceptions eg extremely large and extremely small values) are of type DECIMAL
. 十进制文字(例外,例如极大和极小的值)是
DECIMAL
类型。 For example: 例如:
SELECT TYPENAME(0.1)
returns 'Decimal'. 返回'十进制'。
When using the numeric operators (add, subtract, multiply and divide) involving a value of type DECIMAL
will coerce the result to type DECIMAL
(the same exceptions as above apply). 当使用涉及
DECIMAL
类型值的数字运算符(加,减,乘和除)时,将强制结果键入DECIMAL
(与上述相同的例外情况适用)。
A simple yet effective test is to create a table with one column for each of the numeric data types, insert a small value (say 1) for each, then add/subtract/multiply/divide all by a decimal literal (say 0.1): 一个简单而有效的测试是为每个数值数据类型创建一个包含一列的表,为每个数据类型插入一个小值(比如1),然后用十进制文字(比如0.1)加/减/乘/除所有:
SQL DDL: SQL DDL:
CREATE TABLE TestNumericDataTypes
(
TINYINT_col TINYINT NOT NULL,
SMALLINT_col SMALLINT NOT NULL,
INTEGER_col INTEGER NOT NULL,
REAL_col REAL NOT NULL,
FLOAT_col FLOAT NOT NULL,
DECIMAL_col DECIMAL NOT NULL,
CURRENCY_col CURRENCY NOT NULL,
YESNO_col YESNO NOT NULL,
DATETIME_col DATETIME NOT NULL
);
SQL DML: SQL DML:
INSERT INTO TestNumericDataTypes
(
TINYINT_col, SMALLINT_col, INTEGER_col,
REAL_col, FLOAT_col, DECIMAL_col,
CURRENCY_col, YESNO_col, DATETIME_col
)
VALUES (1, 1, 1, 1, 1, 1, 1, 1, 1);
SQL DML: SQL DML:
SELECT TYPENAME(TINYINT_col * 0.1),
TYPENAME(SMALLINT_col * 0.1),
TYPENAME(INTEGER_col * 0.1),
TYPENAME(REAL_col * 0.1),
TYPENAME(FLOAT_col * 0.1),
TYPENAME(DECIMAL_col * 0.1),
TYPENAME(CURRENCY_col * 0.1),
TYPENAME(YESNO_col * 0.1),
TYPENAME(DATETIME_col * 0.1),
TYPENAME(TINYINT_col / 0.1),
TYPENAME(SMALLINT_col / 0.1),
TYPENAME(INTEGER_col / 0.1),
TYPENAME(REAL_col / 0.1),
TYPENAME(FLOAT_col / 0.1),
TYPENAME(DECIMAL_col / 0.1),
TYPENAME(CURRENCY_col / 0.1),
TYPENAME(YESNO_col / 0.1),
TYPENAME(DATETIME_col / 0.1),
TYPENAME(TINYINT_col + 0.1),
TYPENAME(SMALLINT_col + 0.1),
TYPENAME(INTEGER_col + 0.1),
TYPENAME(REAL_col + 0.1),
TYPENAME(FLOAT_col + 0.1),
TYPENAME(DECIMAL_col + 0.1),
TYPENAME(CURRENCY_col + 0.1),
TYPENAME(YESNO_col + 0.1),
TYPENAME(DATETIME_col + 0.1),
TYPENAME(TINYINT_col - 0.1),
TYPENAME(SMALLINT_col - 0.1),
TYPENAME(INTEGER_col - 0.1),
TYPENAME(REAL_col - 0.1),
TYPENAME(FLOAT_col - 0.1),
TYPENAME(DECIMAL_col - 0.1),
TYPENAME(CURRENCY_col - 0.1),
TYPENAME(YESNO_col - 0.1),
TYPENAME(DATETIME_col - 0.1)
FROM TestNumericDataTypes;
I'm not sure whether you can create all these types via the Access interface nad you may not know how to run SQL DDL so here's some vanilla VBA (Access not required eg can be run from Excel, no references required eg just copy and paste): 我不确定你是否可以通过Access接口创建所有这些类型nad你可能不知道如何运行SQL DDL所以这里有一些vanilla VBA(不需要访问,例如可以从Excel运行,不需要引用,例如只需复制和粘贴):
Sub TestAccessDecimals()
On Error Resume Next
Kill Environ$("temp") & "\DropMe.mdb"
On Error GoTo 0
Dim cat
Set cat = CreateObject("ADOX.Catalog")
With cat
.Create _
"Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & _
Environ$("temp") & "\DropMe.mdb"
With .ActiveConnection
Dim Sql As String
Sql = _
"CREATE TABLE TestNumericDataTypes" & vbCr & "(" & vbCr & " TINYINT_col TINYINT NOT NULL, " & vbCr & " SMALLINT_col SMALLINT NOT NULL, " & vbCr & " INTEGER_col INTEGER NOT NULL, " & vbCr & " REAL_col REAL NOT NULL, " & vbCr & " FLOAT_col FLOAT NOT" & _
" NULL, " & vbCr & " DECIMAL_col DECIMAL NOT NULL, " & vbCr & " CURRENCY_col CURRENCY NOT NULL, " & vbCr & " YESNO_col YESNO NOT NULL, " & vbCr & " DATETIME_col DATETIME NOT NULL" & vbCr & ");"
.Execute Sql
Sql = _
"INSERT INTO TestNumericDataTypes " & vbCr & "(" & vbCr & " TINYINT_col, SMALLINT_col, INTEGER_col, " & vbCr & " REAL_col, FLOAT_col, DECIMAL_col, " & vbCr & " CURRENCY_col, YESNO_col, DATETIME_col" & vbCr & ") " & vbCr & "VALUES (1, 1, 1, 1, 1, 1," & _
" 1, 1, 1);"
.Execute Sql
Sql = _
"SELECT TYPENAME(TINYINT_col * 0.1), " & vbCr & " TYPENAME(SMALLINT_col * 0.1), " & vbCr & " TYPENAME(INTEGER_col * 0.1), " & vbCr & " TYPENAME(REAL_col * 0.1), " & vbCr & " TYPENAME(FLOAT_col * 0.1)," & _
" " & vbCr & " TYPENAME(DECIMAL_col * 0.1), " & vbCr & " TYPENAME(CURRENCY_col * 0.1), " & vbCr & " TYPENAME(YESNO_col * 0.1), " & vbCr & " TYPENAME(DATETIME_col * 0.1)," & vbCr & " TYPENAME(TINYINT_col / 0.1)," & _
" " & vbCr & " TYPENAME(SMALLINT_col / 0.1), " & vbCr & " TYPENAME(INTEGER_col / 0.1), " & vbCr & " TYPENAME(REAL_col / 0.1), " & vbCr & " TYPENAME(FLOAT_col / 0.1), " & vbCr & " TYPENAME(DECIMAL_col / 0.1)," & _
" " & vbCr & " TYPENAME(CURRENCY_col / 0.1), " & vbCr & " TYPENAME(YESNO_col / 0.1), " & vbCr & " TYPENAME(DATETIME_col / 0.1)," & vbCr & " TYPENAME(TINYINT_col + 0.1), " & vbCr & " TYPENAME(SMALLINT_col +" & _
" 0.1), " & vbCr & " TYPENAME(INTEGER_col + 0.1), " & vbCr & " TYPENAME(REAL_col + 0.1), " & vbCr & " TYPENAME(FLOAT_col + 0.1), " & vbCr & " TYPENAME(DECIMAL_col + 0.1), " & vbCr & " TYPENAME(CURRENCY_col" & _
" + 0.1), " & vbCr & " TYPENAME(YESNO_col + 0.1), " & vbCr & " TYPENAME(DATETIME_col + 0.1)," & vbCr & " TYPENAME(TINYINT_col - 0.1), " & vbCr & " TYPENAME(SMALLINT_col - 0.1), " & vbCr & " TYPENAME(INTEGER_col" & _
" - 0.1), " & vbCr & " TYPENAME(REAL_col - 0.1), " & vbCr & " TYPENAME(FLOAT_col - 0.1), " & vbCr & " TYPENAME(DECIMAL_col - 0.1), " & vbCr & " TYPENAME(CURRENCY_col - 0.1), " & vbCr & " TYPENAME(YESNO_col" & _
" - 0.1), " & vbCr & " TYPENAME(DATETIME_col - 0.1)" & vbCr & "FROM TestNumericDataTypes;"
Dim rs
Set rs = .Execute(Sql)
MsgBox rs.GetString
End With
Set .ActiveConnection = Nothing
End With
End Sub
The result is Decimal
in every case. 在每种情况下,结果都是
Decimal
。 QED QED
A few exceptions alluded to earlier: 前面提到的一些例外情况:
Decimal literals which are equal to their INTEGER
value eg 十进制文字,等于它们的
INTEGER
值,例如
SELECT TYPENAME(1.0)
returns 'Long' (which is the VBA equivalent of Jet 4.0's INTEGER
type -- why it shows the VBA name and not the Jet name I don't know). 返回'Long'(这是Jet 4.0的
INTEGER
类型的VBA等价物 - 为什么它显示VBA名称而不是我不知道的Jet名称)。
...except when the value is beyond the INTEGER
range: ...除非值超出
INTEGER
范围:
SELECT TYPENAME(10000000000)
returns 'Decimal' 返回'十进制'
...excpet when the value is beyond the DECIMAL
range: ...当值超出
DECIMAL
范围时激励:
SELECT TYPENAME(1E29)
returns 'Double' (being the VBA equivalent of Jet's FLOAT
). 返回'Double'(相当于Jet的
FLOAT
的VBA)。
In the positive range, operating on the value with a DECIMAL
literal retains the type as FLOAT
eg 在正范围内,使用
DECIMAL
文字对值进行操作DECIMAL
类型保留为FLOAT
例如
SELECT TYPENAME(1E29 + 0.1)
returns 'Double (
FLOAT`). 返回'Double
(
FLOAT`)。
...whereas in the negative range it is coersed to DECIMAL
......在负面范围内,它被赋予了
DECIMAL
SELECT TYPENAME(1E-29 + 0.1)
returns 'Decimal'. 返回'十进制'。
Coersion works differently when crossing bounds eg (noting that the upper bounds for INTEGER
is 2,147,483,647): 穿越边界时Coersion的工作方式不同,例如(注意
INTEGER
的上限是2,147,483,647):
SELECT TYPENAME(2147483648)
returns 'Decimal` 返回'十进制'
...whereas: ...然而:
SELECT TYPENAME(2147483647 + 1.0)
returns 'Double' ( FLOAT
). 返回'Double'(
FLOAT
)。
No doubt there are other exceptions I haven't stumbled upon. 毫无疑问,还有其他例外我没有偶然发现。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.