Intouch2014R2实时值落库与Excel报表取数 简介面向使用 Intouch2014R2 搭建 SCADA 系统的工程人员与自动化学习者这份文档围绕人机界面接入 SQL Server 2012 数据库并借助 Excel 生成报表的流程展开适合需要处理实时与历史数据存储、查询、定时写入和报表输出的现场调试及项目实践。包内仅含 1 个 doc 文件压缩包约 2.48MB以图文步骤串起数据库创建与身份验证、登录名权限配置、标记名字典与绑定列表设置、数据库连接与断开脚本、定时写入判断以及 Excel 报表模板、VBA 引用配置和数据库文件恢复等内容覆盖从数据落库到报表呈现的主要环节。目前已有 533 人学习下载可作为 Intouch 与 SQL Server 集成及 Excel 报表落地的查阅型手册便于按章节核对连接参数、脚本条件和模板搭建要点也能为类似 SCADA 数据报表项目提供可复用的操作思路。1. Intouch2014R2 落库与 Excle 报表把 HMI 实时值变成可交接的历史数据Intouch2014R2 的 IDE 里做画面不难难的是把操作员看到的实时值稳定落到 SQL Server 2012再让 Excle 报表按班次、按日把数据取出来。这份操作文档解决的就是这条链路建库和账号、在 Intouch 里建连接标记、用绑定列表把变量和表列对齐、用条件脚本定时写库最后用 Excel 模板从 SQL Server 2012 取数。适合正在做 SCADA 报表交接、手里有 Intouch2014R2 和 SQL Server 2012、又不想把连接串和表名写死在脚本里的工程师。下面按“数据库入口、Intouch 标记与脚本、Excel 报表、排查、回放验证”拆开讲能照着在测试库复现。2. SQL Server 2012 的入口身份验证、账号权限与报表表结构2.1 先改身份验证模式还是先建应用账号现场最容易翻车的一步不是脚本而是数据库入口没理顺。Intouch 通过 OLEDB 连接 SQL Server 2012如果实例只开了系统身份验证而 Intouch 运行账户和数据库账户又不在同一个域环境里连接串再怎么写都可能连不上。常见做法是先把实例改成“SQL Server 和 Windows 身份验证模式”再建一个只给报表读写权限的应用账号不要图省事用 sa。sa 权限太大密码一旦落在脚本或 Excel 控制面板里后面交接很难收场。操作顺序我一般这样走步骤操作位置关键点1SSMS 连接实例右键服务器属性安全性页选“SQL Server 和 Windows 身份验证模式”按变更窗口重启数据库服务2安全性 - 登录名 - 新建登录名选 SQL Server 身份验证默认数据库指向业务库3用户映射只勾业务库角色给db_datareader、db_datawriter4用新账号单独登录 SSMS执行一条SELECT和一条测试INSERT确认权限够用建账号的 SQL 可以抄下面这段但强密码必须替换成现场策略允许的密码Demo_SCADA只是示例库名实际换成自己的业务库。CHECK_POLICY ON让密码策略继续生效不要为了省事关掉。-- 在 master 下执行... 必须替换为现场值 USE master; GO CREATE LOGIN scada_app WITH PASSWORD N强密码, CHECK_POLICY ON; GO USE Demo_SCADA; GO CREATE USER scada_app FOR LOGIN scada_app; ALTER ROLE db_datareader ADD MEMBER scada_app; ALTER ROLE db_datawriter ADD MEMBER scada_app; GO这段脚本的逻辑是“登录名”和“数据库用户”分开建登录名管实例入口数据库用户管业务库里的权限角色映射决定能读还是能写。参数上重点看三个地方账号名不要用中文和空格默认数据库要指向业务库避免登录后落到 master角色不要给db_ownerIntouch 只需要写表和读表。现场如果已经有 DBA 管账号这一步可以让 DBA 建好自己只拿连接参数不要把 sa 密码写进 Intouch 脚本。注意连接串里的密码不要明文写进 Intouch 应用程序脚本也不要放在 Excel 的可见单元格里。至少把配置放到受控 ini 文件或受保护工作表交接时单独说明权限。2.2 报表表结构列名与 Intouch 绑定列表一一对应Intouch 的SQLInsert不是让你手写INSERT语句它靠绑定列表把变量值按列塞进表里。所以表结构要稳列名要固定自增列不要出现在绑定列表里。下面这张DailyParam是示例表字段够覆盖时间、产线、标记名、值、质量码和批次。Id用自增主键给数据库自己用Intouch 绑定列表从TagTime开始绑不要把Id绑进去。CREATE TABLE dbo.DailyParam( Id BIGINT IDENTITY(1,1) PRIMARY KEY, TagTime DATETIME2(0) NOT NULL, LineName NVARCHAR(32) NOT NULL, TagName NVARCHAR(64) NOT NULL, TagValue FLOAT NULL, Quality INT NOT NULL DEFAULT 0, BatchNo NVARCHAR(32) NULL ); GO CREATE INDEX IX_DailyParam_TagTime ON dbo.DailyParam(TagTime); GODATETIME2(0)比DATETIME秒级精度更干净报表按秒查询时不容易出现毫秒尾巴TagValue用FLOAT对应 Intouch 的内存实数LineName、TagName用NVARCHAR留余量别卡得太死。索引先建在TagTime上因为 Excel 报表最常按时间范围查。绑定列表和表列的对应关系可以按下面这张表核对Intouch 标记类型建议 SQL 类型说明内存整型INT计数、状态码、质量码内存实数FLOAT模拟量、温度、压力内存消息NVARCHAR(n)字符串、班次、批次号内存离散BIT启停、报警状态现场常见做法是先把绑定列表只绑三列时间、标记名、值跑通一次SQLInsert再加质量码和批次号。这样出错时能快速判断是表结构问题还是脚本问题不用一上来就查整张宽表。2.3 恢复历史库附加 mdf/ldf 的先后与权限操作文档里数据库恢复这部分很实用SQL Server 数据库至少有两个文件数据文件.mdf和日志文件.ldf。恢复时不要把.mdf单独拷走两个文件要放在同一个目录里再在 SSMS 里右键“数据库”-“附加”添加.mdf确认.ldf路径能对上。只拷.mdf有时也能附加但会触发日志重建日志里的历史操作和权限信息可能丢后面查问题就少了一层依据。我一般按这个顺序做先停掉历史库写入确认没有连接占用把整个 DataBase 目录拷到历史数据服务器的目标盘用数据库服务账户检查目录读写权限在 SSMS 里附加附加后看“所有者”和“恢复模式”最后用应用账号执行一条按时间范围的查询确认权限没丢。附加失败常见三种路径不对、服务账户没权限、源库版本高于目标实例。源库版本高的情况不要硬降级换同版本或更高版本实例附加或者让 DBA 做导出导入。检查项通过标准文件.mdf和.ldf同目录文件名没被改权限数据库服务账户对目录有读写权限版本目标实例版本不低于源实例附加后表数量、行数、按时间查询正常账号应用账号能读不能改表结构3. Intouch 侧的标记与绑定让 SQLInsert 只写一次、写对列3.1 Connid1、NodeName、WSQLS三类状态标记别省Intouch 的标记名字典里连接号和状态标记是后面排错的“黑匣子”。Connid1用内存整型保存SQLConnect回填的连接号GetDateTimeS用内存消息记录连接或写入时间NodeName用内存消息保存本机计算机名WSQLS用内存离散做写库幂等锁。这几个标记不占多少资源但少了它们脚本出问题时只能猜。标记名类型初值用途Connid1内存整型0保存数据库连接号GetDateTimeS内存消息空记录连接/写入时间便于排错NodeName内存消息空保存本机名多站部署时防重复写WSQLS内存离散0写库锁防止同一分钟重复插入LastWriteTime内存消息空可选记录最后一次成功写入时间GetNodeName(NodeName, 131)里的第二个参数按现场函数说明填原文示例是 131别把这个数字当成固定值照抄到所有版本。多操作站项目里NodeName判断很有用只有采集站写库其他站只显示不然同一分钟会有多台机器同时插入。3.2 条件脚本连接放 $Second3写库放 $Second5Intouch 的条件脚本用系统秒触发原文把连接放在$Second3写库放在$Second5。这个节奏可以保留但连接不要每分钟无条件重连。下面这段连接脚本用Connid1 0做首次连接判断连上后记录时间如果现场版本对连接号回填规则不同先用 SQL 访问管理器测一次别把Connid1当布尔量硬判断。 条件$Second 3条件类型为真时 Connid1 为 0 时尝试连接避免每分钟重复 SQLConnect IF Connid1 0 THEN SQLConnect(Connid1, providersqloledb;Data SourceSQL实例名;Initial Catalog业务库;User ID应用账号;Password密码;); GetDateTimeS $DateAndTime; ENDIF这段脚本的逻辑是先判断连接号是否为空再调用SQLConnect。连接字符串里五个部分用分号隔开Provider固定sqloledbData Source填实例名Initial Catalog填业务库User ID和Password填应用账号。...全部是占位符现场替换密码不要用 sa也不要把生产密码写进截图。写库脚本要解决原文里一个很容易踩的坑插入后立刻把WSQLS复位如果当前分钟仍然大于等于 58下一个 5 秒条件为真时会再插一次结果一分钟多条。下面把复位放到分钟回绕的ELSE分支里插入后保持WSQLS1等分钟回到 58 之前再清锁。 条件$Second 5条件类型为真时 GetNodeName(NodeName, 131); IF NodeName 采集站计算机名 THEN IF $Minute 58 THEN IF WSQLS 0 THEN SQLInsert(Connid1, DailyParam, DailyParam_Bind); WSQLS 1; GetDateTimeS $DateAndTime; ENDIF; ELSE 分钟回绕后复位避免同一分钟重复写 WSQLS 0; ENDIF; ENDIFSQLInsert三个参数分别是连接号、数据库表名、Intouch 绑定列表名。第一个DailyParam是 SQL 表第二个DailyParam_Bind是绑定列表不要写反也不要在这里写INSERT INTO。NodeName判断保证只有采集站写库$Minute 58是业务上的日切/班切窗口WSQLS是幂等锁。关闭应用程序时还要在“关闭时”脚本里加SQLDisconnect(Connid1);不然连接号会一直挂着。3.3 绑定列表列名、类型、顺序的四个对齐绑定列表在 SQL 访问管理器里建添加变量时要和表列一一对应变量名对列名变量类型对列类型添加顺序对表列顺序变量数量对非自增列数量。四个对齐里最容易错的是顺序和自增列。表里Id是自增列绑定列表里不能出现表里TagTime是DATETIME2绑定列表里用消息型时间字符串时格式要固定成yyyy-MM-dd HH:mm:ss不要用带星期的本地格式。绑定完成后先在测试表上执行一次SQLInsert再到 SSMS 里SELECT TOP 10 * FROM dbo.DailyParam ORDER BY Id DESC看结果。时间列变成1900-01-01通常是格式不匹配字符串列截断通常是NVARCHAR长度不够插入报列数不匹配通常是绑定列表多了自增列或少了非空列。把这些检查做完再上生产表比在画面上盯半天有效。4. Excel 报表取数控制面板、VBA 参数查询与刷新节奏4.1 模板结构控制面板、参数日报、引用Excel 报表模板不要一上来写 VBA先把“控制面板”页做出来。服务器、库名、账号、密码、开始时间、结束时间、刷新间隔都放在单元格里VBA 只负责读单元格和拼连接串。这样换现场只改单元格不用进代码。常见布局是 B2 到 B8B2 实例名B3 业务库B4 只读账号B5 密码B6 开始时间B7 结束时间B8 刷新分钟数。VBA 引用至少要确认三类Visual Basic For Applications、Excel 对象库、ADODB 引用。不同机器上 ADODB 的版本号可能不一样按本机列表里可用的选不要照抄版本号。Excel 进程位数也要注意32 位和 64 位混用时某些数据提供程序会报“未找到提供程序”或“未注册类”。用SQLOLEDB这种系统自带提供程序通常比装额外驱动省事。4.2 参数化查询别把开始时间拼进 SQL 字符串报表查询最怕把时间直接拼进 SQL 字符串格式一错就查不到遇到单引号还容易出问题。下面这段 VBA 用ADODB.Command传参数135是时间戳参数类型1是输入参数。查询范围用和结束时间不包含班次边界不会重复统计。Option Explicit Public Sub RefreshReportData() Dim wsCfg As Worksheet, wsRpt As Worksheet Dim conn As Object, cmd As Object, rs As Object Dim connStr As String, sql As String Dim tStart As Date, tEnd As Date Set wsCfg ThisWorkbook.Worksheets(控制面板) Set wsRpt ThisWorkbook.Worksheets(参数日报) tStart wsCfg.Range(B6).Value tEnd wsCfg.Range(B7).Value If tEnd tStart Then MsgBox 结束时间必须大于开始时间 Exit Sub End If connStr ProviderSQLOLEDB;Data Source wsCfg.Range(B2).Value _ ;Initial Catalog wsCfg.Range(B3).Value _ ;User ID wsCfg.Range(B4).Value _ ;Password wsCfg.Range(B5).Value ; sql SELECT TagTime, LineName, TagName, TagValue, Quality, BatchNo _ FROM dbo.DailyParam WHERE TagTime ? AND TagTime ? _ ORDER BY TagTime Set conn CreateObject(ADODB.Connection) conn.Open connStr Set cmd CreateObject(ADODB.Command) Set cmd.ActiveConnection conn cmd.CommandType 1 cmd.CommandText sql cmd.Parameters.Append cmd.CreateParameter(pStart, 135, 1, , tStart) cmd.Parameters.Append cmd.CreateParameter(pEnd, 135, 1, , tEnd) Set rs cmd.Execute wsRpt.Range(A2:F20000).ClearContents If Not rs.EOF Then wsRpt.Range(A2).CopyFromRecordset rs End If rs.Close conn.Close Set rs Nothing Set cmd Nothing Set conn Nothing End Sub这段代码的关键在参数化pStart、pEnd由 Excel 单元格传进去不拼字符串CopyFromRecordset从 A2 开始粘贴表头留在第一行A2:F20000是示例范围数据量更大就改范围或分页。账号用只读账号别给写权限。密码放在控制面板里并不等于安全至少把工作表保护起来交接时说明密码管理方式。4.3 刷新节奏5 秒写库不等于 5 秒刷报表Intouch 那边 5 秒写一次库是采集节奏Excel 报表没必要 5 秒刷一次。历史报表按 1 到 5 分钟刷新就够班次报表甚至可以手动刷新。定时刷新用Application.OnTime但一定要记录下一次时间关闭工作簿时取消不然 Excel 关了还会弹出来。Public nextRun As Date Public Sub ScheduleRefresh() On Error Resume Next Application.OnTime nextRun, RefreshReportData, , False On Error GoTo 0 nextRun Now TimeValue(00:05:00) Application.OnTime nextRun, RefreshReportData End SubOnTime的第一个参数是触发时间第二个是过程名取消时要把nextRun传回去并置False。如果每次打开都重新调度容易叠出多个定时任务表现是越刷新越快。我的做法是在Workbook_Open里只调一次ScheduleRefresh在Workbook_BeforeClose里取消。4.4 班次汇总与时间边界日报之外班次报表更常被问到。按产线、标记名做平均、最大、最小和样本数SQL 可以这样写。Quality 0只取质量好的点质量码定义按现场来不要默认所有 0 都是好点。SELECT LineName, TagName, AVG(TagValue) AS AvgValue, MAX(TagValue) AS MaxValue, MIN(TagValue) AS MinValue, COUNT(*) AS SampleCount FROM dbo.DailyParam WHERE TagTime ? AND TagTime ? AND Quality 0 GROUP BY LineName, TagName ORDER BY LineName, TagName;时间边界用半开区间08:00 到 20:00 的班次查 08:00 AND 20:00不要把 20:00 整点算进白班。空结果先看控制面板的时间格式再看数据库里TagTime是不是被写成了字符串格式。Excel 透视表接这段查询结果时把TagTime放行区域、TagName放列区域刷新后就能出班次对比。5. 排查写库重复、连接失败与报表空白的 5 个坑5.1 连接串能连上但 SQLInsert 没数据先看绑定列表现象SSMS 里用应用账号能查表Intouch 脚本也不报错但表里没有新行。原因多数在绑定列表列名和表列不一致、变量类型对不上、绑定列表里混进了自增列或者SQLInsert第二个参数写成了 SQL 语句。解决打开 SQL 访问管理器逐列对照表结构把自增列删掉先用只有三列的测试表跑通确认 SQLInsert(本文还有配套的精品资源点击获取