2、SQL查询语句实战:SELECT语句在Intouch中的使用、WHERE条件过滤、ORDER BY排序
好,咱们直接进入正题。上一章我们把数据库表结构搭好了,也把Intouch和SQL Server连上了。但说实话,连上只是第一步,真正干活的是怎么把数据查出来。
这一章,我就带你手把手搞定SELECT语句。别小看它,我见过太多项目,就因为查询写得烂,导致画面卡死、报表出不来。嗯,咱们从最基础的开始。
2.1 SELECT语句:从表中拿数据
SELECT,说白了就是「我要看什么」。它的基本骨架很简单:
SELECT 列名 FROM 表名
比如,我想看历史报警表里的所有记录:
SELECT * FROM AlarmHistory
这里的*是通配符,代表「所有列」。但我在实际项目中,几乎不用*。为什么?
有一次,我在一个水处理项目里,用*查报警表,结果画面卡了十几秒。后来一查,那张表有30多列,其中几列存的是大段的文本描述。你想想看,每次查询都拉回这么多没用的数据,性能能好吗?
SELECT AlarmTime, TagName, AlarmValue FROM AlarmHistory
2.2 WHERE条件过滤:只拿你想要的
不加条件的SELECT,等于把整张表倒出来。这在Intouch里基本没有意义——你不可能让操作员看几百万条历史记录。
WHERE子句就是干这个的:加条件,筛数据。
2.2.1 基本比较运算符
| 运算符 | 含义 | 示例 |
|---|---|---|
| = | 等于 | WHERE TagName = 'Tank_Level' |
| <> 或 != | 不等于 | WHERE AlarmValue <> 0 |
| > | 大于 | WHERE AlarmValue > 100 |
| < | 小于 | WHERE AlarmValue < 50 |
| BETWEEN | 在范围内 | WHERE AlarmValue BETWEEN 50 AND 100 |
| LIKE | 模糊匹配 | WHERE TagName LIKE 'Tank%' |
举个例子。我想查某个液位标签在2024年1月1日之后的所有报警:
SELECT AlarmTime, TagName, AlarmValue, AlarmStatus
FROM AlarmHistory
WHERE TagName = 'Tank_Level_01'
AND AlarmTime >= '2024-01-01 00:00:00'
YYYY-MM-DD,但Intouch传过来的字符串是MM/DD/YYYY,结果查出来全是空的。排查了半天,最后发现是格式不匹配。
2.2.2 组合条件:AND 和 OR
实际项目中,很少只用一个条件。比如我想查「液位高报警」且「值大于80」的记录:
SELECT * FROM AlarmHistory
WHERE TagName = 'Tank_Level_01'
AND AlarmValue > 80
AND AlarmStatus = 'Active'
注意,AND的优先级高于OR。如果你混用,最好加括号。我见过有人写:
-- 这样写容易有歧义
WHERE TagName = 'Tank_01' OR TagName = 'Tank_02' AND AlarmValue > 100
你猜它先执行哪个?嗯,它会先执行AND,再执行OR。所以上面这句,实际等价于:
WHERE TagName = 'Tank_01' OR (TagName = 'Tank_02' AND AlarmValue > 100)
这很可能不是你想要的结果。我的建议是:永远用括号明确优先级。
WHERE (TagName = 'Tank_01' OR TagName = 'Tank_02')
AND AlarmValue > 100
2.3 ORDER BY排序:让数据排好队
查出来的数据默认是按插入顺序排列的。但你想看最新的报警在最上面,怎么办?
用ORDER BY。
SELECT AlarmTime, TagName, AlarmValue
FROM AlarmHistory
WHERE TagName = 'Tank_Level_01'
ORDER BY AlarmTime DESC
DESC表示降序(最新的在最上面),ASC表示升序(默认)。
也可以按多列排序。比如先按标签名排,再按时间排:
SELECT * FROM AlarmHistory
ORDER BY TagName ASC, AlarmTime DESC
2.4 在Intouch中执行SELECT
好了,SQL语句写好了,怎么在Intouch里用?
Intouch通过ODBC连接数据库,用SQLSelect()函数执行查询。基本流程是:
- 用
SQLConnect()建立连接 - 用
SQLSelect()执行查询 - 用
SQLFirst()/SQLNext()遍历结果 - 用
SQLDisconnect()断开连接
举个例子,在按钮脚本里写:
// 建立连接
SQLConnect(ConnectionId, "DSN=MySCADA;UID=sa;PWD=123456");
// 执行查询
SQLSelect(ConnectionId, "SELECT AlarmTime, TagName, AlarmValue FROM AlarmHistory WHERE TagName = 'Tank_Level' ORDER BY AlarmTime DESC");
// 获取第一条记录
SQLFirst(ConnectionId);
// 把结果读到内存标签里
TagName = SQLResult(ConnectionId, 2); // 第2列
AlarmValue = SQLResult(ConnectionId, 3); // 第3列
// 循环读取下一条
WHILE SQLNext(ConnectionId) == 1 DO
TagName = SQLResult(ConnectionId, 2);
AlarmValue = SQLResult(ConnectionId, 3);
ENDWHILE;
// 断开连接
SQLDisconnect(ConnectionId);
SQLDisconnect(),结果数据库连接数爆满,导致其他客户端连不上。后来我养成了习惯:每次查询完,立刻断开连接。如果脚本里有多处查询,可以用一个全局变量管理连接ID。
2.5 本章知识体系
下面这张图,帮你理清SELECT语句的核心逻辑:
2.6 实战小贴士
最后,分享几个我在项目中总结的实用技巧:
- 先测试再部署:我习惯先在SQL Server Management Studio里把SELECT语句跑通,确认结果正确,再复制到Intouch脚本里。这样能避免很多低级错误。
- 参数化查询:如果条件里的值是变量(比如操作员选择的日期),别直接拼字符串。用
SQLSetStatement()配合参数,既安全又高效。 - 分页查询:如果数据量很大(比如几十万条),用
TOP或OFFSET FETCH做分页。别一次全查出来,Intouch画面扛不住。
一句话总结:SELECT是SQL的基石。WHERE帮你精准定位,ORDER BY让数据井然有序。在Intouch里用好它们,你的画面会又快又准。
公众号:蓝海资料掘金营,微信deep3321