
CAST 函数
函数概述
功能说明: 数据类型转换函数,将指定的表达式转换为目标数据类型。
版本: 全版本支持
返回结果类型: 由 CAST 中指定的目标类型决定。
适用数据类型: 除 JSON 和 VARBINARY 类型外的所有数据类型。当目标类型为 VARBINARY 时,输入只能是 VARCHAR 类型。
嵌套子查询支持: 适用于内层查询和外层查询。
适用于: 表和超级表。
语法
sql
CAST(expr AS type_name[(length[,precision])])
参数说明:
expr: 要转换的表达式,可以是列名、常量、函数结果或复合表达式type_name: 目标数据类型length: 字符串类型的长度(可选)precision: DECIMAL 类型的精度(可选)
支持的类型转换
数值类型转换
| 源类型 | 目标类型 | 说明 |
|---|---|---|
| TINYINT/SMALLINT/INT/BIGINT | TINYINT/SMALLINT/INT/BIGINT | 支持,可能溢出 |
| FLOAT/DOUBLE | TINYINT/SMALLINT/INT/BIGINT | 支持,截断小数部分 |
| 数值类型 | FLOAT/DOUBLE | 支持,可能精度损失 |
| 数值类型 | DECIMAL(M,N) | 支持,M≤38,N≤M |
| 字符串 | 数值类型 | 支持,无效字符转为 0 |
字符串类型转换
| 源类型 | 目标类型 | 说明 |
|---|---|---|
| VARCHAR | NCHAR | 支持 |
| NCHAR | VARCHAR | 支持 |
| 数值类型 | VARCHAR(N)/NCHAR(N) | 支持,N≤4096 |
| TIMESTAMP | VARCHAR(N)/NCHAR(N) | 支持,转为 ISO8601 格式 |
| VARCHAR | VARBINARY | 支持,仅此方向 |
时间类型转换
| 源类型 | 目标类型 | 说明 |
|---|---|---|
| TIMESTAMP | BIGINT | 支持,输出时间戳数值 |
| BIGINT | TIMESTAMP | 支持,按数据库精度解析 |
| VARCHAR/NCHAR | TIMESTAMP | 支持,需符合 ISO8601 格式 |
布尔类型转换
| 源类型 | 目标类型 | 说明 |
|---|---|---|
| BOOL | TINYINT/SMALLINT/INT/BIGINT | true→1, false→0 |
| 数值类型 | BOOL | 非 0→true, 0→false |
使用说明
类型转换规则
- 溢出处理: 转换到数值类型时,若超出范围会溢出,但不报错
- 截断处理: 转换到字符串类型时,若超出指定长度会截断,但不报错
- 精度损失: 浮点数转整数会丢失小数部分,无四舍五入
- 无效转换: 字符串转数值时,无效字符可能转为 0
字符串长度限制
- VARCHAR/NCHAR 的
length参数不能超过 4096 字节 - 长度参数必须大于 0
- 不指定长度时使用默认值
DECIMAL 类型限制
- 不支持与 JSON、VARBINARY、GEOMETRY 类型互转
- precision (M) 范围: 1-38
- scale (N) 范围: 0-M
时间精度
- 函数会自动添加数据库精度作为参数
- TIMESTAMP 转换受客户端时区影响
智能电表示例环境搭建
1. 创建数据库
sql
-- 创建数据库,设置精度为毫秒
CREATE DATABASE power PRECISION 'ms';
-- 使用数据库
USE power;
2. 创建超级表
sql
-- 创建智能电表超级表
CREATE STABLE meters (
ts TIMESTAMP, -- 时间戳
current FLOAT, -- 电流 (A)
voltage FLOAT, -- 电压 (V)
phase FLOAT -- 相位
) TAGS (
groupid INT, -- 分组ID
location VARCHAR(24) -- 地理位置
);
3. 创建子表并插入数据
sql
-- 创建加州的电表
CREATE TABLE d1001 USING meters TAGS (1, 'California');
CREATE TABLE d1002 USING meters TAGS (1, 'California');
-- 创建纽约的电表
CREATE TABLE d1003 USING meters TAGS (2, 'New York');
CREATE TABLE d1004 USING meters TAGS (2, 'New York');
-- 创建德州的电表
CREATE TABLE d1005 USING meters TAGS (3, 'Texas');
-- 插入加州电表数据
INSERT INTO d1001 VALUES
('2024-01-15 14:00:00.000', 10.2, 220.5, 0.31),
('2024-01-15 14:05:00.000', 10.3, 220.1, 0.32),
('2024-01-15 14:10:00.000', 10.5, 219.8, 0.33),
('2024-01-15 14:15:00.000', 11.2, 220.3, 0.31),
('2024-01-15 14:20:00.000', 12.1, 221.2, 0.30),
('2024-01-15 14:25:00.000', 12.6, 218.4, 0.35),
('2024-01-15 14:30:00.000', 10.3, 219.5, 0.32);
INSERT INTO d1002 VALUES
('2024-01-15 14:00:00.000', 9.8, 221.0, 0.30),
('2024-01-15 14:05:00.000', 10.1, 220.8, 0.31),
('2024-01-15 14:10:00.000', 10.4, 220.5, 0.32),
('2024-01-15 14:15:00.000', 10.8, 220.2, 0.33),
('2024-01-15 14:20:00.000', 11.5, 219.9, 0.34),
('2024-01-15 14:25:00.000', 11.0, 220.1, 0.33),
('2024-01-15 14:30:00.000', 10.5, 220.4, 0.32);
-- 插入纽约电表数据
INSERT INTO d1003 VALUES
('2024-01-15 14:00:00.000', 11.5, 218.5, 0.28),
('2024-01-15 14:05:00.000', 11.8, 219.0, 0.29),
('2024-01-15 14:10:00.000', 12.2, 208.1, 0.30),
('2024-01-15 14:15:00.000', 12.8, 232.5, 0.31),
('2024-01-15 14:20:00.000', 13.2, 219.8, 0.32),
('2024-01-15 14:25:00.000', 12.9, 220.2, 0.31),
('2024-01-15 14:30:00.000', 12.3, 220.8, 0.30);
INSERT INTO d1004 VALUES
('2024-01-15 14:00:00.000', 10.9, 221.5, 0.29),
('2024-01-15 14:05:00.000', 11.2, 221.2, 0.30),
('2024-01-15 14:10:00.000', 11.6, 220.9, 0.31),
('2024-01-15 14:15:00.000', 12.0, 220.6, 0.32),
('2024-01-15 14:20:00.000', 12.5, 220.3, 0.33),
('2024-01-15 14:25:00.000', 12.1, 220.5, 0.32),
('2024-01-15 14:30:00.000', 11.7, 220.8, 0.31);
-- 插入德州电表数据
INSERT INTO d1005 VALUES
('2024-01-15 14:00:00.000', 13.5, 217.2, 0.27),
('2024-01-15 14:05:00.000', 14.0, 217.8, 0.28),
('2024-01-15 14:10:00.000', 14.5, 218.5, 0.29),
('2024-01-15 14:15:00.000', 15.0, 219.0, 0.30),
('2024-01-15 14:20:00.000', 15.5, 222.3, 0.31),
('2024-01-15 14:25:00.000', 15.0, 219.8, 0.30),
('2024-01-15 14:30:00.000', 14.5, 220.2, 0.29);
智能电表应用场景
场景一: SELECT 子句中的基础类型转换
用途: 查询结果的类型转换
sql
-- 1. 数值类型转换: 电流值从浮点转整数
SELECT
ts,
location,
CAST(current AS BIGINT) AS current_int,
CAST(voltage AS INT) AS voltage_int
FROM meters
WHERE ts >= '2024-01-15 14:00:00'
ORDER BY ts DESC
LIMIT 10;
输出示例:
ts | location | current_int | voltage_int |
========================================================================
2024-01-15 14:30:00.000 | Texas | 14 | 220 |
2024-01-15 14:30:00.000 | New York | 11 | 220 |
2024-01-15 14:30:00.000 | New York | 12 | 220 |
2024-01-15 14:30:00.000 | California | 10 | 220 |
2024-01-15 14:30:00.000 | California | 10 | 219 |
说明:
current为 FLOAT 类型,转换为 BIGINT 后小数部分被截断voltage同样从 FLOAT 转为 INT,方便按整数进行告警判断
场景二: WHERE 子句中的类型转换
用途: 条件判断中统一数据类型
sql
-- 查询电流整数部分大于 12 的记录
SELECT
ts,
location,
current,
voltage
FROM meters
WHERE CAST(current AS INT) > 12
AND ts >= '2024-01-15 14:00:00'
ORDER BY current DESC
LIMIT 5;
-- 查询电压在指定范围的记录(使用 DECIMAL 精确控制)
SELECT
ts,
location,
CAST(voltage AS DECIMAL(5,1)) AS voltage_exact
FROM meters
WHERE CAST(voltage AS DECIMAL(5,1)) BETWEEN 218.0 AND 221.0
LIMIT 10;
输出示例:
ts | location | current | voltage |
========================================================================
2024-01-15 14:20:00.000 | Texas | 15.500000 | 222.300000 |
2024-01-15 14:25:00.000 | Texas | 15.000000 | 219.800000 |
2024-01-15 14:15:00.000 | Texas | 15.000000 | 219.000000 |
2024-01-15 14:10:00.000 | Texas | 14.500000 | 218.500000 |
2024-01-15 14:30:00.000 | Texas | 14.500000 | 220.200000 |
场景三: GROUP BY 子句中的类型转换
用途: 按转换后的类型分组统计
sql
-- 按电流整数值分组统计
SELECT
CAST(current AS INT) AS current_level,
COUNT(*) AS cnt,
AVG(voltage) AS avg_voltage
FROM meters
WHERE ts >= '2024-01-15 14:00:00'
GROUP BY CAST(current AS INT)
ORDER BY current_level;
-- 按日期分组统计(时间戳转日期字符串)
SELECT
CAST(ts AS VARCHAR(10)) AS date,
location,
COUNT(*) AS record_count,
AVG(current) AS avg_current
FROM meters
GROUP BY CAST(ts AS VARCHAR(10)), location
ORDER BY date DESC, location;
输出示例:
current_level | count | avg_voltage |
======================================================
9 | 1 | 221.000000000000000 |
10 | 8 | 220.387500000000000 |
11 | 6 | 220.116666666666674 |
12 | 7 | 219.542857142857139 |
13 | 2 | 218.325000000000017 |
14 | 3 | 218.833333333333314 |
15 | 3 | 220.366666666666674 |
date | location | record_count | avg_current |
=======================================================================
2024-01-15 | California | 7 | 11.014285714285715 |
2024-01-15 | New York | 7 | 12.028571428571429 |
2024-01-15 | Texas | 7 | 14.571428571428571 |
场景四: ORDER BY 子句中的类型转换
用途: 按转换后的值排序
sql
-- 按电压转换为 DECIMAL 后排序
SELECT
ts,
location,
voltage,
CAST(voltage AS DECIMAL(5,2)) AS voltage_decimal
FROM meters
WHERE ts >= '2024-01-15 14:00:00'
ORDER BY CAST(voltage AS DECIMAL(5,2)) DESC
LIMIT 10;
-- 按时间戳转换后的字符串排序
SELECT
CAST(ts AS VARCHAR(64)) AS time_str,
location,
current
FROM meters
WHERE location = 'California'
ORDER BY CAST(ts AS VARCHAR(64)) DESC
LIMIT 5;
输出示例:
ts | location | voltage | voltage_decimal |
===========================================================================
2024-01-15 14:15:00.000 | New York | 232.500000 | 232.50 |
2024-01-15 14:20:00.000 | Texas | 222.300000 | 222.30 |
2024-01-15 14:00:00.000 | New York | 221.500000 | 221.50 |
2024-01-15 14:20:00.000 | California | 221.200000 | 221.20 |
2024-01-15 14:05:00.000 | New York | 221.200000 | 221.20 |
场景五: 聚合函数中的类型转换
用途: 聚合计算前的类型准备
sql
-- 计算功率并控制精度
SELECT
location,
AVG(CAST(current * voltage AS DECIMAL(10,2))) AS avg_power,
MAX(CAST(current * voltage AS DECIMAL(10,2))) AS max_power,
MIN(CAST(current * voltage AS DECIMAL(10,2))) AS min_power
FROM meters
WHERE ts >= '2024-01-15 14:00:00'
GROUP BY location
ORDER BY avg_power DESC;
-- 统计电压范围分布
SELECT
CASE
WHEN CAST(voltage AS DECIMAL(5,1)) < 210.0 THEN 'Low'
WHEN CAST(voltage AS DECIMAL(5,1)) <= 230.0 THEN 'Normal'
ELSE 'High'
END AS voltage_range,
COUNT(*) AS `count`,
AVG(current) AS avg_current
FROM meters
GROUP BY voltage_range
ORDER BY voltage_range;
输出示例:
location | avg_power | max_power | min_power |
===================================================================================
Texas | 3174.22 | 3449.65 | 2932.20 |
New York | 2646.58 | 2977.60 | 2514.25 |
California | 2403.00 | 2752.44 | 2141.64 |
voltage_range | count | avg_current |
========================================================
Low | 2 | 12.400000000000000 |
Normal | 33 | 11.881818181818182 |
High | 0 | NULL |
场景六: 子查询中的类型转换
用途: 内层和外层查询的类型处理
sql
-- 内层查询转换类型,外层查询使用
SELECT
date,
location,
daily_avg
FROM (
SELECT
CAST(ts AS VARCHAR(10)) AS date,
location,
AVG(CAST(current AS DECIMAL(10,2))) AS daily_avg
FROM meters
WHERE ts >= '2024-01-15 00:00:00'
GROUP BY CAST(ts AS VARCHAR(10)), location
) AS daily_stats
WHERE daily_avg > 11.0
ORDER BY date DESC, daily_avg DESC;
-- 嵌套类型转换:统计结果转字符串
SELECT
location,
CONCAT(CAST(max_current AS VARCHAR(20)), 'A') AS max_current_display
FROM (
SELECT
location,
MAX(CAST(current AS INT)) AS max_current
FROM meters
WHERE ts >= '2024-01-15 14:00:00'
GROUP BY location
) AS location_max
ORDER BY max_current_display DESC;
输出示例:
date | location | daily_avg |
=======================================================
2024-01-15 | Texas | 14.57 |
2024-01-15 | New York | 12.03 |
2024-01-15 | California | 11.01 |
location | max_current_display |
======================================
Texas | 15A |
New York | 13A |
California | 12A |
场景七: CASE 表达式中的类型转换
用途: 条件分支中的类型统一
sql
-- 根据电压值返回不同状态描述
SELECT
ts,
location,
voltage,
CASE
WHEN voltage < 210 THEN CONCAT(CAST('Low: ' AS VARCHAR(50)), CAST(voltage AS VARCHAR(20)))
WHEN voltage > 230 THEN CONCAT(CAST('High: ' AS VARCHAR(50)), CAST(voltage AS VARCHAR(20)))
ELSE CONCAT(CAST('Normal: ' AS VARCHAR(50)), CAST(voltage AS VARCHAR(20)))
END AS voltage_status
FROM meters
WHERE ts >= '2024-01-15 14:10:00'
ORDER BY voltage
LIMIT 10;
-- 动态过载判断(布尔转换)
SELECT
location,
CASE
WHEN CAST(AVG(current) AS INT) > 12 THEN CAST(1 AS BOOL)
ELSE CAST(0 AS BOOL)
END AS is_high_load
FROM meters
WHERE ts >= '2024-01-15 14:00:00'
GROUP BY location
ORDER BY is_high_load DESC, location;
输出示例:
ts | location | voltage | voltage_status |
======================================================================================
2024-01-15 14:10:00.000 | New York | 208.100000 | Low: 208.100000 |
2024-01-15 14:00:00.000 | Texas | 217.200000 | Normal: 217.200000 |
2024-01-15 14:05:00.000 | Texas | 217.800000 | Normal: 217.800000 |
2024-01-15 14:25:00.000 | California | 218.400000 | Normal: 218.400000 |
2024-01-15 14:10:00.000 | Texas | 218.500000 | Normal: 218.500000 |
2024-01-15 14:15:00.000 | New York | 232.500000 | High: 232.500000 |
location | is_high_load |
================================
Texas | true |
New York | true |
California | false |
场景八: UNION 操作中的类型转换
用途: 合并不同表时统一列类型
sql
-- 创建一个存储整数电流的表用于演示
CREATE TABLE meters_int (
ts TIMESTAMP,
current INT,
voltage INT,
location VARCHAR(24)
);
INSERT INTO meters_int VALUES
('2024-01-15 16:00:00.000', 10, 220, 'California'),
('2024-01-15 16:05:00.000', 11, 221, 'California');
-- 合并不同精度的数据
SELECT
CAST(ts AS VARCHAR(64)) AS time_str,
location,
CAST(current AS DECIMAL(10,2)) AS current,
CAST(voltage AS DECIMAL(10,2)) AS voltage
FROM meters
WHERE ts >= '2024-01-15 14:30:00'
UNION ALL
SELECT
CAST(ts AS VARCHAR(64)) AS time_str,
location,
CAST(current AS DECIMAL(10,2)) AS current,
CAST(voltage AS DECIMAL(10,2)) AS voltage
FROM meters_int
ORDER BY time_str DESC
LIMIT 10;
输出示例:
time_str | location | current | voltage |
=============================================================================
2024-01-15 16:05:00.000 | California | 11.00 | 221.00 |
2024-01-15 16:00:00.000 | California | 10.00 | 220.00 |
2024-01-15 14:30:00.000 | Texas | 14.50 | 220.20 |
2024-01-15 14:30:00.000 | New York | 11.70 | 220.80 |
2024-01-15 14:30:00.000 | New York | 12.30 | 220.80 |
场景九: 复杂计算表达式中的类型转换
用途: 多步计算中的类型控制
sql
-- 功率计算(精确控制精度)
SELECT
ts,
location,
current,
voltage,
CAST(
CAST(current AS DECIMAL(10,3)) * CAST(voltage AS DECIMAL(10,3))
AS DECIMAL(15,2)
) AS power_watts
FROM meters
WHERE ts >= '2024-01-15 14:20:00'
ORDER BY power_watts DESC
LIMIT 10;
输出示例:
ts | location | current | voltage | power_watts |
====================================================================================
2024-01-15 14:20:00.000 | Texas | 15.500000 | 222.300000 | 3445.65 |
2024-01-15 14:25:00.000 | Texas | 15.000000 | 219.800000 | 3297.00 |
2024-01-15 14:30:00.000 | Texas | 14.500000 | 220.200000 | 3192.90 |
2024-01-15 14:20:00.000 | New York | 13.200000 | 219.800000 | 2901.36 |
2024-01-15 14:25:00.000 | California | 12.600000 | 218.400000 | 2751.84 |
注意事项
-
精度损失: 从高精度类型转换到低精度类型可能导致精度损失
sqlSELECT CAST(10.789 AS INT); -- 结果: 10(截断,非四舍五入) -
溢出处理: 数值类型转换时注意目标类型的取值范围
sqlSELECT CAST(999999999999 AS INT); -- 可能溢出 -
字符串截断: 转换为字符串时若长度不足会发生截断
sqlSELECT CAST(123456789 AS VARCHAR(5)); -- 结果: '12345' -
性能考虑: 频繁的类型转换会影响查询性能
- 建议在数据写入时就使用合适的类型
- 避免在大量数据的 WHERE 条件中使用 CAST
- 对于经常需要转换的字段,考虑创建计算列
-
NULL 值处理: NULL 值转换后仍为 NULL
sqlSELECT CAST(NULL AS INT); -- 结果: NULL -
时区影响: TIMESTAMP 与字符串互转时受客户端时区设置影响
sql-- 确保时间字符串包含时区信息 SELECT CAST('2024-01-15 14:30:00+08:00' AS TIMESTAMP); -
DECIMAL 溢出: DECIMAL 类型计算可能报溢出错误
sql-- 注意 DECIMAL 的 precision 和 scale 限制 SELECT CAST(999999999999999999.99 AS DECIMAL(38,2)); -
字符串转数值: 无效字符串转为 0,不会报错
sqlSELECT CAST('abc' AS INT); -- 结果: 0(静默转换) SELECT CAST('123abc' AS INT); -- 结果: 123(截断转换) -
布尔值转换: 布尔值与数值转换的规则
sqlSELECT CAST(true AS INT); -- 结果: 1 SELECT CAST(false AS INT); -- 结果: 0 SELECT CAST(1 AS BOOL); -- 结果: true SELECT CAST(0 AS BOOL); -- 结果: false -
时间戳精度: 转换时注意数据库的时间精度设置
sql-- 毫秒精度数据库 SELECT CAST('2024-01-15 14:30:00.123456' AS TIMESTAMP); -- 结果会截断到毫秒: 2024-01-15 14:30:00.123
相关函数
- TO_CHAR: 将时间戳按指定格式转换为字符串,更灵活的格式控制
- TO_TIMESTAMP: 将字符串按指定格式转换为时间戳,支持自定义格式
- TO_UNIXTIMESTAMP: 将日期时间字符串转换为 Unix 时间戳
- TO_ISO8601: 将时间戳转换为 ISO8601 格式字符串,标准化输出
- TO_JSON: 将字符串常量转换为 JSON 类型
最佳实践
-
提前规划数据类型: 在建表时选择合适的数据类型,减少后续转换需求
-
批量转换: 在子查询中完成类型转换,避免重复计算
sql-- 推荐 SELECT * FROM ( SELECT CAST(current AS INT) AS current_int FROM meters ) WHERE current_int > 10; -- 不推荐 SELECT * FROM meters WHERE CAST(current AS INT) > 10 AND CAST(current AS INT) < 15; -
索引优化: 避免在索引列上使用 CAST,会导致索引失效
sql-- 如果 ts 列有索引,以下查询无法使用索引 SELECT * FROM meters WHERE CAST(ts AS VARCHAR(10)) = '2024-01-15'; -- 推荐使用范围查询 SELECT * FROM meters WHERE ts >= '2024-01-15 00:00:00' AND ts < '2024-01-16 00:00:00'; -
明确长度: 转换为字符串类型时明确指定长度,避免默认值不足
sqlSELECT CAST(voltage AS VARCHAR(20)) FROM meters; -- 明确指定长度 -
错误处理: 使用 CASE 表达式进行安全转换
sqlSELECT CASE WHEN current IS NULL THEN NULL WHEN current < 0 THEN 0 ELSE CAST(current AS INT) END AS safe_current FROM meters; -
性能测试: 对于大数据量查询,测试 CAST 对性能的影响
sql-- 使用 EXPLAIN 查看执行计划 EXPLAIN SELECT CAST(current AS INT) FROM meters WHERE ts > NOW - 1d;
关于 TDengine
TDengine 专为物联网IoT平台、工业大数据平台设计。其中,TDengine TSDB 是一款高性能、分布式的时序数据库(Time Series Database),同时它还带有内建的缓存、流式计算、数据订阅等系统功能;TDengine IDMP 是一款AI原生工业数据管理平台,它通过树状层次结构建立数据目录,对数据进行标准化、情景化,并通过 AI 提供实时分析、可视化、事件管理与报警等功能。