Files
streamsql/docs/NEGATIVE_NUMBER_SUPPORT.md
2025-06-17 14:20:40 +08:00

225 lines
5.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# StreamSQL 负数支持文档
## 概述
StreamSQL 现在全面支持负数在 CASE 表达式中的使用。本文档总结了负数支持的完善情况、支持范围和使用建议。
## ✅ 已支持的负数用法
### 1. 基本负数常量
```sql
-- 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. 比较运算符后的负数
```sql
-- 比较运算符后直接跟负数
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 表达式中的负数
```sql
-- 简单 CASE 中使用负数作为匹配值
CASE temperature
WHEN -10 THEN 'FROZEN'
WHEN -5 THEN 'COLD'
WHEN 0 THEN 'ZERO'
ELSE 'OTHER'
END
```
### 4. 算术表达式中的负数
```sql
-- 括号内的负数运算
CASE WHEN temperature + (-10) > 0 THEN 1 ELSE 0 END
CASE WHEN (temperature * -1) > 10 THEN 1 ELSE 0 END
```
## ⚠️ 部分支持或限制
### 1. 函数参数中的负数表达式
```sql
-- 当前不完全支持:函数参数中的负数变量
CASE WHEN ABS(-temperature) > 10 THEN 1 ELSE 0 END -- ❌
-- 推荐替代方案:使用括号或先计算
CASE WHEN ABS(temperature * -1) > 10 THEN 1 ELSE 0 END -- ✅
```
### 2. BETWEEN 语句中的负数范围
```sql
-- 当前不支持: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
-- 避免在 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 -- ✅
```
## 🔧 技术实现
### 词法分析器增强
1. **智能负数识别**
- 识别比较运算符后的负数(`<`, `>`, `<=`, `>=`, `==`, `!=`
- 支持逻辑运算符后的负数(`AND`, `OR`
- 支持 CASE 关键字后的负数(`WHEN`, `THEN`, `ELSE`
2. **连续运算符检查优化**
- 允许比较运算符后跟负数的合法组合
- 智能区分负数与减号运算符
3. **空格处理**
- 正确处理空格分隔的负数标记
- 改进 token 化过程以支持各种负数格式
### 表达式求值增强
1. **负数常量解析**:完全支持负整数和负小数
2. **类型转换**:正确处理负数的数值转换
3. **NULL 值处理**:负数与 NULL 值的正确交互
## 📊 测试覆盖
### 表达式级别测试
- ✅ 负数常量在 THEN/ELSE 中
- ✅ 负数常量在 WHEN 条件中
- ✅ 负数小数支持
- ✅ 负数在算术表达式中
- ✅ 负数在简单 CASE 中
- ✅ 负零处理
### SQL 集成测试
- ✅ 完整 SQL 语句中的负数支持
- ✅ 非聚合查询中的负数表达式
- ✅ 聚合查询中的负数处理
## 🎯 使用建议
### 1. 推荐的负数写法
```sql
-- ✅ 推荐:紧密连接的负数
CASE WHEN temperature < -10 THEN 'FREEZING' END
-- ✅ 推荐:括号包围的负数(最安全)
CASE WHEN temperature < (-10) THEN 'FREEZING' END
-- ✅ 推荐:负数小数
CASE WHEN temperature < -10.5 THEN 'FREEZING' END
```
### 2. 避免的写法
```sql
-- ❌ 避免:空格分隔的负数
CASE WHEN temperature < - 10 THEN 'FREEZING' END
-- ❌ 避免:复杂的负数表达式在函数中
CASE WHEN ABS(-temperature) > 10 THEN 1 END
```
### 3. 最佳实践
1. **使用括号**:当不确定负数解析时,总是使用括号包围负数
2. **避免空格**:在负号和数字之间不要添加空格
3. **测试验证**:对包含负数的复杂表达式进行充分测试
4. **版本兼容**:确保使用的 StreamSQL 版本支持所需的负数功能
## 🚀 未来改进计划
1. **完全支持函数参数中的负数表达式**
2. **支持 BETWEEN 语句中的负数范围**
3. **改进 SQL 解析器对空格分隔负数的处理**
4. **扩展负数支持到更多数学和字符串函数**
## 示例代码
```go
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 开发团队