资讯动态

WinCC VBS+SQL报表:日报查询、统计与Excel打印实战

发布时间:2026/10/30 2:52:22 来源:尧图企业网站定制
简介这是一份围绕SIMATIC WinCC平台实现SQL报表查询与打印的实践文档面向工业自动化上位机开发、HMI组态及WinCC脚本学习者帮助解决生产数据按日期检索、表格展示与报表输出的问题。内容从Microsoft SQL Server 2005新建数据库、定义时间及CPU、内存、硬盘等字段开始延伸到WinCC全局脚本中用VBScript写入与查询数据并讲解MSFlexGrid、MS DTPicker控件在日报表画面中的组态、查询按钮取数及打印按钮导出Excel的处理附录给出可参考的VBS代码。资源包仅含1个doc文件大小约1.11MB便于集中查阅完整流程与脚本片段。已有1682人学习适合需要理解WinCC与SQL交互、控件绑定的技术人员对照实践积累报表画面设计与数据查询排错思路。1. 夜班交接前的那张日报表被我塞进了 WinCC 画面凌晨两点交接班操作工拿着手写表格去抄 CPU 和内存占用率抄完再敲进 Excel 发给值班长——这套「WINCC 报表 VBS脚本 SQL」方案要解决的就是这个场面。方案把现场变量按周期写进一张 SQL 表画面上放两个 DTPicker 选起止日期点“查询”MSFlexGrid 里就是整天的明细末尾自动补上 MAX / MIN / AVG 三行再点“打印”就落到 Excel 里预览输出。适合手里已经有 WinCC 项目、又被要求交日报周报的自动化工程师也适合不想装第三方报表组件、只想用现有全局脚本把历史数据拉出来的同学。整套东西不用编译、不打部署包改需求就是改几行 VBS。文档里从建库建表、控件注册到三段完整脚本都带着抄下来能直接跑。2. 全景拆解一条数据从现场变量走到 Excel 表格这套方案结构简单但层次分得清楚采集在 WinCC 的变量系统里存储在 SQL Server 的一张普通表里展示靠画面上的两个 ActiveX 控件输出借 Excel 的 COM 接口。四段之间只靠两样东西连接——OLEDB 连接串和画面元素名。把这两样记住了后面哪一段出问题都能一眼定位。2.1 四层数据流变量、SQL 表、ActiveX 控件、Excel按数据流动方向拆开看各层的承担者是这样的层次承担者关键动作采集层WinCC 内部变量cpu / ram / hdHMIRuntime.Tags(cpu).Read读取当前值存储层SQL Server 库中的报表表ADO 连接 INSERT 语句写入展示层MSFlexGrid 两个 DTPicker查询脚本把记录集铺进表格输出层Excel COM 对象单元格逐格赋值、加边框、打印预览写入链路和查询链路彼此独立全局脚本只管往表里写画面脚本只管从表里读两张脚本唯一的交集是“表名 字段名 连接串”这三样必须对得上。原文里恰好这三样都没统一——写入脚本把数据插进VBSReport表的time,cpu,ram,hd字段查询脚本却从report表读shijian,cpu,ram,harddisk连接串里的库名一个写SQL-Report、一个写Example-report。这种不一致在单机调试时很容易被“反正能跑”糊过去换台机器就全线崩后面避坑那一章会单独说。理解了这个分层调试思路也就有了表里没数据就查全局脚本的触发条件表里有数据但画面空就查查询脚本的 SQL 和字段名画面有数据但打印报错就查 Excel COM 调用。玄学问题基本不存在都是一层一层能验的。2.2 为什么是 VBS ADO而不是自带归档控件WinCC 自带的趋势和归档控件画曲线很好用但真要做“选个日期区间、列出每一行原始记录、末尾加统计行、再导成 Excel 打印”这种报表它就很别扭归档控件的查询条件受限于组态导出格式也由控件自己决定而且归档数据落在项目目录里别的系统想读就得额外折腾。VBS 方案的取舍很明确。好处是脚本直接跑在 WinCC 运行时进程里HMIRuntime.Tags读写变量零成本ADO 走 OLEDB 连 SQL Server 不需要额外装驱动数据落到标准数据库后别的系统、别的报表工具、甚至直接在管理工具里跑 SQL 都能读到。代价也得认全靠 COM 组件控件要注册SQL 是字符串拼出来的没有类型检查一个引号写错就整段执行失败脚本没有版本管理改错了只能靠记忆回滚。我一般会在项目初期就把这套东西的边界划清楚单表、单库、按天查询、数据量控制在几万行以内这套方案很舒服。如果要按班次、按产线、按几十个变量横向对比那就得往上堆 SQL 分组和索引脚本也会越来越长那时候不如换成存储过程 视图脚本只负责取结果。2.3 环境准备SQL 实例、WinCC 项目与 OCX 注册动手前先确认三件事都齐了缺一样后面都会卡住。第一步是 SQL Server 侧。打开管理工具连上实例在 Databases 上右键 New Database名字按项目约定取原文用的SQL-Report我建议直接用项目代号加_Report后缀省得以后几个项目撞名。然后在该库的 Tables 上右键 New Table把列名和数据类型填进去保存时给表起名。库名和表名一旦定下来后面所有脚本都得照抄别凭记忆敲。第二步是 WinCC 侧。新建项目、建内部变量、建主画面和报表画面这些都按常规走。真正容易卡的是 ActiveX 控件的注册——MSFlexGrid 属于 VB6 时代的组件Windows 默认不带。:: 32 位系统或 32 位进程把控件拷到 System32 后注册 copy MSFLXGRD.OCX C:\Windows\System32\ regsvr32 C:\Windows\System32\MSFLXGRD.OCX :: 解除注册控件版本冲突、画面打不开时用 regsvr32 /u C:\Windows\System32\MSFLXGRD.OCX命名的含义很直白regsvr32后面跟 OCX 的完整路径就是注册加/u是反注册。这里有个血泪经验——在 64 位系统上WinCC 运行时是 32 位进程只认 32 位控件必须用C:\Windows\SysWOW64\regsvr32.exe去注册放在SysWOW64目录下的 OCX用开始菜单里那个默认的 regsvr32 注册完了画面照样报“未注册类”。日期控件 DTPicker 依赖MSCOMCT2.OCX同样要按这个流程走一遍。第三步确认控件能在画面里被选到。在画面的 ActiveX Controls 上右键 Add/Remove列表里应该能看到Microsoft FlexGrid Control, Version 6.0和Microsoft Date and Time Picker Control 6.0 (SP4)。如果列表里没有说明注册没生效或者位数不对先回去查上一步别急着往脚本上找原因。提示把 OCX 拷进系统目录这一步等于给整台机器装了个全局组件。项目交付前记得在目标机器上重复一遍别只在开发机上验证。3. 写入链路建表规范与全局脚本 action写入这一段是整套方案的地基。表结构定歪了后面查询脚本怎么写都别扭触发周期定错了一天下来几万条冗余数据画面点查询要转半天。3.1 建库建表字段类型定死后面所有脚本图形界面点出来的表本质上就是一条 DDL。我把原文那张表还原成语句顺手把字段名统一了——原文写入脚本里时间字段叫time查询脚本里叫shijian这是第一处不一致建表时统一成shijian后面两张脚本都照这个写。-- 报表主表一行对应一次采样 CREATE TABLE dbo.VBSReport ( id INT IDENTITY(1,1) PRIMARY KEY, shijian DATETIME NOT NULL, -- 采样时刻与查询脚本字段名保持一致 cpu FLOAT NULL, -- CPU 占用率单位 % ram FLOAT NULL, -- 内存占用率单位 % harddisk FLOAT NULL -- 硬盘占用率单位 % ); -- 时间是唯一的查询条件必须建索引否则一天的数据都要全表扫 CREATE INDEX IX_VBSReport_shijian ON dbo.VBSReport(shijian);几个参数值得停一下。DATETIME而不是VARCHAR存时间是为了让BETWEEN能走索引、能按范围比较如果存成字符串2025-3-1和2025-03-01就是两个值区间查询立刻失效。三个指标用FLOAT够用如果现场变量本身是整型百分比用SMALLINT更省空间。id自增主键不是必须的但加了以后排查重复写入很方便——看id是不是连续就能判断全局脚本有没有被执行两次。原文用图形界面建表好处是直观坏处是字段类型选错了没人提醒。我习惯在图形界面建完之后右键生成一次脚本存到项目文档里换环境时直接执行不用再点一遍。3.2 action 函数逐段从读变量到写库全局脚本里的写入函数是最短的一段但每一行都有坑位。原文的action函数拆开看是这样Option Explicit Function action Dim a, b, c, d Dim strcn, cn, is_SQL 1. 取当前时间 三个现场变量 a Now b HMIRuntime.Tags(cpu).Read c HMIRuntime.Tags(ram).Read d HMIRuntime.Tags(hd).Read 2. OLEDB 连接串库名、实例名、认证方式三要素 strcn ProviderSQLOLEDB.1;Integrated SecuritySSPI; _ Persist Security InfoFalse; _ Initial CatalogSQL-Report;Data Source.\wincc 3. 打开连接并执行插入 Set cn CreateObject(ADODB.Connection) cn.ConnectionString strcn cn.Open is_SQL insert into VBSReport(shijian,cpu,ram,harddisk) Values( _ a , b , c , d ) cn.Execute is_SQL cn.Close Set cn Nothing End Function连接串的四个参数各有分工ProviderSQLOLEDB.1指定用 SQL Server 的 OLEDB 提供程序Integrated SecuritySSPI表示走 Windows 集成认证也就是用运行 WinCC 的那个系统账号登数据库不需要在脚本里放用户名密码Initial Catalog是数据库名必须和建库时写的一字不差Data Source.\wincc里的点代表本机wincc是实例名如果现场是默认实例就只写.。拼接 INSERT 那段是最脆的地方。Now返回的是区域格式的日期字符串中文系统下大致是2025/3/1 14:22:01这种形态SQL Server 一般能识别但一旦服务器语言设置或区域选项不同就会出现“从字符串转换日期和/或时间时失败”。稳妥做法是显式格式化 用 ISO 格式拼时间避开区域设置差异 Dim ts ts Year(a) - Right(0 Month(a), 2) - _ Right(0 Day(a), 2) _ Right(0 Hour(a), 2) : Right(0 Minute(a), 2) : _ Right(0 Second(a), 2)Right(0 x, 2)是补零的土办法个位数月份补成03SQL Server 无论什么区域设置都能按yyyy-mm-dd hh:mi:ss正确解析。这种写法比调Format()可靠因为Format()的输出受系统区域设置影响脚本换台机器结果就变。注意HMIRuntime.Tags(cpu).Read里的变量名必须和 WinCC 变量管理里完全一致大小写不敏感但拼写不能错。读不到变量不会报错只会返回空值写进库就是一堆 NULL。3.3 触发条件周期怎么定、数据量怎么估全局脚本写完只是躺在那儿不配触发器它一行都不会跑。原文特意标注了“注意全局脚本触发条件”这确实是新手最容易漏的一步。在全局脚本编辑器里给这个动作挂一个定时器触发器周期按需要选。周期和数据量的关系是可以算的1 秒一次一天 86400 条10 秒一次8640 条1 分钟一次1440 条。报表按天查1 分钟粒度已经足够看出趋势一天 1440 行铺进 MSFlexGrid 也不至于卡。真按秒级采一个月就是两百多万行查询脚本又没做分页点一次“查询”画面能僵在那儿十几秒操作工以为死机了。如果变量本身变化不频繁用“变量触发”比定时更省在 WinCC 里给变量配一个变化触发值变了才写一条。缺点是采样间隔不均匀做平均值统计时每个点的权重不一样对日报表来说这点误差通常能接受。还有一件事原文没提但必须做表大了之后要清理。最简单的办法是建一个每日执行的 SQL 作业把 N 天前的记录删掉或者转存到历史表。不清理的话两三年后这张表能撑到几个 G查询脚本即使有索引也会越来越慢。4. 查询链路DTPicker 取值、两条 SQL 与 MSFlexGrid 填充查询这一段是整套方案里代码量最大的部分也是最能体现设计思路的地方用一条 SQL 拿明细、另一条 SQL 拿统计避免在 VBS 里循环算最大最小平均用控件的TextMatrix直接定位单元格赋值避免一行行 Add。拆开看就四步。4.1 两个 ActiveX 控件插入画面与命名约定在日报表画面里从 ActiveX Controls 里把Microsoft FlexGrid Control, Version 6.0和Microsoft Date and Time Picker Control 6.0 (SP4)拖到画面上各放两个日期控件起、止一个表格控件。放好之后第一件事是改名字——脚本里全靠ScreenItems(名字)拿对象名字对不上就是运行时“对象不存在”。我一般约定成Date1起始、Date2结束、MSFlexGrid1表格和原文保持一致。控件属性里能改的项不少关键的几个是MSFlexGrid 的Rows和Cols决定初始行列数脚本里会重新赋Rows所以初始值不重要、FixedRows设 2 让前两行固定不滚动、FixedCols设 0。DTPicker 的Format属性设成日期格式操作工点开就是日历比手输靠谱。如果插入控件时画面报错、控件显示成红叉八成还是注册问题回第 2 章第 3 节按位数重新注册一遍。这一步没通后面所有脚本都白写。4.2 日期取值与合法性校验DTPicker 的Value属性直接就是Date类型取年月日不需要解析字符串Sub OnClick(ByVal Item) Dim Date1, Date2 Dim By, Bm, Bd, Ny, Nm, Nd Dim BeginDate, EndDate Set Date1 ScreenItems(Date1) Set Date2 ScreenItems(Date2) 取出起止日期的年月日 By Year(Date1.Value) : Bm Month(Date1.Value) : Bd Day(Date1.Value) Ny Year(Date2.Value) : Nm Month(Date2.Value) : Nd Day(Date2.Value) 起点补 00:00:00终点补 23:59:59保证当天数据不漏 BeginDate By - Bm - Bd 00:00:00 EndDate Ny - Nm - Nd 23:59:59 起止时间颠倒时给出提示 If By Ny Or (By Ny And Bm Nm) Or (By Ny And Bm Nm And Bd Nd) Then MsgBox 输入的时间不正确, vbOK, 错误的起始时间 Exit Sub 原文缺这一句见第 5 章 End If End Sub校验那段的多条件判断按“年大 → 同年月大 → 同年月日大”逐级比较短句Or连起来虽然不好看但逻辑是对的。真正的问题在没有Exit Sub提示弹完之后脚本继续往下跑还是会去查一个非法区间结果要么空结果集、要么 SQL 报错。这是我加的第一处改动。日期拼成2025-3-1 00:00:00这种没有补零的格式SQL Server 能认因为它是按yyyy-m-d解析的。但如果哪天要把这套逻辑搬到别的数据库就得改成补零的 ISO 格式别指望每个数据库都这么宽容。4.3 明细 聚合两条 SQL一次把数据拿全查询用两条 SQL一条出明细、一条出统计都在同一次点击里执行 明细按时间升序取出区间内所有原始记录时间统一成 19 位字符串 Sql SELECT CONVERT(char(19), shijian, 20) AS shijian, cpu, ram, harddisk _ FROM report WHERE shijian BETWEEN BeginDate AND EndDate _ ORDER BY shijian 统计一次算出 3 个指标的 avg / min / max共 9 个值 Sql1 SELECT avg(cpu) AS ylp, avg(ram) AS wdp, avg(harddisk) AS llp, _ min(cpu) AS ylx, min(ram) AS wdx, min(harddisk) AS llx, _ max(cpu) AS yld, max(ram) AS wdd, max(harddisk) AS lld _ FROM report WHERE shijian BETWEEN BeginDate AND EndDate CONVERT(char(19), shijian, 20)里的20是 ODBC 标准样式输出固定为yyyy-mm-dd hh:mi:ss长度正好 19 位。这一步很关键明细查出来的时间如果直接按DATETIME显示VBS 转字符串时会带上毫秒和区域格式铺进表格里长短不一看着很乱。转成定长字符串后后面用Mid(t,11,16)截取时分秒也不会错位。BETWEEN是闭区间起点00:00:00、终点23:59:59正好把整天圈进来。用 次日 00:00:00的开区间写法更严谨不会漏掉23:59:59.500这种毫秒数据但现场变量按分钟采的话这个差异可以忽略。两条 SQL 共用一个连接省掉一次握手开销。命令对象用CommandType 1即adCmdText直接执行文本Set oRs oCom.Execute拿记录集。这里有个细节原文做对了连接对象设了CursorLocation 3adUseClient客户端游标所以oRs.RecordCount能拿到真实行数。默认的服务端游标下RecordCount返回-1后面MSFlexGrid1.Rows oRs.RecordCount 6就会算出个负数控件直接报错。统计那条 SQL 的结果只有一行取出来是 9 个字段 统计结果只有一行直接按别名取 ylp oRs1(ylp) : wdp oRs1(wdp) : llp oRs1(llp) 平均 ylx oRs1(ylx) : wdx oRs1(wdx) : llx oRs1(llx) 最小 yld oRs1(yld) : wdd oRs1(wdd) : lld oRs1(lld) 最大变量名用的是拼音首字母ylp 利用率平均、ylx 最小、yld 最大对应 cpuw开头对应内存ll开头对应硬盘。这种命名在小脚本里能接受一旦要让别人接手还是改成avgCpu / minCpu / maxCpu更省事——这也是二次开发那一章要动手改的第一件事。4.4 填充 MSFlexGrid行数、表头与统计行记录集拿到之后剩下的就是往表格里铺。这一步的核心是算清楚行号Set MSFlexGrid1 ScreenItems(MSFlexGrid1) MSFlexGrid1.Clear MSFlexGrid1.Rows oRs.RecordCount 6 2 行表头 N 行数据 3 行统计 1 行余量 列宽按内容估单位是像素 MSFlexGrid1.ColWidth(0) 900 序号 MSFlexGrid1.ColWidth(1) 1900 时间 MSFlexGrid1.ColWidth(2) 1000 CPU% MSFlexGrid1.ColWidth(3) 1000 RAM% MSFlexGrid1.ColWidth(4) 1100 HardDisk% 第 0 行合并成一整条标题 For z 0 To 4 MSFlexGrid1.Col z MSFlexGrid1.Text Computer Ultilization Message(per Day) Next MSFlexGrid1.MergeCells 4 flexMergeFree允许任意单元格合并 MSFlexGrid1.MergeRow(0) True 按行方向合并 第 1 行是列名 MSFlexGrid1.TextMatrix(1, 0) NO. MSFlexGrid1.TextMatrix(1, 1) Time MSFlexGrid1.TextMatrix(1, 2) CPU% MSFlexGrid1.TextMatrix(1, 3) RAM% MSFlexGrid1.TextMatrix(1, 4) HardDisk% 最后三行的行首标签 MSFlexGrid1.TextMatrix(oRs.RecordCount 3, 0) MAX MSFlexGrid1.TextMatrix(oRs.RecordCount 4, 0) MIN MSFlexGrid1.TextMatrix(oRs.RecordCount 5, 0) AVGTextMatrix(row, col)是 MSFlexGrid 最常用的属性直接按行列坐标读写文本不需要先定位再赋值。行号分配是0 行合并标题、1 行列名、2 到RecordCount1是数据、3 / 4 / 5分别是 MAX / MIN / AVG。原文里2那行是 SUM被注释掉了——三个百分比相加没有业务含义删得对。MergeCells 4对应flexMergeFree配合MergeRow(0) True第 0 行相邻的同内容单元格才会合起来。如果不设MergeCellsMergeRow是不生效的标题会显示成五段重复文字这是很典型的一处顺序依赖。数据循环里有两个细节要留意For i 1 To oRs.RecordCount MSFlexGrid1.TextMatrix(i 1, 0) i 序号从 1 开始 Next这段单独跑一遍循环只为填序号然后才是真正铺数据的那段Do While Not oRs.EOF。分成两段的原因很简单TextMatrix的行号要先确定而填充数据时会移动游标。原文在数据循环里还夹了一句n n 1n在上面已经被赋成RecordCount用过了循环里再自增就把它污染了——后面再用n做判断的地方全都不对。这种变量复用是脚本里最常见的隐性 bug改的时候直接把循环里那句删掉。时间列的显示还做了一次条件处理起止日期是同一天时只显示Mid(t, 11, 16)也就是hh:mm跨天时显示完整时间戳。这样单日报表清爽多日报表也不会混。提示Rows一次赋到位不要在循环里往AddItem。MSFlexGrid 每改一次行数都会重绘几百行逐条加能明显看到闪烁。4.5 打印MSFlexGrid 转 Excel 再预览打印这一段不碰数据库纯粹是把表格内容搬到 ExcelSet MSFlexGrid1 ScreenItems(MSFlexGrid1) Set ExcelApp CreateObject(Excel.Application) Set ExcelBook ExcelApp.Workbooks.Add Set ExcelSheet ExcelBook.Worksheets(1) ExcelApp.Visible True 调试期开着看交付时建议改 False 逐格搬运Excel 的 Cells 行列都从 1 开始控件从 0 开始 For irow 0 To MSFlexGrid1.Rows - 1 For icol 0 To MSFlexGrid1.Cols - 1 ExcelSheet.Cells(irow 1, icol 1) Trim(MSFlexGrid1.TextMatrix(irow, icol)) Next Next 给数据区加外框1 左 2 右 3 上 4 下 z MSFlexGrid1.Rows ExcelSheet.Range(A1:E z).Borders(1).Weight 2 ExcelSheet.Range(A1:E z).Borders(2).Weight 2 ExcelSheet.Range(A1:E z).Borders(3).Weight 2 ExcelSheet.Range(A1:E z).Borders(4).Weight 2 ExcelSheet.Rows(1).RowHeight 0.75 / 0.035 厘米转磅 ExcelSheet.Cells.EntireColumn.AutoFit ExcelSheet.Rows(1).Font.Name 宋体 ExcelSheet.Rows(1).Font.Bold True ExcelSheet.Cells.HorizontalAlignment 3 居中 ExcelSheet.PageSetup.CenterHorizontally True ExcelSheet.PrintPreview 换成 PrintOut 就直接打印 ExcelBook.Close ExcelApp.Quit Set ExcelApp Nothing行列索引的错位是最容易翻车的地方控件TextMatrix(0,0)对应 Excel 的Cells(1,1)所以取的时候要统一1。整个搬运是双层循环单元格数量等于行数乘列数一天 1440 行就是七千多次 COM 调用能明显感觉到卡顿——不追求样式的场景直接把二维数组一次性赋给Range.Value会快一个数量级。RowHeight那个0.75 / 0.035是把厘米换算成磅Excel 的行高单位是磅1 厘米约等于 28.35 磅所以反过来除。这种魔法数字建议提出来定义成常量。ExcelApp.Quit和Set ExcelApp Nothing这两句千万不要省。少一句Excel 进程就常驻在后台操作工点十次打印就攒十个EXCEL.EXE最后内存吃满现场排查起来一头雾水。真出了这事任务管理器里结束进程只是临时办法根治还得靠脚本里成对写QuitNothing。PrintPreview和PrintOut二选一前者先给操作工看一眼再决定打不打后者点一下就出纸。车间里我倾向用预览省纸也省得打错了重新来。5. 避坑与排查控件注册、连接串、字段名最容易耗掉一整天这套方案代码量不大但涉及 WinCC、Windows 组件、SQL Server、Excel 四个独立系统任何一处配置不一致现象都很像“脚本写错了”。下面几条是我在这类项目里反复遇到的。现象一画面一打开就报“未注册类”或者控件位置显示红叉。原因MSFlexGrid / DTPicker 属于 COM 组件开发机上装过 VB6 所以能选到目标机器上根本没注册或者注册了 64 位版本而 WinCC 运行时是 32 位进程加载不了。 解决先用C:\Windows\SysWOW64\regsvr32.exe注册SysWOW64目录下的MSFLXGRD.OCX和MSCOMCT2.OCX重启 WinCC 运行时再看。如果还不行在画面里删掉控件重新插一遍——控件对象里存的是 CLSID注册信息变了以后旧对象可能失效。现象二查询报“对象名 report 无效”或者语句能跑但永远查出 0 行。原因写入脚本和查询脚本用的不是同一张表、同一批字段、同一个库。原文里写入插的是VBSReport(time,cpu,ram,hd)查询读的是report(shijian,cpu,ram,harddisk)连接串的Initial Catalog一个写SQL-Report、一个写Example-report——三处全对不上。 解决把库名、表名、字段名、连接串这四样写在一张纸上贴显示器边上所有脚本只能出现纸上的名字。改完在管理工具里先跑一遍同样的 SELECT确认有数据再回画面点按钮。现象三oRs.RecordCount得到 -1接着Rows -1 6控件报参数错误。原因ADO 默认用服务端游标RecordCount不可用返回 -1。 解决打开连接后、执行查询前给Connection设CursorLocation 3adUseClient改用客户端游标。代价是大结果集会一次性拉到内存几万行以内没问题上十万行就该考虑分页了。现象四日期选的是当天但只能查到前一天的记录或者一条都查不到。原因结束时间没补到23:59:59BETWEEN 2025-3-1 00:00:00 AND 2025-3-1 00:00:00只能命中零点整那一条或者时间字段是VARCHAR类型2025-3-1和2025-03-01字符串比较时排序结果和预期相反。 解决时间字段一律用DATETIME查询时起点补00:00:00、终点补23:59:59。拼接前先Exit Sub拦掉非法区间别让脚本带着错日期往下跑。现象五全局脚本编译通过、运行时也不报错但表里就是没数据。原因触发器没配或者配了但周期设得太长比如 1 小时一次调试时等了五分钟以为没生效也可能是HMIRuntime.Tags(cpu)里的变量名拼错读到的是空值插进去全是NULL。 解决先看全局脚本编辑器里那个动作有没有挂触发器再把周期临时改成 10 秒验证。变量名直接从变量管理里复制别手敲。验证阶段可以在脚本里加一行HMIRuntime.Trace action fired: Now vbCrLf输出到 WinCC 的诊断窗口比弹MsgBox温和得多——运行时弹窗会阻塞画面刷新。现象六打印几次之后机器变慢任务管理器里躺着一排EXCEL.EXE。原因脚本中途报错跳过了Quit或者只写了Close没写Quit。 解决把ExcelBook.Close和ExcelApp.Quit放在错误处理之后也要执行的路径上VBS 里没有finally至少保证正常路径上成对出现末尾加Set ExcelApp Nothing释放引用。6. 二次开发把一次性脚本改成能维护的报表模块这套脚本能跑但它是按“一次性交付”写的连接串硬编码在每个 Sub 里字段名中英混用变量名是拼音首字母SQL 靠字符串拼。要在这上面继续加需求按班次统计、多变量对比、导出 PDF不先做一轮整理改到第三个需求就会失控。几个改动优先级最高的地方现状改法收益连接串散落在每个 Sub抽成一个GetConn()函数放全局脚本换库只改一处表名字段名不统一建视图v_report屏蔽差异查询脚本不再关心物理表字符串拼 SQLADODB.CommandCreateParameter免去转义防注入拼音变量名改成avgCpu / minRam这类交接成本直线下降最值得先做的是连接串和查询的封装。全局脚本里加一个函数画面脚本只调它 全局脚本统一连接入口换库只改这里 Function GetConn() Dim cn Set cn CreateObject(ADODB.Connection) cn.ConnectionString ProviderSQLOLEDB.1;Integrated SecuritySSPI; _ Initial CatalogSQL-Report;Data Source.\wincc cn.CursorLocation 3 客户端游标保证 RecordCount 可用 cn.Open Set GetConn cn End Function验证方法很土但有效改完之后先不点画面按钮在管理工具里把同一条 SQL 手工跑一遍看结果集的行数和首末行时间对不对对得上再回画面点查询两边数字一致才算通过。这个顺序能帮你区分“SQL 写错了”和“脚本搬数据搬错了”省掉大量来回猜的时间。还有一个具体技巧查询结果超过 2000 行时别一次性铺满表格加个TOP 2000或者按小时分段加载并在画面角落显示“共 N 条显示前 2000 条”。操作工真正关心的往往是趋势和统计行明细只是佐证把画面拖死反而没人用。从那以后我每次接这类报表需求都先把库名、表名、字段名、连接串四样东西抄在一张纸上贴在显示器边上脚本里只允许出现纸上的名字写完再对着纸逐字核一遍——这套笨办法救过我至少三次通宵。希望帮到你。本文还有配套的精品资源点击获取

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

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

免费获取报价 →
↑