☰
WINCC SQL报表查询方案:VBScript实现日报表数据采集与展示
2026/10/30 5:15:06 网站建设 项目流程

简介:这份文档面向已具备WinCC组态基础、希望打通SQL报表查询链路的工控技术人员,围绕VBScript脚本与ActiveX控件在SIMATIC WinCC中的应用展开,重点解决生产数据写入数据库、按日期查询并在画面中展示与打印的问题。压缩包仅含1个doc文件,大小约1.11MB,内容以操作说明、画面组态要点和脚本示例为主,便于集中查阅与对照实践。文档覆盖SQL Server 2005建库建表、WinCC全局脚本写入记录、MSFlexGrid与MS DTPicker控件配置,以及“查询”“打印”按钮的VBS实现,并附写入和查询SQL数据的代码附录,可帮助读者理解从数据采集到报表输出的完整流程。目前已有1682人学习,适合需要参考WinCC SQL报表搭建思路与脚本写法的读者。

1. 从手抄日报到一键查询:这套 WINCC SQL 报表方案解决什么问题

某条产线的操作工每班结束要手抄三个数——CPU 负载、内存占用、硬盘余量——抄在纸质日报上,班组长再录进表格。画面上的数在实时跳动,但没人能按天把它拉出来。这套基于 VBScript 和控件实现的 WINCC SQL 报表查询方案,解决的就是“画面有数、报表没数”这件事:WINCC 全局脚本周期把变量写进 SQL 表,日报表画面上的 MSFlexGrid 和 MS DTPicker 负责选日期、显示结果,查询和打印都由 VBS 脚本驱动。它适合正在做上位机报表课设、毕设,或者现场需要补一套轻量日报表的人。下面按数据链路、画面组态、脚本实现、排查、验收的顺序拆开讲,每一段都落到能直接改的参数和代码上。

2. 数据链路设计:从 WINCC 变量到 SQL 表的三段式结构

2.1 报表表结构:四个字段先定死

先说表。原文写入脚本里表叫 VBSReport,字段是 time、cpu、ram、hd;查询脚本里表叫 report,字段是 shijian、cpu、ram、harddisk。同一个项目里两套命名,是后面“查不到数据”的第一大来源。我一般会在动手写脚本之前,先把库名、表名、字段名写成一张对照表贴在项目边上,后面所有脚本只认这一份。

建表语句通常这样写:

-- 报表主表:一条记录对应一次采样 CREATE TABLE Report ( shijian DATETIME NOT NULL, -- 采样时刻,写入时取 Now cpu FLOAT NULL, -- CPU 占用率,单位 % ram FLOAT NULL, -- 内存占用率,单位 % harddisk FLOAT NULL -- 硬盘占用率,单位 % );

字段类型的选择有讲究。时间用 DATETIME 而不是 VARCHAR,BETWEEN 比较才能走索引,也免得字符串排序把“10 点”排到“9 点”前面;三个指标用 FLOAT,现场变量可能是整型也可能是浮点,FLOAT 兜得住。按一天 1440 条、一年五十多万条估算,给 shijian 建一个非聚集索引,按天查询的响应基本在毫秒级:

CREATE INDEX IX_Report_shijian ON Report(shijian);

提示:库名建议统一叫 SQL-Report,别在写入脚本里写一个、查询脚本里写另一个。原文示例里出现的 Example-report 就是典型的手滑,查半天查不出数据,最后发现连的是另一个库。

建库操作本身不复杂:打开 SQL Server Management Studio 连上实例,Databases 右键 New Database,名字填 SQL-Report;展开库,Tables 右键 New Table,按上面的字段填 Column Name 和 Data Type,保存时给表名 Report。库和表建完,再回 WINCC 写全局脚本。

2.2 全局脚本写入:ADO 连接与 INSERT

WINCC 的全局脚本挂在项目树下的 Global Script 里,新建一个 VBS 动作,函数名保持 action。下面这段是写入链路的核心:

' WINCC 全局脚本:周期把三个变量写入 SQL 报表表 Option Explicit Function action Dim a, b, c, d Dim strcn, cn, is_SQL a = Now ' 采样时间 b = HMIRuntime.Tags("cpu").Read ' CPU 占用率 c = HMIRuntime.Tags("ram").Read ' 内存占用率 d = HMIRuntime.Tags("hd").Read ' 硬盘占用率 strcn = "Provider=SQLOLEDB.1;Integrated Security=SSPI;" & _ "Persist Security Info=False;" & _ "Initial Catalog=SQL-Report;Data Source=.\wincc" Set cn = CreateObject("ADODB.Connection") cn.ConnectionString = strcn cn.Open is_SQL = "INSERT INTO Report(shijian, cpu, ram, harddisk) VALUES('" & _ a & "','" & b & "','" & c & "','" & d & "')" cn.Execute is_SQL cn.Close Set cn = Nothing End Function

连接字符串四段各管一件事:Provider 指定 SQLOLEDB;Integrated Security=SSPI 表示用 Windows 账户验证,不写用户名密码;Initial Catalog 是库名;Data Source 里的.\wincc是实例名,默认实例可以直接写机器名或一个点。HMIRuntime.Tags("cpu").Read 读的是 WINCC 变量管理器里建好的内部变量,名字必须和变量表里一字不差,多一个空格都读不到。

日期拼接这里有个细节值得单独说。Now 转成字符串会跟着操作系统区域设置走,如果现场是中文日期格式,拼进 SQL 可能变成“2024/5/6 10:00:00”,SQL Server 一般能认,但不保险。稳妥的做法是显式格式化后再拼:

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)

多写三行,省掉后面排查日期格式的时间。写入失败的处理也别省,cn.Execute抛错会直接中断脚本,可以在外面包一层On Error Resume Next,把错误码写进一个 WINCC 内部变量,画面上做个报警灯,比事后翻日志快得多。

2.3 触发周期:写多密才算合适

全局脚本建好后要挂触发器。WINCC 的全局脚本触发器可以按周期、按变量变化、按事件,报表场景一般用周期触发。周期怎么定,看两个约束:一是报表要什么粒度,日报表只关心小时级趋势,5 分钟足够;二是数据库增长,1 分钟一次一天 1440 条,5 分钟一次一天 288 条,一年差五倍。

触发方式适用场景注意点
周期触发(1 分钟)需要分钟级趋势数据量大,索引要跟上
周期触发(5 分钟)日报表、班报表推荐,量级可控
变量变化触发只在异常时记录容易漏采,不适合连续报表
事件触发(按钮)手动补录依赖操作,不能作为主链路

触发时间建议错开整点,比如每 5 分钟的 30 秒触发,避免多个脚本同时打数据库。写完脚本先别急着组态画面,打开 SSMS 看一眼表里有没有新记录:有记录,说明写入链路通了;没记录,先查全局脚本的运行状态和触发器是否启用,别去画面里找原因。

3. 画面组态与控件落位:MSFlexGrid 和 DTPicker 怎么装进画面

3.1 控件注册:regsvr32 两条命令先跑通

原文提到,直接在 ActiveX Controls 里选 Microsoft FlexGrid Control, Version 6.0 时,如果机器上没装过 VB6,控件可能不在列表里,需要手工注册 MSFLXGRD.OCX。步骤是:把 OCX 拷到系统目录,然后在“开始→运行”里执行注册命令。32 位系统拷到 C:\WINDOWS\system32,64 位系统要放到 SysWOW64,否则注册了 WINCC 也认不到。

regsvr32 MSFLXGRD.OCX regsvr32 /u MSFLXGRD.OCX

第一条是注册,弹“DllRegisterServer in MSFLXGRD.OCX succeeded”才算成功;第二条带 /u 是反注册,换版本或者卸载时用。注册报“模块加载失败”,先确认文件位数和系统位数是否匹配,再用管理员权限开命令窗口重试。DTPicker 对应的是 MSCOMCT2.OCX,添加控件时选 Microsoft Date and Time Picker Control 6.0 (SP4)。两个控件都注册好之后,在 WINCC 画面编辑器里右键 ActiveX Controls → Add/Remove,把它们勾进列表,再拖到画面上。

控件列表里找不到的情况,多半是注册表里没有这个 CLSID,或者 WINCC 是以另一个用户身份跑的。换管理员账户登录再注册一次,通常能解决。

3.2 画面布局与控件命名

项目结构一般是三个画面:主画面做导航,报表画面做汇总,日报表画面做查询和表格。日报表画面上放两个 DTPicker、一个 MSFlexGrid、两个按钮。控件拖进去之后第一件事是改 Name 属性,因为脚本里用 ScreenItems("名字") 取对象,名字对不上,脚本跑到那一行就报“对象不存在”。我习惯按功能命名,不直接用默认的 DTPicker1、MSFlexGrid1。

控件名类型作用关键属性
Date1MS DTPicker起始日期Format 设为短日期
Date2MS DTPicker结束日期Format 设为短日期
MSFlexGrid1MSFlexGrid结果显示Cols=5,Rows 由脚本动态设
btnQuery按钮触发查询OnClick 挂查询脚本
btnPrint按钮导出打印OnClick 挂打印脚本

MSFlexGrid 的外观属性不用在属性面板里一个个点,画面初始化时用脚本设一次更清楚:

' 画面打开时调用:设定表格骨架,查询脚本里只改内容 MSFlexGrid1.Cols = 5 MSFlexGrid1.Rows = 10 MSFlexGrid1.FixedCols = 0 MSFlexGrid1.FixedRows = 2 MSFlexGrid1.ColWidth(0) = 900 MSFlexGrid1.ColWidth(1) = 1900 MSFlexGrid1.ColWidth(2) = 1000 MSFlexGrid1.ColWidth(3) = 1000 MSFlexGrid1.ColWidth(4) = 1100

FixedRows=2 表示前两行固定不随滚动消失:第一行是合并后的标题,第二行是列名。ColWidth 的单位是像素级,序号列 900、时间列 1900,剩下的指标列各 1000 出头,基本不用再横向滚动。

3.3 变量绑定与画面切换

WINCC 变量管理器里建三个内部变量:cpu、ram、hd,类型选浮点,和全局脚本里 HMIRuntime.Tags 读的名字保持一致。如果现场是从 PLC 采上来的,这里可以换成外部变量,全局脚本不用改。变量类型别随手选成整型,现场 CPU 占用率经常带小数,整型会把小数截掉,报表上看着像少了精度。

画面切换用按钮的鼠标单击事件挂 OpenPicture,或者组态画面窗口。日报表画面建议做成弹出式,查询完关掉回主画面,避免操作工在多个画面之间迷路。组态完先别写查询脚本,先在画面上放一个临时按钮,脚本里写一句 MsgBox Date1.Value,点一下看能不能取到日期。取不到,说明控件名或者控件本身有问题,先解决这个再往下走,比在几百行查询脚本里定位快。

4. 查询与打印:两条脚本把数据送上屏、送上纸

4.1 时间参数组装与合法性校验

DTPicker 的 Value 是日期型,脚本里取年、月、日拼成字符串,再补上时分秒:

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) 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 "输入的时间不正确", vbOKOnly, "错误的起始时间" Exit Sub End If

起始时间补 00:00:00、结束时间补 23:59:59,BETWEEN 这个闭区间才能把当天的数据完整包进来。月份和日期不补零也能被 SQL Server 识别,但补零更稳,遇到区域设置不同的机器不至于翻车。原文的校验只弹了 MsgBox 没有退出,脚本会继续往下跑,查一个起止倒序的区间,结果为空还以为是数据问题——这个 Exit Sub 是必须加的。

4.2 两条 SQL:明细给表格,聚合给统计行

查询分两条:一条拉明细给表格,一条算最大、最小、平均给底部统计行。明细 SQL 里用 CONVERT 把时间转成 19 位字符串,省得在 VBS 里再处理日期格式:

Dim Sql, Sql1 Sql = "SELECT CONVERT(char(19), shijian, 20) AS shijian, cpu, ram, harddisk " & _ "FROM Report WHERE shijian BETWEEN '" & BeginDate & "' AND '" & EndDate & "' " & _ "ORDER BY shijian" 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) 的输出格式是 yyyy-mm-dd hh:mi:ss,20 是 ODBC 标准样式,正好 19 个字符。BETWEEN 两端都包含,配 00:00:00 和 23:59:59 覆盖一整天。连接和取数用 ADODB:

Dim conn, oRs, oCom, oRs1, oCom1 Dim strcn strcn = "Provider=SQLOLEDB.1;Integrated Security=SSPI;" & _ "Persist Security Info=False;Initial Catalog=SQL-Report;Data Source=.\wincc" Set conn = CreateObject("ADODB.Connection") conn.ConnectionString = strcn conn.CursorLocation = 3 ' adUseClient,RecordCount 才准 conn.Open Set oCom = CreateObject("ADODB.Command") oCom.CommandType = 1 Set oCom.ActiveConnection = conn oCom.CommandText = Sql Set oRs = oCom.Execute Set oCom1 = CreateObject("ADODB.Command") oCom1.CommandType = 1 Set oCom1.ActiveConnection = conn oCom1.CommandText = Sql1 Set oRs1 = oCom1.Execute

CursorLocation = 3 是关键,服务端游标下 RecordCount 经常返回 -1,表格行数就算错,填到一半越界。聚合结果用

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询