forked from GiteaTest2015/streamsql
5.8 KiB
5.8 KiB
StreamSQL 负数支持文档
概述
StreamSQL 现在全面支持负数在 CASE 表达式中的使用。本文档总结了负数支持的完善情况、支持范围和使用建议。
✅ 已支持的负数用法
1. 基本负数常量
-- CASE 表达式中的负数常量
CASE WHEN temperature > 0 THEN 1 ELSE -1 END
-- 负数小数
CASE WHEN temperature > 0 THEN 1.5 ELSE -2.5 END
-- 负零
CASE WHEN temperature = -0 THEN 1 ELSE 0 END
2. 比较运算符后的负数
-- 比较运算符后直接跟负数
CASE WHEN temperature < -10 THEN 'FREEZING' ELSE 'NORMAL' END
CASE WHEN temperature >= -5.5 THEN 'ABOVE' ELSE 'BELOW' END
CASE WHEN temperature > -20 THEN 'WARM' ELSE 'COLD' END
3. 简单 CASE 表达式中的负数
-- 简单 CASE 中使用负数作为匹配值
CASE temperature
WHEN -10 THEN 'FROZEN'
WHEN -5 THEN 'COLD'
WHEN 0 THEN 'ZERO'
ELSE 'OTHER'
END
4. 算术表达式中的负数
-- 括号内的负数运算
CASE WHEN temperature + (-10) > 0 THEN 1 ELSE 0 END
CASE WHEN (temperature * -1) > 10 THEN 1 ELSE 0 END
⚠️ 部分支持或限制
1. 函数参数中的负数表达式
-- 当前不完全支持:函数参数中的负数变量
CASE WHEN ABS(-temperature) > 10 THEN 1 ELSE 0 END -- ❌
-- 推荐替代方案:使用括号或先计算
CASE WHEN ABS(temperature * -1) > 10 THEN 1 ELSE 0 END -- ✅
2. BETWEEN 语句中的负数范围
-- 当前不支持:BETWEEN 与负数组合
CASE WHEN temperature BETWEEN -20 AND -10 THEN 1 ELSE 0 END -- ❌
-- 推荐替代方案:使用比较运算符
CASE WHEN temperature >= -20 AND temperature <= -10 THEN 1 ELSE 0 END -- ✅
3. SQL 中的空格分隔负数
-- 避免在 SQL 中使用空格分隔的负数
SELECT CASE WHEN temperature < - 10 THEN 'COLD' END -- ❌ 解析问题
-- 推荐写法:紧密连接或使用括号
SELECT CASE WHEN temperature < -10 THEN 'COLD' END -- ✅
SELECT CASE WHEN temperature < (-10) THEN 'COLD' END -- ✅
🔧 技术实现
词法分析器增强
-
智能负数识别:
- 识别比较运算符后的负数(
<,>,<=,>=,==,!=) - 支持逻辑运算符后的负数(
AND,OR) - 支持 CASE 关键字后的负数(
WHEN,THEN,ELSE)
- 识别比较运算符后的负数(
-
连续运算符检查优化:
- 允许比较运算符后跟负数的合法组合
- 智能区分负数与减号运算符
-
空格处理:
- 正确处理空格分隔的负数标记
- 改进 token 化过程以支持各种负数格式
表达式求值增强
- 负数常量解析:完全支持负整数和负小数
- 类型转换:正确处理负数的数值转换
- NULL 值处理:负数与 NULL 值的正确交互
📊 测试覆盖
表达式级别测试
- ✅ 负数常量在 THEN/ELSE 中
- ✅ 负数常量在 WHEN 条件中
- ✅ 负数小数支持
- ✅ 负数在算术表达式中
- ✅ 负数在简单 CASE 中
- ✅ 负零处理
SQL 集成测试
- ✅ 完整 SQL 语句中的负数支持
- ✅ 非聚合查询中的负数表达式
- ✅ 聚合查询中的负数处理
🎯 使用建议
1. 推荐的负数写法
-- ✅ 推荐:紧密连接的负数
CASE WHEN temperature < -10 THEN 'FREEZING' END
-- ✅ 推荐:括号包围的负数(最安全)
CASE WHEN temperature < (-10) THEN 'FREEZING' END
-- ✅ 推荐:负数小数
CASE WHEN temperature < -10.5 THEN 'FREEZING' END
2. 避免的写法
-- ❌ 避免:空格分隔的负数
CASE WHEN temperature < - 10 THEN 'FREEZING' END
-- ❌ 避免:复杂的负数表达式在函数中
CASE WHEN ABS(-temperature) > 10 THEN 1 END
3. 最佳实践
- 使用括号:当不确定负数解析时,总是使用括号包围负数
- 避免空格:在负号和数字之间不要添加空格
- 测试验证:对包含负数的复杂表达式进行充分测试
- 版本兼容:确保使用的 StreamSQL 版本支持所需的负数功能
🚀 未来改进计划
- 完全支持函数参数中的负数表达式
- 支持 BETWEEN 语句中的负数范围
- 改进 SQL 解析器对空格分隔负数的处理
- 扩展负数支持到更多数学和字符串函数
示例代码
package main
import (
"fmt"
"github.com/rulego/streamsql"
)
func main() {
// 创建 StreamSQL 实例
sql := streamsql.New()
defer sql.Stop()
// 包含负数的 SQL 查询
query := `
SELECT deviceId,
temperature,
CASE
WHEN temperature < -10 THEN 'FREEZING'
WHEN temperature < 0 THEN 'COLD'
WHEN temperature = 0 THEN 'ZERO'
ELSE 'POSITIVE'
END as temp_category,
CASE
WHEN temperature > 0 THEN temperature
ELSE (-1.0)
END as adjusted_temp
FROM stream
`
// 执行查询
err := sql.Execute(query)
if err != nil {
fmt.Printf("执行失败: %v\n", err)
return
}
// 添加数据处理器
sql.AddSink(func(result interface{}) {
fmt.Printf("结果: %+v\n", result)
})
// 添加测试数据
testData := []map[string]interface{}{
{"deviceId": "sensor1", "temperature": -15.0},
{"deviceId": "sensor2", "temperature": -5.0},
{"deviceId": "sensor3", "temperature": 0.0},
{"deviceId": "sensor4", "temperature": 10.0},
}
for _, data := range testData {
sql.AddData(data)
}
}
更新日期: 2025-06-17
版本: StreamSQL v0.x
作者: StreamSQL 开发团队