简体   繁体   English

这是在 SQL 中投射、舍入和平均 object 的正确方法吗?

[英]Is this the correct way to cast, round, and avg an object in SQL?

QUESTION问题

How do I use avg and round to provide a decimal point in PostgreSQL?如何使用avground在 PostgreSQL 中提供小数点?

What function do I need to convert a string to a decimal number?我需要什么 function 将字符串转换为十进制数?

FUNCTIONS USED使用的功能

1st function第一个 function

AVG(ratings.dating) AS scent_avg

1st error第一个错误

Error: expected { scents_id: 1, scent_avg: 4.5 } response body, got { scents_id: 1, scent_avg: '4.5000000000000000' }

2nd function 2号 function

ROUND(AVG(ratings.rating), 1) AS scent_avg

2nd error第二个错误

Error: expected { scents_id: 1, scent_avg: 4.5 } response body, got { scents_id: 1, scent_avg: '4.5' }

3rd function 3号 function

What function is used to convert a string to a number?什么 function 用于将字符串转换为数字?

EDIT编辑

Looks like I had a mental lapse.看来我心理有问题。 sticky bit clarified that int has no decimals.粘性位澄清了 int 没有小数。 I removed the int bit from the original post.我从原始帖子中删除了 int 位。

In most databases, this should do the trick:在大多数数据库中,这应该可以解决问题:

cast(avg(ratings.ratio * 1.0) as decimal(4, 1))

I don't see any rounding here.我在这里看不到任何舍入。 4.5 IS the average of 4 and 5 mathematically speaking.从数学上讲, 4.545的平均值。

Formatted string格式化字符串

Use to_char() to get a formatted string without insignificant zeroes (or padding blanks) - "rounded to the tenth decimal place" as you commented:使用to_char()获取格式化字符串,不包含无关紧要的零(或填充空白) - 正如您评论的“四舍五入到小数点后十位”:

SELECT to_char(round(avg(ratings.rating), 10), 'FM999999999990.9999999999')

Note the one 0 .注意一个0 Typically you want that position in any case.通常,在任何情况下您都想要 position。 Like for 0.3 .喜欢0.3 Add as many 9 as you want to allow digits.添加尽可能多的9 ,以允许数字。 The manual: 手册:

0 specifies a digit position that will always be printed, even if it contains a leading/trailing zero. 0指定将始终打印的数字 position,即使它包含前导/尾随零。 9 also specifies a digit position, but if it is a leading zero then it will be replaced by a space, while if it is a trailing zero and fill mode is specified then it will be deleted. 9还指定了一个数字 position,但如果是前导零,则将其替换为空格,而如果是尾随零并指定填充模式,则将其删除。

And about the FM prefix: 关于FM前缀:

fill mode (suppress leading zeroes and padding blanks)填充模式(抑制前导零和填充空白)

Numeric value without insignificant trailing zeroes没有无关紧要的尾随零的数值

Cast to double precision ( float8 ) to get a numeric value without insignificant trailing zeroes.转换为double precision ( float8 ) 以获取没有无关紧要的尾随零的数值。 The cast trims insignificant zeroes.演员修剪微不足道的零。 Generally, casting to a floating point number can introduce corner case rounding errors.通常,转换为浮点数会引入极端情况舍入误差。

I had suggested more sophisticated solutions first, but since you are only interested in precision up to the tenth decimal place and float8 is precise up to 15 fractional digits, the problem does not apply.我首先建议了更复杂的解决方案,但是由于您只对精确到小数点后十位的精度感兴趣,而float8精确到 15 个小数位,所以问题不适用。 The manual: 手册:

On all currently supported platforms, the real type has a range of around 1E-37 to 1E+37 with a precision of at least 6 decimal digits.在所有当前支持的平台上, real类型的范围约为 1E-37 到 1E+37,精度至少为 6 位十进制数字。 The double precision type has a range of around 1E-307 to 1E+308 with a precision of at least 15 digits. double precision类型的范围约为 1E-307 到 1E+308,精度至少为 15 位。 Values that are too large or too small will cause an error.值太大或太小都会导致错误。 Rounding might take place if the precision of an input number is too high.如果输入数字的精度太高,可能会发生舍入。 Numbers too close to zero that are not representable as distinct from zero will cause an underflow error.太接近零且无法表示为与零不同的数字将导致下溢错误。

So just:所以就:

SELECT round(avg(ratings.rating), 10)::float8

Note that we cast after rounding, as the variant of round() accepting a number of decimal places only works for numeric (due to the inexact nature of internal storage of floating point numbers).请注意,我们在舍入后进行转换,因为接受小数位数的round()的变体仅适用于numeric (由于浮点数内部存储的不精确性质)。


Inside Postgres, you wouldn't worry too much about those trailing zeroes.在 Postgres 中,你不会太担心那些尾随的零。 The manual: 手册:

Numeric values are physically stored without any extra leading or trailing zeroes.数值是物理存储的,没有任何额外的前导零或尾随零。 Thus, the declared precision and scale of a column are maximums, not fixed allocations.因此,列的声明精度和比例是最大值,而不是固定分配。 (In this sense the numeric type is more akin to varchar(n) than to char(n) .) The actual storage requirement is two bytes for each group of four decimal digits, plus three to eight bytes overhead. (从这个意义上说,数字类型更类似于varchar(n)而不是char(n) 。)实际的存储要求是每组四个十进制数字需要两个字节,加上三到八个字节的开销。

See:看:

Inside Postgres, equality is established correctly:在 Postgres 内部,平等是正确建立的:

SELECT numeric '4.50000000' = numeric '4.5'  -- true
SELECT jsonb '{"scents_id": 4.5}' = jsonb '{"scents_id": 4.5000}'  -- true

Your client throwing the error seems to compare text representations, which is subtly incorrect.抛出错误的客户似乎在比较文本表示,这是不正确的。 So you may have to format like your client expects...所以你可能必须像你的客户期望的那样格式化......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM