3、数据写入操作:INSERT INTO语句、使用Intouch脚本向SQL Server写入数据、处理写入失败
好,咱们接着聊数据写入。前面讲了怎么从数据库里把数据捞出来,现在反过来——怎么把现场的数据存进去。说白了,就是让Intouch把采集到的温度、压力、流量这些值,老老实实写到SQL Server的表格里。
我个人习惯把数据写入分成三个层次来看:第一层是SQL语句本身怎么写,第二层是Intouch脚本里怎么调用,第三层是万一写失败了怎么办。咱们一层一层剥开。
3.1 INSERT INTO语句——写入的“基本功”
先看SQL语句。INSERT INTO,就是往表里插一行数据。语法其实很简单:
INSERT INTO 表名 (字段1, 字段2, 字段3)
VALUES (值1, 值2, 值3)
举个例子。假设我们有个表叫 TagHistory,用来存历史数据:
CREATE TABLE TagHistory (
ID INT IDENTITY(1,1) PRIMARY KEY,
TagName NVARCHAR(50),
TagValue FLOAT,
TimeStamp DATETIME
)
那插入一条记录的SQL就是:
INSERT INTO TagHistory (TagName, TagValue, TimeStamp)
VALUES ('Tank1_Temperature', 85.6, '2025-01-15 14:30:00')
嗯,这里要注意几个细节:
- 字段顺序要和VALUES一一对应。我见过有人把TagName和TagValue写反了,结果温度值存到了名字字段里,查出来全是乱码。
- 字符串要用单引号。SQL Server里字符串常量必须用单引号,双引号是给标识符用的,别搞混。
- 自增字段不用写。像ID这种设置了IDENTITY的字段,SQL Server会自动生成,你不需要在INSERT语句里给它赋值。
INSERT INTO TagHistory (TagName, TagValue, TimeStamp) VALUES
('Tank1_Temp', 85.6, GETDATE()),
('Tank2_Temp', 90.2, GETDATE()),
('Tank3_Temp', 78.9, GETDATE())这样比一条一条执行快得多,尤其是批量写入的时候。
3.2 用Intouch脚本向SQL Server写入数据
SQL语句写好了,怎么让Intouch去执行它?这就得靠脚本了。Intouch里操作数据库,核心就几个步骤:连接、执行、关闭。
我一般用QuickScript或者条件脚本。下面是一个典型的写入脚本:
// 定义变量
Dim objConn As Object
Dim objCmd As Object
Dim sConnStr As String
Dim sSQL As String
Dim fValue As Float
// 获取当前值
fValue = Tank1_Temperature;
// 构建连接字符串
sConnStr = "Provider=SQLOLEDB;Data Source=localhost;Initial Catalog=SCADA_DB;User ID=sa;Password=123456;";
// 构建SQL语句
sSQL = "INSERT INTO TagHistory (TagName, TagValue, TimeStamp) VALUES ('Tank1_Temperature', " + String(fValue) + ", GETDATE())";
// 创建连接对象
Set objConn = CreateObject("ADODB.Connection");
objConn.ConnectionString = sConnStr;
objConn.Open;
// 创建命令对象并执行
Set objCmd = CreateObject("ADODB.Command");
objCmd.ActiveConnection = objConn;
objCmd.CommandText = sSQL;
objCmd.Execute;
// 清理对象
Set objCmd = Nothing;
objConn.Close;
Set objConn = Nothing;
这段脚本看着长,其实逻辑很清晰:
- 创建ADODB对象——这是Intouch和数据库之间的桥梁。
- 拼SQL语句——把变量值拼到字符串里。注意要把数值转成字符串。
- 执行——调用Execute方法。
- 释放资源——用完的对象要关掉、清空,不然内存会泄漏。
我在项目中遇到过一个问题:脚本执行了,但数据库里没数据。查了半天,发现是连接字符串写错了——Data Source写成了Data Souce,少了个r。这种低级错误,排查起来最费时间。所以我的习惯是:先把连接字符串单独拿出来测试,确认能连上再写脚本。
3.3 处理写入失败——别让数据丢了
写入操作,说白了就是“把鸡蛋放到篮子里”。但篮子可能漏,可能被人踢翻。现场环境复杂,网络波动、数据库满、权限不够……什么情况都可能发生。
我曾经在一个项目里,半夜两点被电话叫醒——说数据全丢了。跑过去一看,数据库磁盘满了,INSERT语句全部失败,但Intouch那边没有任何提示,该采集采集,该显示显示,就是没存进去。从那以后,我写写入脚本必加错误处理。
错误处理的核心思路就一句话:捕获异常,记录日志,通知操作员。
看代码:
// 错误处理示例
On Error GoTo ErrorHandler
' ... 连接、执行代码 ...
ExitScript:
' 正常清理
Set objCmd = Nothing
If Not objConn Is Nothing Then
If objConn.State = 1 Then objConn.Close
Set objConn = Nothing
End If
Exit Sub
ErrorHandler:
' 记录错误日志
LogError "数据写入失败: " & Err.Description & ",SQL: " & sSQL
' 尝试重连(最多3次)
Dim iRetry As Integer
For iRetry = 1 To 3
' 重新连接并执行
' ...
If Err.Number = 0 Then Exit For
Next
' 如果还是失败,写入本地缓存文件
If Err.Number <> 0 Then
WriteToLocalCache sSQL
End If
Resume ExitScript
这里有几个关键点:
- On Error GoTo——Intouch脚本里捕获错误的经典写法。一旦出错,跳转到错误处理标签。
- 重试机制——网络抖动导致的失败,重试几次可能就好了。我一般设3次,间隔1秒。
- 本地缓存——如果数据库彻底连不上,就把数据先写到本地文件里。等网络恢复了再补写。这是最后的保底方案。
还有一个容易被忽略的点:事务控制。如果你一次写入多条记录,最好用事务包起来。要么全部成功,要么全部回滚。不然写了一半数据库崩了,数据就不完整了。
// 事务示例
objConn.BeginTrans
' 执行多条INSERT
objCmd.Execute "INSERT INTO ..."
objCmd.Execute "INSERT INTO ..."
objCmd.Execute "INSERT INTO ..."
' 全部成功,提交
objConn.CommitTrans
嗯,这里要注意:BeginTrans和CommitTrans要成对出现。如果中间出错了,记得调用RollbackTrans回滚。
3.4 知识体系总览
说了这么多,咱们用一张图把数据写入的核心逻辑串起来:
这张图把数据写入的三个层次和最终走向说清楚了。你想想看,从SQL语句到脚本执行,再到失败处理,每一步都有坑。但只要按这个流程来,基本能覆盖90%以上的场景。
1. 手动执行一次SQL语句,确认语法没问题。
2. 断开数据库网线,测试错误处理是否生效。
3. 查看日志文件,确认错误信息记录完整。
这三步走完,心里才踏实。
好了,数据写入这块就聊到这儿。记住一句话:写入操作,成功是应该的,失败才是需要重点关注的。把失败处理做好了,系统才能真正稳定运行。