记录学习过程(PostgreSQL官方文档)
数字类型
数字类型包括2 字节、4 字节和 8 字节整数,4 字节和 8 字节浮点数,以及精度可选的小数。
| Name | Storage Size | Description | Range |
|---|---|---|---|
| smallint | 2 bytes | small-range integer | -32768 to +32767 |
| integer | 4 bytes | typical choice for integer | -2147483648 to +2147483647 |
| bigint | 8 bytes | large-range integer | -9223372036854775808 to +9223372036854775807 |
| decimal | variable | user-specified precision,exact | up to 131072 digits before the decimal point; up to 16383 digits after the decimal point |
| numeric | variable | user-specified precision,exact | up to 131072 digits before the decimal point; up to 16383 digits after the decimal point |
| real | 4 bytes | variable-precision, inexact | 6 decimal digits precision |
| double precision | 8 bytes | variable-precision, inexact | 15 decimal digits precision |
| smallserial | 2 bytes | small autoincrementing integer | 1 to 32767 |
| serial | 4 bytes | autoincrementing integer | 1 to 2147483647 |
| bigserial | 8 bytes | large autoincrementing integer | 1 to 9223372036854775807 |
整数类型
smallint、integer 和 bigint 类型用于存储整数(即无小数部分的数字),三者支持的数值范围不同。若尝试存储超出允许范围的值,将会触发错误。
integer 类型是最常用的选择,因为它在数值范围、存储大小和性能之间实现了最佳平衡。smallint 类型通常仅在磁盘空间极其紧张时使用。bigint 类型则专为 integer 类型范围不足的场景设计。
SQL 标准仅规定了 integer(或 int)、smallint 和 bigint 这三种整数类型。int2、int4 和 int8 属于扩展类型名,部分其他 SQL 数据库系统也会使用这些名称。
任意精度数字
numeric 类型可以存储具有极大位数的数字。它特别推荐用于存储货币金额以及其他要求精确性的数值。对 numeric 类型的数值进行计算时,在可行的情况下会得到精确结果,例如加法、减法和乘法。但是,与整数类型或浮点类型相比,numeric 类型的计算速度非常慢。
- numeric 类型的精度(precision) 是指整个数字中有效数字的总位数,即小数点左右两侧的数字位数之和。
- numeric 类型的标度(scale) 是指小数部分(小数点右侧)的数字位数。
因此,数字 23.5141 的精度为 6,标度为 4。整数可以被认为标度为 0。
可以指定 numeric 类型列的最大精度和最大标度。声明 numeric 类型列的语法如下:
- NUMERIC(precision, scale)
- NUMERIC(precision) 选取的标度为 0
精度必须为正数,而标度可以是正数或负数。
不指定任何精度和标度时,会创建一个 无约束 numeric ,可以存储任意长度的数值,直到达到系统实现的上限。这类列不会将输入值强制转换为某个固定标度,而声明了标度的 numeric 列则会将输入值强制转换为该标度。如果关心可移植性,应始终显式指定精度和标度。
在 numeric 类型声明中可显式指定的最大精度为 1000。无约束的 numeric 列受前表 中所述限制的约束。
如果要存储的数值其标度大于列的声明标度,系统会将该数值四舍五入到指定的小数位数。如果小数点左侧的位数超过声明精度减去声明标度,则会抛出错误。
例如NUMERIC(3, 1),将数值四舍五入到 1 位小数,并且可以存储 ** 介于 -99.9 到 99.9 之间(包含端点)** 的数值。
从 PostgreSQL 15 开始,允许声明标度为负数的 numeric 类型列。此时数值会向小数点左侧进行四舍五入。精度仍然表示未被舍入的最大数字位数。
例如 NUMERIC(2, -3),将数值四舍五入到最接近的千位,并且可以存储 ** 介于 -99000 到 99000 之间(包含端点)** 的数值。 该数值必须保留到"千位",且总共只能有 2 位有效数字。
-
Scale = -3:意味着数值必须舍入到 103103 (1000) 的倍数。小数点后不仅没有数字,连个位、十位、百位都必须是 0。
-
Precision = 2:意味着在舍入后,整个数字中非零的有效数字最多只能有 2 位。
例如NUMERIC(3, 5),将数值四舍五入到小数点后 5 位,并且可以存储 介于 -0.00999 到 0.00999 之间(包含端点 的数值。
PostgreSQL 允许在 numeric 类型声明中,标度可以是 -1000 到 1000 范围内的任意值。但是,SQL 标准要求标度必须在 0 到精度 之间。使用超出该范围的标度,可能无法在其他数据库系统上兼容移植。
numeric 类型的数值在物理存储时不会保留任何前导零和末尾零。因此,列所声明的精度和标度是最大值,而非固定分配的空间。(从这个意义上说,numeric 类型更接近于 varchar (n),而非 char (n)。)实际的存储需求为:每 4 个十进制数字占用 2 字节,外加 3 到 8 字节的额外开销。
除普通数值外,numeric 类型还支持以下几个特殊值:
- Infinity
- -Infinity
- NaN
这些值改编自 IEEE 754 标准,分别表示 "无穷大"(infinity)、"负无穷大"(negative infinity)和 "非数值"(not-a-number,NaN)。在 SQL 命令中将这些值作为常量书写时,必须给它们加上引号,例如 UPDATE table SET x = '-Infinity'。输入时,这些字符串的识别不区分大小写。无穷大值也可简写为 inf 和 -inf。
无穷大值的行为符合数学预期。例如,无穷大加上任何有限值仍等于无穷大 ,无穷大加上无穷大也是如此;但无穷大减去无穷大会得到 NaN(非数值),因为它没有明确定义的含义。注意:无穷大只能存储在无约束的 numeric 列中,因为它在概念上超出了任何有限的精度限制。
NaN(非数值)用于表示未定义的运算结果。一般情况下,任何包含 NaN 的运算都会得到 NaN。不过这里有一个唯一的例外:当运算的其他输入满足这样一个条件------即无论用什么样的有限数值或无限数值去替换那个 NaN,得到的输出结果都是一样的;在这种情况下,NaN 的运算结果也就直接采用那个输出值。(例如:NaN 的 0 次方结果为 1,就是这条规则的体现。)
在 "非数值(NaN)" 概念的大多数实现中,NaN 与任何其他数值(包括其自身)都不相等。为了让数值能够被排序并用于基于树的索引,PostgreSQL 将所有 NaN 值视为彼此相等,且大于所有非 NaN 数值。
decimal 类型和 numeric 类型是等价的。这两种类型都属于 SQL 标准的一部分。
在对数值进行舍入时,numeric 类型会将"中间值"情况向远离零的方向舍入;而 real 和 double precision 类型(在大多数机器上)则会将"中间值"情况舍入到最近的偶数。
- numeric 类型(银行家舍入法的反面)
规则:向远离零的方向 。
例子:1.5 会变成 2,2.5 也会变成 3(总是进位)。 - real / double precision 类型(银行家舍入法)
规则:向最近的偶数舍入 。
例子:1.5 会变成 2(因为 2 是偶数),但 2.5 也会变成 2(因为 2 是偶数,离它最近的偶数就是 2)。
这种差异主要是由于 numeric 通常用于精确计算(如财务),而 real/double 是二进制浮点数,遵循 IEEE 754 标准。