资讯动态

InTouch+SQL Server:自动生成Excel报表的完整解决方案

发布时间:2026/10/2 12:51:06 来源:尧图企业网站定制
简介面向SCADA系统工程师与工业自动化技术人员这份资料围绕WonderWare Intouch 2014R2IDE平台讲解如何将现场数据写入SQL Server 2012数据库并通过Excel报表系统实现数据读取与展示。内容覆盖SQL Server登录权限配置、数据库和表的新建、Intouch标记名字典与SQL访问管理器绑定以及SQLConnect、SQLInsert等脚本用法同时给出Excel报表模板与VBA引用配置步骤并包含数据库备份恢复操作便于完成数据入库到报表呈现的完整链路。资源为单个doc文档约2.48MB图文步骤配合代码片段适合按章节跟做。目前已有530人学习下载对正在搭建SCADA历史库或报表功能的读者有较好的参考价值。1. 在Intouch里加数据库做Excel报表这篇文档到底讲什么我刚看到这个标题时第一反应是这是要把组态软件里的历史数据变成能交差、能复查、能按月归档的生产报表。现场很多InTouch项目跑了好几年画面里有温度、压力、液位、产量可领导一到月底要报表还得靠人工从趋势图上读数、手写台账。标题里“数据库”和“基于EXCLE报表系统”放在一起其实是一条很具体的链路先把InTouch的实时值写进SQL Server这类标准数据库再定时把库里的数据按班次、按日、按月聚合成Excel。这套做法适合已经把InTouch跑起来、但历史数据还在“黑匣子”里的工厂也适合刚接手项目想补记录和报表的工程师。整篇文档解决的就是三件事库怎么建、数据怎么自动进库、报表怎么自动出。2. 选型与建库SQL Server 做主库还是先用 ODBC 连通2.1 为什么现场报表一般不走 InTouch 自带历史库InTouch自带历史记录器也能存历史数据趋势控件可以直接回放。但到了报表这一步它的导出方式非常别扭要么用历史趋势控件手工截取要么通过专用接口往文件里导再手动处理。部门之间传数据、做月度汇总、或者交给ERP系统这样的格式根本没法用。现场常见做法是让InTouch通过ODBC直连SQL Server。SQL Server的好处在于它是标准数据库Excel、VBA、Web报表系统、BI工具都能直接读不用绕路。对大多数项目来说选SQL Server而不是MySQL或Oracle主要理由是维护成本低、Windows环境里权限好控制、SQL Server Agent还能定时跑作业直接生成报表文件。如果现场IT对Oracle很熟也不是不能用但后续配合InTouch脚本和Excel VBA时SQL Server的驱动和示例最多踩坑最少。2.2 建库建表字段、主键和中文排序规则第一步是规划数据库名称我叫它ReportDB一眼就知道这是报表库。表名用TagReadings每行保存一个点位在某时刻的一个值。最小表结构如下IF OBJECT_ID(dbo.TagReadings) IS NULL BEGIN CREATE TABLE dbo.TagReadings ( Id BIGINT IDENTITY(1,1) PRIMARY KEY, TagName NVARCHAR(64) NOT NULL, TagValue FLOAT NOT NULL, Quality SMALLINT NOT NULL DEFAULT 0, SourceTime DATETIME2(0) NOT NULL ); CREATE INDEX IX_TagReadings_TagName_Time ON dbo.TagReadings(TagName, SourceTime); END这个结构里Id用自增主键主要作用不是查询而是后面做断线补传时可以按Id顺序取数据。TagName存点位的标记名比如BoilerPressure、FlowRateA不要直接存中文虽然SQL Server支持NVARCHAR存中文但InTouch的SQL Access Manager对中文标记名的兼容性偶尔有玄学问题。TagValue用FLOATInTouch的实数基本就是单精度浮点入库双精度足够。Quality是质量码0表示坏值192表示好值写库时过滤就靠它。SourceTime用DATETIME2(0)精确到秒就够了报表按小时、按班次聚合不需要毫秒。排序规则要注意。很多新装的SQL Server默认是Latin1_General_CI_AS对中文排序不是乱码就是不按拼音走。如果是中文项目建库时可以显式指定Chinese_PRC_CI_AS然后在创建表时也继承这个排序。我一般会建议在数据库层面定好不要在表里改列排序规则不然报表查询一旦用中文显示名效率会打折扣。索引方面TagName加SourceTime的顺序很重要报表场景几乎都是先定点位范围再定时间范围这个索引能让90%的报表查询走Index Seek。2.3 配置 ODBC 数据源并绑定 SQL Access ManagerInTouch自己不直接知道SQL Server在哪它通过ODBC连接。现场最典型的错误是InTouch跑32位却去控制面板里配了64位ODBC结果SQL Connect永远失败。这里需要先确认InTouch版本对应的位数64位版本用64位ODBC32位版本要打开SysWOW64下的odbcad32.exe来配置。配置系统DSN的步骤一般是打开ODBC数据源管理器选“系统DSN”。添加驱动选“ODBC Driver 17 for SQL Server”或系统里安装的SQL Server Native Client。服务器填SQL Server实例地址如果是本机可以填127.0.0.1。选“使用用户名和密码登录”输入专门建给采集用的账号比如scada_user。默认数据库选ReportDB。测试连接成功后再关掉配置窗口。之后打开InTouch自带的SQL Access Manager这是组态软件里管理数据库映射的工具。在里面建ConnectionConnectionId自己起名比如ReportLinkDSN选刚才配好的ReportDSN填写用户名密码。再建一个Transaction Cache名字叫DBQ后面脚本里的SQLInsert要用它。接着建TagGroup把InTouch标记名和数据库表的字段绑定TagName列绑定InTouch标记BoilerPressureTagValue列绑定标记BoilerPressure的值SourceTime列绑定系统变量$Time。这里有一个细节SQL Access Manager里的TagGroup绑定顺序要和表的字段顺序对得上。它按TagGroup里的绑定顺序生成INSERT语句如果顺序错乱数据会写进错列这个排查起来很费劲。连接信息可以在InTouch脚本里直接用SQLConnect覆盖也可以全靠SQL Access Manager配置我习惯在启动脚本里显式写连接日志排查更方便IF SQLConnect(ReportLink, DSNReportDSN;UIDscada_user;PWDscada123;) THEN WriteToLog(数据库连接成功); ELSE WriteToLog(数据库连接失败请检查DSN和账号); END;这段脚本里的ReportLink就是SQL Access Manager里定义的ConnectionIdDSNReportDSN是ODBC系统DSN的名字UID和PWD是数据库登录账号。WriteToLog是InTouch的日志函数连接失败时可以在记录器里直接看到原因比对着黑屏猜原因强得多。3. 让数据自动进库写库脚本、触发方式和断线补传3.1 从西门子1500到标记先保住数据源头数据库配好了但InTouch里如果连PLC的数据都没上来后面全是空库。以西门子1500为例现场常用MODBUS TCP或者S7协议把PLC数据送进InTouch。这里容易翻车的地方是PLC侧DB块地址和InTouch访问名里的偏移地址对不上画面数值看起来正常但写进库却是0或旧值。做数据库报表前先确认InTouch访问名对应的设备地址能实时变化这一步省得后面报表数据全是零。如果用的是MODBUS TCPInTouch里Access Name要填写IP和Unit ID对应1500的MODBUS地址区。1500侧需要启用MODBUS TCP服务器功能并且把DB块数据映射到保持寄存器区域。这些都通之后再检查InTouch标记比如汽包压力、给水流量确认在窗口脚本里能实时读到变化值。3.2 脚本写入定时、变化判断和批量插入InTouch写库最常放在WindowViewer的“应用脚本”里按周期执行。我见过有人把写库脚本放在画面按钮里结果画面没打开数据就停了。正确做法是放在应用脚本或全局脚本里绑定一个固定周期比如5秒执行一次。下面是一个最小可用的写库脚本IF SQLConnect(ReportLink, DSNReportDSN;UIDscada_user;PWDscada123;) THEN IF ChangeSinceLastScan(BoilerPressure) THEN SQLSetTagGroupValues(TagGroup1, BoilerPressure, BoilerPressure, 192, $Time); SQLInsert(ReportLink, TagGroup1, DBQ); END; END;ChangeSinceLastScan是InTouch内置函数用来判断某个标记从上一次扫描到现在是否变化。如果压力值一直恒定它返回FALSE就可以不写库。这样既省空间又让报表里不会出现大量重复行。SQLSetTagGroupValues的作用是把TagGroup里绑定的字段值提前写好第一个参数是TagGroup名字第二个是标记名第三是标记值第四是质量码192第五是时间戳$Time。SQLInsert才真正执行插入ReportLink是连接IDTagGroup1是刚才配置的映射组DBQ是SQL Access Manager里预设的Transaction Cache缓冲区。这里要强调一个参数质量码192不要写成0。现场最常见的问题就是通信短暂的闪断InTouch里数值没变但质量码已经掉到0如果不判断质量码报表里会出现一堆“看起来正常但其实是冻结值”的数据。把质量码一起写进库后面报表查询一过滤干净很多。如果点位很多比如一次要写20个温度点不要每个点都执行一条SQLInsert而是把20个字段全部绑定到一个TagGroup里一次INSERT写入一行。执行频率控制在5秒一次一天86400秒算下来才17280行对SQL Server来说毫无压力。注意SQLAccessManager里的Transaction Cache它的作用是缓冲写入失败的数据如果SQL Server短暂不可用缓存能顶一会儿。这个缓存不要设太大默认即可否则恢复连接后会一次性拥入大量旧数据。3.3 断线补传别让通讯中断丢了数据只要现场跑过两三个月就会遇到PLC重启、交换机掉线、SQL Server维护窗口这几件事。通信断了以后InTouch标记值会保持最后值脚本如果不去判断质量码会把旧值反复写库。更麻烦的是SQL Server如果在半夜重启InTouch这边的INSERT会一直失败但SQLAccessManager的缓存只帮你缓一小会儿时间长了数据还是丢。现场比较可靠的做法是加一张PendingWrites表先写本地再同步到主表。这张表结构简单CREATE TABLE dbo.PendingWrites ( Id INT IDENTITY(1,1) PRIMARY KEY, TagName NVARCHAR(64) NOT NULL, TagValue FLOAT NOT NULL, Quality SMALLINT NOT NULL, SourceTime DATETIME2(0) NOT NULL );写库脚本可以改成这样正常INSERT写主表失败时把这一条记录INSERT到PendingWrites等数据库恢复后再通过一个存储过程或数据同步工具把PendingWrites合并回TagReadings。这里涉及一个实际项目的取舍数据量不大时用存储过程最简单数据量大、分多个站点时可以用数据库同步工具把待补数据定时搬运到报表库。我一般会写一个简单的存储过程来完成补传InTouch侧只做一件事SQLExecute调用这个存储过程。这样InTouch不需要关心复杂的事务逻辑全部交给SQL Server自己处理。补传的时机放在每小时整点避免写入高峰。这个方法虽然不是万能的但比裸写SQLInsert硬闯可靠得多。4. 基于EXCLE的报表系统从数据库到班报、日报4.1 报表取数的基本模型时间、点位、聚合数据库里有了每5秒一条的实时数据报表的本质就变成了一个很简单的SQL按时间范围、按点位做聚合。现场报表最常见的三种形式是班级报8小时、日报24小时、月报自然月。它们背后的查询逻辑一模一样只是时间范围不同。以日报为例取一天内每个点位的平均值、最大值、最小值SELECT TagName, AVG(TagValue) AS AvgValue, MAX(TagValue) AS MaxValue, MIN(TagValue) AS MinValue, COUNT(*) AS SampleCount FROM dbo.TagReadings WHERE SourceTime 2025-06-01 00:00:00 AND SourceTime 2025-06-02 00:00:00 GROUP BY TagName ORDER BY TagName;这个查询里的时间范围写法我建议用左闭右开即开始时间且结束时间。如果写成BETWEEN 2025-06-01 00:00:00 AND 2025-06-01 23:59:59很容易漏掉最后一秒的数据。MIN、MAX、AVG是报表里最常用的三个聚合函数SampleCount也建议保留它能帮你判断这个点在这一天是完整采集还是中断过如果应该8640行假设5秒一个点结果只有5000行说明中间有掉线。班报比日报多一步把24小时按班次划分。常见做法是直接在SQL里加一个CASE表达式把SourceTime小时数映射成班次名SELECT CASE WHEN DATEPART(HOUR, SourceTime) 8 AND DATEPART(HOUR, SourceTime) 16 THEN 早班 WHEN DATEPART(HOUR, SourceTime) 16 AND DATEPART(HOUR, SourceTime) 24 THEN 中班 ELSE 夜班 END AS ShiftName, ...这里有个比价好的习惯报表SQL不要直接写在Excel VBA里写死而是先在SQL Server Management Studio里跑通再贴回VBA。否则VBA里调错一个字段名定位半天最后发现是SQL写错了。4.2 用VBA实现Excel报表生成的最小示例Excel侧生成报表我一般不会用复杂的透视表而是让VBA直接查SQL Server把结果铺到固定模板里。这个做法稳定、容易改格式、用户看到的就是一个标准Excel表格。Sub GenerateDailyReport() Dim conn As Object Set conn CreateObject(ADODB.Connection) conn.Open ProviderSQLOLEDB;Data Source10.1.2.3;Initial CatalogReportDB;User IDrep_user;Passwordrep123; Dim rs As Object Set rs CreateObject(ADODB.Recordset) rs.Open SELECT TagName, AVG(TagValue) AS AvgValue, MAX(TagValue) AS MaxValue, _ MIN(TagValue) AS MinValue FROM dbo.TagReadings _ WHERE SourceTime 2025-06-01 00:00:00 _ AND SourceTime 2025-06-02 00:00:00 _ GROUP BY TagName ORDER BY TagName, conn, 1, 1 Worksheets(日报).Range(A2).CopyFromRecordset rs rs.Close conn.Close Set rs Nothing Set conn Nothing End SubADODB.Connection的CreateObject写法好处是不需要先在Excel VBA里勾选Microsoft ActiveX Data Objects库换电脑也能直接跑。连接字符串里的Data Source填SQL Server的IPInitial Catalog填ReportDB用户名用报表只读账号rep_user。最后一个参数1,1表示游标类型是Keyset、锁类型是只读报表查询够用也避免锁住生产表。CopyFromRecordset会把查询结果整体一次性铺到工作表A2是起始单元格。注意Excel的行高、列宽、小数显示格式不会被自动带出来建议模板里先画好表头、设好数字格式比如温度保留1位小数压力保留2位小数。VBA跑完之后只填数据格式不冲突。这个最小示例能解决80%的日报需求。剩下的20%是多表头、合并单元格、特殊签名栏那就把Excel模板做成固定格式VBA只往里写数据不要在VBA里动态画样式否则后面改一个字体都要改代码。4.3 自动排程计划任务或SQL Server作业报表不能靠人每天打开Excel点“运行宏”那样过两周就有人忘记。现场可靠做法是两个方向一是Windows计划任务定时打开Excel跑VBA二是SQL Server Agent定时生成CSV或直接生成Excel。前者简单对现有Excel模板改动小后者不依赖前台Excel进程更适合无人值守。Windows计划任务的做法是把VBA宏放到Personal.xlsb宏工作簿里或者做成一个xlsm模板计划任务启动Excel后通过命令行参数打开模板并触发宏。这里有个坑如果Excel模板文件本身被设为只读或者上次异常崩溃后留下了一个隐藏的Excel进程宏会打不开文件或者文件被占用。所以计划任务的运行账户要和实际使用Excel的账户分开并且做好任务结束后自动关闭Excel的检查。SQL Server Agent的做法更干净把报表SQL写成作业定时执行输出CSV文件sqlcmd -S 10.1.2.3 -d ReportDB -U rep_user -P rep123 -W -s , -Q SET NOCOUNT ON; SELECT TagName, CONVERT(varchar(19), ...); -o D:\Reports\DailyReport.csv这条命令里的-W是去掉字段尾随空格-s , 是指定逗号分隔-o是输出文件路径。sqlcmd输出的CSV不带BOMExcel打开中文可能乱码所以生成后用一个小PowerShell脚本把文件转成UTF-8 with BOM即可。这个办法的好处是后台跑Excel不定时弹窗也不会被用户误关。缺点是没有Excel格式需要再有一层转换。最好的组合是SQL Agent生成数据CSV再加一个计划任务用Excel打开CSV另存成格式化的xlsx。不管用哪种排程报表文件名都建议带上日期比如DailyReport_20250602.xlsx这样历史报表归档不覆盖出问题还能翻出某一天的文件重新比对。5. InTouch数据库与报表的避坑清单五个高频问题5.1 数据始终写不进库先查连接名和TagGroup现象InTouch运行正常画面数值在跳打开SQL Server查询却一张空表或只有零星几条。原因大部分是SQLConnect的ConnectionId和SQL Access Manager里的连接ID不一致比如配置里叫ReportLink脚本里写成reportlink也有可能是TagGroup里字段顺序和表结构不匹配插入时类型转换失败被SQL Server拒了。解决第一步打开InTouch记录器日志确认SQLConnect是否返回成功。如果有“无法打开intouch应用程序。请参阅记录器以获取详细信息”这类启动报错说明SQL Access Manager没有随InTouch一起启动先去手动打开它再看记录器。第二步在SQL Server端用SQL Profiler或者扩展事件跟踪看InTouch是不是真的发出了INSERT语句。没发SQL问题在InTouch侧发了SQL被拒问题在表结构或数据长度。5.2 时间戳和时区错位谁的时间为准现象报表出来以后班次和现场对不上白班数据和现场早班差8小时。原因InTouch写库用的$Time是运行机本地时间SQL Server查询的报表如果用了服务器的GETDATE()两个时间基准就不一样。解决写入时明确绑定$Time不要依赖SQL Server的默认时间值查询时统一用SourceTime字段不要用GETDATE()去反推。如果现场部署跨时区建议在SQL查询里用AT TIME ZONE或者DATEADD把SourceTime先转换到指定时区再GROUP BY。观察一段时间后抽查几条数据和组态画面最后值比对确认时间基准一致。5.3 Excel文件被占用导出前Copy一份现象VBA跑的时候报“文件正被使用”或者“权限不足”报表生成了但不完整。原因目标文件被用户打开或者上一次Excel进程没有完全释放。解决VBA导出前用FileCopy把模板复制成一个新文件再在复制出来的文件上操作避免直接碰用户正在查看的模板。操作结束后必须用wb.Close SaveChanges:True释放工作簿再用Set wb Nothing释放对象。如果计划任务里用了Excel任务结束时检查进程里Excel是否还在在就把进程结束否则第二天任务必卡。5.4 通讯中断后出现0值靠质量码过滤现象报表里温度、压力某一天突然出现了几十个0最大值、最小值全部异常。原因InTouch与西门子1500之间的MODBUS TCP链路闪断InTouch把丢失的数据默认置成0写库脚本没有判断质量码就把0值写进去了。解决在SQLSetTagGroupValues里把质量码参数改成对应标记的质量变量或者直接对值做范围检查超过常识范围不写库。更好的做法是写库前先判断通信状态Bool如果这个点位来源于同一条MODBUS链路链路断的时候只写一个链路故障标记所有相关点都不插入。报表里如果再看到0值先查通信时段再查质量码不要急着改报表公式。5.5 库连接堆积启动一次连接不要频繁断开现象InTouch跑一两个月后SQL Server里出现几十个Sleeping会话写库越来越慢甚至到后面SQLInsert直接超时。原因脚本里每执行一次SQLInsert就SQLConnect一次执行完又不断开或者断开失败连接全部堆积在SQL Server里。解决把SQLConnect放在InTouch应用启动脚本里执行一次整个运行周期复用同一个连接只有检测到SQL Server重启或网络异常时才SQLDisconnect后再重连。这里有个原则连接生命周期和InTouch进程保持一致不要放进周期执行脚本里。如果现场必须定时重连也要先SQLDisconnect再SQLConnect。这一条算是做InTouch数据库最常见的血泪经验80%的写库慢问题都是连接没释放。6. 进阶从Excel表升级到轻量Web报表的过渡方案Excel报表做到第三个月你大概率会遇到新的需求生产经理要在手机上看昨天夜班的产量质量主管要按批次筛温度曲线老板要在一个页面上看两个车间的对比。这时候再靠Excel文件分发光传文件就能占半天时间。我的习惯是提前把数据库当中间层Excel报表只是一个输出模板同时再加一层轻量Web报表系统。架构很简单SQL Server生产库保持现在这个结构不变新增一个只读账号给Web报表系统使用。Web端直接查TagReadings表用同样的GROUP BY聚合逻辑把班报、日报渲染成网页表格并提供按时间范围筛选的功能。报表系统的数据源只有数据库不再依赖InTouch也不依赖Excel这样即使InTouch停机历史数据照样能在浏览器里查到。这条路的落地成本不高一个简单的后端接口做查询前端表格展示再加一个导出Excel按钮。导出Excel可以复用第4章的SQL查询逻辑只是把VBA换成后端代码。如果不想自己开发也可以考虑现成的Web报表系统只要支持连接SQL Server基本上都能直接对接。需要留意的是不要让报表查询直接打到正在写库的生产库上高峰期会有锁等待。一种常见做法是用数据库同步软件把TagReadings表定期同步到一个独立的报表库然后Web报表只连报表库。这个同步可以每小时一次数据延迟1小时以内对大多数管理报表完全够用。新项目上线时我的建议是第一天先把TagReadings表结构和Excel报表模板定死再让InTouch去连库。表字段、点位名、时间格式这些一旦跑起来再改牵涉到历史数据迁移非常痛苦。我现在的习惯是库表和模板先做给甲方确认再回头配InTouch采集这套顺序能省掉很多返工也算是我吃过亏之后找到的后悔药。验证报表这条路是否可靠最直接的办法是随机抽查今天上午从SQL Server里查某点位的最大值同时翻看昨天生成的Excel报表对应格两边一致就说明链路是通的。连续抽查一周都不出错后面基本不用再看它了。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑