整数类型
类型 TINYINT
、SMALLINT
、INTEGER
、BIGINT
和 HUGEINT
存储各种范围的整数,即不带小数部分的数字。尝试存储超出允许范围的值将导致错误。类型 UTINYINT
、USMALLINT
、UINTEGER
、UBIGINT
和 UHUGEINT
存储无符号整数。尝试存储负数或超出允许范围的值将导致错误。
名称 | 别名 | 最小值 | 最大值 | 字节大小 |
---|---|---|---|---|
TINYINT |
INT1 |
- 2^7 | 2^7 - 1 | 1 |
SMALLINT |
INT2 , INT16 , SHORT |
- 2^15 | 2^15 - 1 | 2 |
INTEGER |
INT4 , INT32 , INT , SIGNED |
- 2^31 | 2^31 - 1 | 4 |
BIGINT |
INT8 , INT64 , LONG |
- 2^63 | 2^63 - 1 | 8 |
HUGEINT |
INT128 |
- 2^127 | 2^127 - 1 | 16 |
UTINYINT |
UINT8 |
0 | 2^8 - 1 | 1 |
USMALLINT |
UINT16 |
0 | 2^16 - 1 | 2 |
UINTEGER |
UINT32 |
0 | 2^32 - 1 | 4 |
UBIGINT |
UINT64 |
0 | 2^64 - 1 | 8 |
UHUGEINT |
UINT128 |
0 | 2^128 - 1 | 16 |
整数类型是常见的选择,因为它在范围、存储大小和性能之间提供了最佳平衡。SMALLINT
类型通常仅在磁盘空间非常宝贵时使用。BIGINT
和 HUGEINT
类型旨在用于整数类型范围不足的情况。
可变整数
前面提到的整数类型都有一个共同点,即最小值和最大值范围内的数字都具有相同的存储大小,UTINYINT
为 1 字节,SMALLINT
为 2 字节等。但有时您需要比 HUGEINT
支持的数字更大的数字!对于这些情况,VARINT
类型会派上用场,因为 VARINT
类型具有大得多的限制(该值最多可包含 1,262,612 位数字)。VARINT
的最小存储大小为 4 字节,每位数字占用一个额外位,向上取整到 8(12 位占用 12 位,向上取整到 16,变为两个额外字节)。
VARINT
类型支持负值和正值。
定点小数
数据类型 DECIMAL(WIDTH, SCALE)
(也可用别名 NUMERIC(WIDTH, SCALE)
)表示一个精确的定点小数。创建 DECIMAL
类型的值时,可以指定 WIDTH
和 SCALE
来定义字段中可以存储的小数值大小。WIDTH
字段确定可以容纳多少位数字,scale
确定小数点后的位数。例如,类型 DECIMAL(3, 2)
可以容纳值 1.23
,但不能容纳值 12.3
或值 1.234
。如果未指定,默认的 WIDTH
和 SCALE
为 DECIMAL(18, 3)
。
两个定点小数的加法、减法和乘法会返回另一个定点小数,其 WIDTH
和 SCALE
满足包含精确结果的要求,如果所需的 WIDTH
超过当前支持的最大 WIDTH
(目前为 38),则会抛出错误。
定点小数的除法通常不会产生有限小数位数的数字。因此,DuckDB 对所有涉及定点小数的除法都使用近似浮点运算,并相应地返回浮点数据类型。
在内部,小数根据其指定的 WIDTH
表示为整数。
宽度 | 内部 | 大小(字节) |
---|---|---|
1-4 | INT16 |
2 |
5-9 | INT32 |
4 |
10-18 | INT64 |
8 |
19-38 | INT128 |
16 |
在不需要的情况下使用过大的小数可能会影响性能。特别是宽度超过 19 的小数,其运算速度会很慢,因为涉及 INT128
类型的算术运算比涉及 INT32
或 INT64
类型的运算昂贵得多。因此,建议将 WIDTH
保持在 18
或以下,除非有充分的理由说明这不足够。
浮点类型
数据类型 FLOAT
和 DOUBLE
精度是可变精度的数值类型。在实践中,这些类型通常是 IEEE 标准 754 二进制浮点算术(分别为单精度和双精度)的实现,具体取决于底层处理器、操作系统和编译器的支持程度。
名称 | 别名 | 描述 |
---|---|---|
FLOAT |
FLOAT4 , REAL |
单精度浮点数(4 字节) |
DOUBLE |
FLOAT8 |
双精度浮点数(8 字节) |
与定点数据类型类似,从字面量转换或从其他数据类型转换为浮点类型时,无法精确表示的输入将存储为近似值。然而,更难预测哪些输入会受到影响。例如,1.3::DECIMAL(1, 0) - 0.7::DECIMAL(1, 0) != 0.6::DECIMAL(1, 0)
并不令人惊讶,但 1.3::FLOAT - 0.7::FLOAT != 0.6::FLOAT
可能会令人惊讶。
此外,虽然定点小数数据类型的乘法、加法和减法是精确的,但这些运算在浮点二进制数据类型上仅是近似的。
然而,对于更复杂的数学运算,内部使用浮点算术,如果中间步骤不转换为与输入和输出相同宽度的定点格式,则可以获得更精确的结果。例如,(10::FLOAT / 3::FLOAT)::FLOAT * 3 = 10
,而 (10::DECIMAL(18, 3) / 3::DECIMAL(18, 3))::DECIMAL(18, 3) * 3 = 9.999
。
总的来说,我们建议:
- 如果您需要精确存储具有已知小数位数的数字,并且需要精确的加法、减法和乘法(例如对于货币金额),请使用
DECIMAL
数据类型或其NUMERIC
别名。 - 如果您想进行快速或复杂的计算,浮点数据类型可能更合适。但是,如果您将结果用于任何重要用途,则应仔细评估您的实现中的边缘情况(范围、无穷大、下溢、无效操作),这些情况的处理方式可能与您预期不同,并且您应该熟悉常见的浮点陷阱。David Goldberg 的文章 “每个计算机科学家都应该了解的浮点算术” 和 Bruce Dawson 博客上的浮点系列提供了很好的起点。
在大多数平台上,FLOAT
类型的范围至少为 1E-37 到 1E+37,精度至少为 6 位小数。DOUBLE
类型的范围通常约为 1E-307 到 1E+308,精度至少为 15 位。超出这些范围的正数(以及超出镜像范围的负数)在某些平台上可能会导致错误,但通常会分别转换为零或无穷大。
除了普通数值之外,浮点类型还有几个表示 IEEE 754 特殊值的特殊值:
Infinity
: 无穷大-Infinity
: 负无穷大NaN
: 非数字
在具有所需 CPU/FPU 支持的机器上,DuckDB 遵循 IEEE 754 规范中关于这些特殊值的规定,但有两个例外:
NaN
与NaN
比较相等,并大于任何其他浮点数。- 某些浮点函数,如
sqrt
/sin
/asin
,对于超出其定义范围的值会抛出错误,而不是返回NaN
。
要将这些值作为字面量插入 SQL 命令中,您必须给它们加上引号,您可以将 Infinity
缩写为 Inf
,并且可以使用任何大小写。例如:
SELECT
sqrt(2) > '-inf',
'nan' > sqrt(2);
(sqrt(2) > '-inf') |
('nan' > sqrt(2)) |
---|---|
true | true |
通用唯一标识符(UUID
)
DuckDB 通过 UUID
类型支持通用唯一标识符 (UUID)。这些标识符使用 128 位,并在内部表示为 HUGEINT
值。打印时,它们以小写十六进制字符显示,并用连字符分隔,如下所示:12345678-1234-1234-1234-1234567890ab
(总共 36 个字符,包括连字符)。例如,4ac7a9e9-607c-4c8a-84f3-843f0191e3fd
是一个有效的 UUID。
DuckDB 支持生成 UUIDv4 和 UUIDv7 标识符。要检索 UUID 值的版本,请使用 uuid_extract_version
函数。
UUIDv4
要生成 UUIDv4 值,请使用 uuid()
函数或其别名 uuidv4()
和 gen_random_uuid()
函数。
UUIDv7
要生成 UUIDv7 值,请使用 uuidv7()
函数。要从 UUIDv7 值中检索时间戳,请使用 uuid_extract_timestamp
函数
SELECT uuid_extract_timestamp(uuidv7()) AS ts;
ts |
---|
2025-04-19 15:51:20.07+00 |
函数
参阅数值函数和运算符。