DECIMAL
数据类型用来存储高精度数值数据,在其他数据库也被称为 NUMERIC
。DECIMAL
数据类型的基本运算返回的是精确结果,适用于需要精确计算的场景,如金融数据、货币计算等。
相比于浮点数类型(FLOAT、DOUBLE),DECIMAL
类型:
DECIMAL
数据类型中有两个重要术语:
PRECISION
最大值为 MAX_PRECISION
。SCALE
必须小于等于指定的 PRECISION
值,且 SCALE
最大值为 MAX_SCALE
。定义一个 DECIMAL(4,2)
数据类型:
[-99.99, 99.99]
DECIMAL UNSIGNED
MAX_PRECISION
值为 38
,MAX_SCALE
值也为 38
(采用 ClickHouse 中 Decimal128 相同行为)DECIMAL(precision, scale) -- 完整格式
DECIMAL(precision) -- scale 默认为 0
precision
:必须为正整数,取值范围 [1, MAX_PRECISION]
scale
:必须为非负整数,取值范围 [0, min(MAX_SCALE, precision)]
scale
时,默认为 0,即只表示整数precision
等于 scale
,则只能表示 (-1,1)
范围内的值-- 创建表使用 DECIMAL 类型
CREATE TABLE financial_data (
ts TIMESTAMP,
amount DECIMAL(10,2), -- 10位精度,2位小数
rate DECIMAL(5,4), -- 5位精度,4位小数
count DECIMAL(8) -- 8位精度,0位小数(整数)
);
Decimal64
或 Decimal128
进行存储Decimal64
:8字节,最大精度18位Decimal128
:16字节,最大精度38位注意:不支持 precision
和 scale
都不指定的方式定义 DECIMAL 类型。
DECIMAL 类型数据可以通过多种方式插入:
-- 插入数值,不会降低精度
INSERT INTO financial_data VALUES (NOW(), 123.45, 0.1250, 1000);
-- 插入字符串格式的数值
INSERT INTO financial_data VALUES (NOW(), '999.99', '0.9999', '99999999');
-- 支持科学计数法,形如 1E-37 即 1×10^(-37)
INSERT INTO financial_data VALUES (NOW(), 1.23E2, 1.5e-3, 1E6);
当插入数值的 scale
高于列定义的 scale
时,会进行四舍五入:
-- 列定义为 DECIMAL(3,1)
INSERT INTO test_table VALUES (0.11); -- 实际存储为 0.1
当插入的数值超出精度范围时,会报 Decimal field overflow
错误:
-- 列定义为 DECIMAL(3,1),有效范围 [-99.9, 99.9]
INSERT INTO test_table VALUES (100.1); -- 报错:Decimal field overflow
查询结果的显示格式受 DECIMAL 的 PRECISION
和 SCALE
控制:
-- 对于 DECIMAL(5,2) 列
SELECT amount FROM financial_data; -- 值 2.3 显示为 2.30
查询中的数值常量使用整数或 DOUBLE 类型解释,不会自动解释为 DECIMAL 类型。如需使用 DECIMAL 类型,可以手动进行类型转换:
-- 常量被解释为 DOUBLE
SELECT 3.14159 + amount FROM financial_data;
-- 手动转换为 DECIMAL
SELECT CAST(3.14159 AS DECIMAL(10,5)) + amount FROM financial_data;
DECIMAL 类型支持的基本运算符:+
、-
、*
、/
、%
、>
、>=
、<
、<=
、=
、!=
运算类型 | 运算符 | 输出类型 | Scale 规则 |
---|---|---|---|
decimal + decimal | + | DECIMAL | max(S1, S2) |
decimal - decimal | - | DECIMAL | max(S1, S2) |
decimal * decimal | * | DECIMAL | MIN(MAX_SCALE, S1 + S2) |
decimal / decimal | / | DECIMAL | S1 |
decimal op float/double | +,-,*,/ | DOUBLE | - |
decimal op integer | +,-,*,/ | DECIMAL | - |
DECIMAL 类型作为数值类型,在与其他数值类型比较时,遵循数值比较规则:
-- 以下比较结果为 true
SELECT 1.1000::DECIMAL(5,4) = 1.1::DECIMAL(3,1); -- DECIMAL 之间
SELECT 123::DECIMAL(3,0) = 123; -- DECIMAL 与整数
SELECT 1.11::DECIMAL(3,2) = 1.11::FLOAT; -- DECIMAL 与浮点数
MAX_PRECISION
时可表示的最大值,则报 overflow
错误MAX_PRECISION - SCALE
,则自动截断,减小 SCALE
操作符两侧不同类型字段计算时的转换规则:
源类型 | 目标类型 | 说明 |
---|---|---|
NULL | NULL | 保持 NULL |
BOOL/TINYINT/SMALLINT/INT/BIGINT | DECIMAL | 整数类型转换为 DECIMAL |
UTINYINT/USMALLINT/UINT/UBIGINT | DECIMAL | 无符号整数转换为 DECIMAL |
FLOAT/DOUBLE | DOUBLE | 浮点数运算结果为 DOUBLE |
VARCHAR/TIMESTAMP | DECIMAL | 字符串和时间戳转换为 DECIMAL |
NCHAR/BINARY | DOUBLE | 转换为 DOUBLE |
JSON/VARBINARY/GEOMETRY | 错误 | 不支持转换 |
DECIMAL 类型支持的函数及其返回类型:
函数 | 返回类型 | 说明 |
---|---|---|
ABS(decimal) | DECIMAL | 绝对值 |
ROUND(decimal) | DECIMAL | 四舍五入 |
FLOOR(decimal) | DECIMAL | 向下取整 |
CEIL(decimal) | BIGINT | 向上取整 |
ACOS/ASIN/ATAN/COS/SIN/TAN | DOUBLE | 三角函数 |
LOG/POW/SQRT | DOUBLE | 对数、幂、平方根 |
函数 | 返回类型 | 说明 |
---|---|---|
SUM(decimal) | DECIMAL | 求和 |
AVG(decimal) | DECIMAL | 平均值 |
MAX(decimal) | DECIMAL | 最大值 |
MIN(decimal) | DECIMAL | 最小值 |
COUNT(decimal) | BIGINT | 计数 |
函数 | 返回类型 | 说明 |
---|---|---|
FIRST(decimal) | DECIMAL | 首个值 |
LAST(decimal) | DECIMAL | 最后值 |
APERCENTILE(decimal, p) | DECIMAL | 百分位数 |
PERCENTILE(decimal, p) | DECIMAL | 百分位数 |
SPREAD(decimal) | DECIMAL | 极差 |
函数 | 返回类型 | 说明 |
---|---|---|
CSUM(decimal) | DECIMAL | 累积和 |
DERIVATIVE(decimal) | DECIMAL | 导数 |
DIFF(decimal) | DECIMAL | 差分 |
MAVG(decimal, k) | DECIMAL | 移动平均 |
IRATE(decimal) | DOUBLE | 瞬时速率 |
TWA(decimal) | DOUBLE | 时间加权平均 |
函数 | 返回类型 | 说明 |
---|---|---|
STDDEV(decimal) | DOUBLE | 标准差 |
HISTOGRAM(decimal, bins) | DOUBLE/BIGINT | 直方图 |
HYPERLOGLOG(decimal) | INTEGER | 基数估计 |
-- CAST 函数支持
SELECT CAST(123.456 AS DECIMAL(10,2)); -- 结果: 123.46
SELECT CAST('999.99' AS DECIMAL(8,2)); -- 结果: 999.99
SELECT CAST(column1 AS DECIMAL(15,4)) FROM t1; -- 类型转换
-- 创建包含 DECIMAL 类型的表
CREATE TABLE finance_records (
ts TIMESTAMP,
account_id INT,
amount DECIMAL(15,2), -- 金额:15位精度,2位小数
rate DECIMAL(8,6), -- 利率:8位精度,6位小数
balance DECIMAL(20,2), -- 余额:20位精度,2位小数
quantity DECIMAL(10,0) -- 数量:10位精度,0位小数(整数)
);
-- 插入数据
INSERT INTO finance_records VALUES
(NOW(), 1001, 1234.56, 0.025000, 10000.00, 100),
(NOW(), 1002, 2345.67, 0.030000, 25000.00, 200),
(NOW(), 1003, 3456.78, 0.035000, 50000.00, 300);
-- 基本查询
SELECT account_id, amount, rate, balance FROM finance_records;
-- 计算利息
SELECT
account_id,
amount,
rate,
amount * rate AS interest,
balance + amount * rate AS new_balance
FROM finance_records;
-- 聚合统计
SELECT
SUM(amount) AS total_amount,
AVG(rate) AS avg_rate,
MAX(balance) AS max_balance,
MIN(balance) AS min_balance
FROM finance_records;
-- 条件查询
SELECT * FROM finance_records
WHERE amount > 2000.00 AND rate >= 0.030000;
-- 创建不同精度的表
CREATE TABLE precision_test (
ts TIMESTAMP,
small_decimal DECIMAL(5,2), -- 范围:-999.99 to 999.99
medium_decimal DECIMAL(10,4), -- 范围:-999999.9999 to 999999.9999
large_decimal DECIMAL(18,6) -- 范围:-999999999999.999999 to 999999999999.999999
);
-- 插入测试数据
INSERT INTO precision_test VALUES
(NOW(), 123.45, 1234.5678, 123456789.123456),
(NOW(), 999.99, 999999.9999, 999999999999.999999);
-- 精度截断示例
INSERT INTO precision_test VALUES
(NOW(), 123.456, 1234.56789, 123456789.1234567);
-- 实际存储为:123.46, 1234.5679, 123456789.123457(四舍五入)
-- 字符串转 DECIMAL
SELECT CAST('12345.67' AS DECIMAL(10,2)) AS decimal_value;
-- 整数转 DECIMAL
SELECT CAST(12345 AS DECIMAL(10,2)) AS decimal_value;
-- DECIMAL 转字符串
SELECT CAST(amount AS VARCHAR(20)) AS amount_str FROM finance_records;
-- 混合类型计算
SELECT
amount,
CAST(amount AS FLOAT) AS amount_float,
amount + 100 AS amount_plus_int,
amount * 1.1 AS amount_times_float -- 结果为 DOUBLE
FROM finance_records;
使用 C API 的 taos_fetch_row
查询 DECIMAL 类型数据时,该列数据会被转换为字符串类型返回:
// 查询 DECIMAL 类型数据
TAOS_RES *res = taos_query(taos, "SELECT amount FROM finance_records");
TAOS_ROW row;
while ((row = taos_fetch_row(res)) != NULL) {
// DECIMAL 列作为字符串读取
char *amount_str = (char *)row[0];
printf("Amount: %s\n", amount_str);
}
调用 taos_fetch_raw_block
接口时,Raw Block 内结构保持不变:
DECIMAL64
:8字节定长字段DECIMAL128
:16字节定长字段字段 | 长度 | 说明 |
---|---|---|
bytes | 1字节 | 所需大小(8/16) |
empty | 1字节 | 保留字段 |
precision | 1字节 | 精度值 |
scale | 1字节 | 标度值 |
Decimal64 解析:
// 8字节数据转换为 int64_t
int64_t decimal64_value = *(int64_t*)data;
// 根据 scale 计算实际值
double actual_value = (double)decimal64_value / pow(10, scale);
Decimal128 解析:
// 16字节数据转换为 int128(小端序)
// 需要自定义 int128 处理或使用库函数
// 根据 scale 计算实际值
各语言连接器对 DECIMAL 类型的支持:
连接器 | 支持状态 | 返回类型 | 说明 |
---|---|---|---|
Java | 支持 | BigDecimal | 完整精度支持 |
Python | 支持 | Decimal | 使用 decimal 模块 |
Go | 支持 | string | 字符串形式返回 |
Node.js | 支持 | string | 字符串形式返回 |
C# | 支持 | decimal | .NET Decimal 类型 |
Rust | 支持 | string | 字符串形式返回 |
# 查看表结构
taos> DESC finance_records;
# 输出示例:
# amount | DECIMAL(15,2) | ...
# 查询数据
taos> SELECT amount FROM finance_records;
# 输出格式按照 DECIMAL 定义的精度显示
taosBenchmark 支持 DECIMAL 类型的性能测试:
# 创建包含 DECIMAL 类型的测试表
taosbenchmark -P 6030 -d test_db -t 10 -n 100000 \
--columns "amount DECIMAL(15,2),rate DECIMAL(8,6)"
DECIMAL 类型相比于其他数值类型的性能特性:
操作类型 | DECIMAL | INT/BIGINT | FLOAT/DOUBLE | 性能比较 |
---|---|---|---|---|
插入 | 正常 | 最快 | 快 | DECIMAL < FLOAT < INT |
查询 | 正常 | 最快 | 快 | DECIMAL < FLOAT < INT |
运算 | 慢 | 最快 | 快 | DECIMAL 比其他类型慢 30-50% |
聚合 | 慢 | 最快 | 快 | DECIMAL 比其他类型慢 30-50% |
DECIMAL 类型特别适合以下场景:
金融系统
科学计算
商业应用
-- 金融应用示例
CREATE TABLE account_transactions (
ts TIMESTAMP,
account_id BIGINT,
transaction_type VARCHAR(20),
amount DECIMAL(18,2), -- 交易金额
balance DECIMAL(20,2), -- 账户余额
exchange_rate DECIMAL(10,6), -- 汇率
fee DECIMAL(8,4) -- 手续费
);
-- 科学数据示例
CREATE TABLE sensor_data (
ts TIMESTAMP,
sensor_id INT,
temperature DECIMAL(6,3), -- 温度(精确到千分位)
pressure DECIMAL(8,2), -- 压力
humidity DECIMAL(5,2), -- 湿度
coordinate_x DECIMAL(15,8), -- 坐标(高精度)
coordinate_y DECIMAL(15,8)
);
以下场景不建议使用 DECIMAL 类型:
MAX_PRECISION = 38
(最大精度)MAX_SCALE = 38
(最大标度)SCALE ≤ PRECISION
(标度不能超过精度)precision
和 scale
根据精度和标度的不同,DECIMAL 类型的数值范围如下:
精度 | 标度 | 数值范围示例 |
---|---|---|
DECIMAL(3,0) | 0 | -999 to 999 |
DECIMAL(3,1) | 1 | -99.9 to 99.9 |
DECIMAL(5,2) | 2 | -999.99 to 999.99 |
DECIMAL(10,4) | 4 | -999999.9999 to 999999.9999 |
DECIMAL(18,6) | 6 | -999999999999.999999 to 999999999999.999999 |
-- 错误示例
CREATE TABLE test (id INT, amount DECIMAL(5,2));
INSERT INTO test VALUES (1, 12345.67); -- 错误:Decimal field overflow
解决方案:增加精度或减少数值大小
-- 错误示例
SELECT amount + 'abc' FROM test; -- 错误:Invalid type conversion
解决方案:确保参与运算的数据类型兼容
-- 错误示例
CREATE TABLE test (amount DECIMAL(5,6)); -- 错误:Scale 不能大于 Precision
解决方案:确保 scale ≤ precision
问题:DECIMAL 类型计算比其他数值类型慢
解决方案:
建议:
问题:插入时精度超出定义范围
解决方案:
如遇到 DECIMAL 类型相关问题,请: