尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
WINCC+SQL Server+VBS实现配方导入与自动报表生成实战
做WINCC项目这几年最让我觉得“花时间花得值”的一件事就是把SQL SERVER和VBS脚本彻底揉进了WINCC里实现了配方数据自动导入、生产报表自动生成。以前遇到报表需求我的第一反应是用WINCC自带的变量记录和报表控件后来发现一旦牵涉到多批次、多配方、跨班次查询这套组合用起来非常别扭数据越积越多查询越来越慢而且报表格式基本定死想加一列都得重新折腾模板。后来我直接把SQL SERVER拉进来用VBS在WINCC里写脚本把变量数据写入数据库、从数据库读取配方参数再到生产结束后自动生成Excel报表整套流程跑下来以后工厂那边基本不用人工碰数据了。这篇文章会把整个方案的思路、库表设计、脚本核心代码、踩过的坑都拆开来讲。适合正在做WINCC二次开发的工程师或者是想学VBS脚本不知道怎么入手的工控朋友。源码级别的关键代码我会贴出来照着改就能用重点是把“为什么这么写”“为什么这么连”讲清楚而不是只给一段能跑的代码就完事。1. 为什么要在WINCC里用SQL变量导入与配方报表的项目背景1.1 先理解需求配方报表到底要解决什么在这个项目里车间有几条产线每台设备生产不同产品时需要下发一组工艺参数比如温度、压力、时间、转速等。这套参数我们通常叫“配方”。生产之前操作工要在WINCC画面上选择当前要生产的产品把对应配方参数下发给PLC生产过程中PLC会实时反馈实际温度、实际压力等状态值生产结束后还需要把这一批产品的实际参数、操作员、时间、判定结果等信息整理成一张报表用来做质量追溯。这里面的核心问题有两个一是配方的保存和下发二是生产记录的归档和追溯。配方如果写在WINCC变量里关机重启就没了而且换产品的时候靠人工输参数效率低不说还容易输错。生产记录如果只存在变量归档里报表功能就得依赖WINCC的报表组件查询条件和输出格式都非常受限。所以我把数据层独立出来用SQL SERVER统一管理配方和生产记录。WINCC通过VBS脚本扮演“中间人”角色负责把变量往数据库写、从数据库往变量读这样整个系统就变成了配方维护在数据库里画面上选择产品编号后按下开始按钮VBS从SQL SERVER把参数读出来写入WINCC变量再下发到PLC。生产过程中VBS周期性地把PLC反馈的实际值写入SQL SERVER。生产结束或者换班时操作员点击“生成报表”VBS按批号把数据库里的记录查出来导出成Excel顺便还能在WINCC画面里用表格控件展示。这样的架构数据是“我们自己的”想怎么查就怎么查想怎么展示就怎么展示后期接MES系统也方便。这是我最终愿意花时间去写脚本的根本原因。1.2 方案选型为什么不用WINCC自带报表非要自己写SQL很多人在这个环节会犹豫毕竟WINCC自带的变量记录和报表功能是“官方方案”不用写代码拖拖拽拽就能出曲线和报表。我并不是说官方方案一无是处趋势曲线用变量记录确实方便但配方管理和批次报表这块自带功能的短板非常明显。我把两种方案做了一张对比表方便大家按自己的场景去选对比项WINCC变量记录 报表控件WINCC SQL SERVER VBS数据结构由WINCC内部管理字段固定自己建表字段完全可控历史数据查询数据量大后查询变慢条件定制困难SQL自由查询索引优化后性能有保证配方管理不方便没有专门功能数据库里一张表就能解决报表格式模板灵活度低改动成本高Excel导出想怎么排就怎么排对接MES/ERP需要额外开发接口其他系统可以直接读库开发门槛低需要会VBS和基础SQL维护成本依赖特定版本和控件环境升级可能有问题数据独立环境依赖相对小以我的项目经验如果是单机设备、数据量小、报表需求固定且简单用自带功能确实省事没必要折腾。但只要涉及多产品、多配方、多批次或者工厂有数据追溯和系统集成需求直接上SQLSERVER是更靠谱的选择。这套方案的扩展性和可控性是自带报表给不了的。1.3 技术路线与整体流程拆解整个项目没有用任何外部插件核心就是三点WINCC的VBS脚本、ADODB数据库访问组件、SQL SERVER数据库。听起来高大上拆开看其实就是一个套路用VBS建立到SQLSERVER的连接然后把WINCC变量和数据库字段互相搬运。先看整体数据流向PLC实时值通过驱动进入WINCC变量这是WINCC的基本功能。VBS脚本按触发条件读取WINCC变量通过ADODB把数据写入SQL SERVER的表。操作员在WINCC画面操作按钮VBS从SQL SERVER读取配方记录解析后写入WINCC内部变量或输出域。画面上的输入输出域与外部变量绑定WINCC自动完成变量到PLC的写操作配方参数也就送到了PLC。生产结束时VBS查询SQL SERVER里的生产记录筛选批号和时间范围通过Excel对象模型生成报表文件保存到指定网络路径。这个流程里WINCC只负责变量采集和画面交互VBS负责逻辑串联SQLSERVER负责数据存储。每个环节的职责非常清楚出了问题也比较好定位。接下来我会把每个环节的细节和代码逐一拆解。2. 数据库设计与SQLSERVER环境准备2.1 配方库表结构设计思路数据库设计的重点不是建多少张表而是想清楚你要存什么、怎么查。我复盘这个项目时发现最开始我把所有数据塞到一张大表里结果字段又长又多查询和写入都别扭。后来拆成“配方基础表”和“生产记录表”两张核心表逻辑一下就清楚了。第一张表是配方基础表专门存产品工艺参数的“标准值”。我一般是这么设计字段CREATE TABLE T_Recipe ( RecipeID INT IDENTITY(1,1) PRIMARY KEY, ProductCode NVARCHAR(50) NOT NULL, ProductName NVARCHAR(100), Rev NVARCHAR(20) DEFAULT A, TempSet FLOAT, -- 设定温度 PressSet FLOAT, -- 设定压力 TimeSet FLOAT, -- 设定时间 SpeedSet FLOAT, -- 设定转速 Remark NVARCHAR(200), CreateTime DATETIME DEFAULT GETDATE() );这里有个容易被忽略的点配方参数是用“一列一个参数”的方式还是“一行一个参数”的方式。一列一个参数宽表适合参数数量固定、报表直接引用列名的情况一行一个参数长表适合参数种类经常变、需要灵活扩展的情况。我建议配方数量不多、参数固定的项目用宽表代码写起来直观如果参数经常增删那用长表插入一条记录时只处理变化的参数扩展性更好。第二张表是生产记录表用来存每一批次的实际生产数据。这张表的特点是“一列一个实际值”也和配方表保持对应便于报表直接比对设定值和实际值CREATE TABLE T_Record ( RecordID INT IDENTITY(1,1) PRIMARY KEY, BatchNo NVARCHAR(50) NOT NULL, ProductCode NVARCHAR(50), ProductName NVARCHAR(100), OperatorName NVARCHAR(50), TempAct FLOAT, -- 实际温度 PressAct FLOAT, -- 实际压力 TimeAct FLOAT, -- 实际时间 SpeedAct FLOAT, -- 实际转速 JudgeResult NVARCHAR(10), -- OK/NG StartTime DATETIME, EndTime DATETIME, SaveTime DATETIME DEFAULT GETDATE() );BatchNo批号是整张表最重要的字段所有追溯都靠它。建议批号的命名规则放在PLC或者WINCC脚本里定义好格式类似“20250314A001”年-月-日-班次-流水号这样查询和筛选都非常高效。还可以给BatchNo建个索引否则数据量上去以后按批号查询会变慢CREATE INDEX IDX_BatchNo ON T_Record(BatchNo);2.2 SQLSERVER版本选择与配置要点SQLSERVER版本这一块很多人上来就问“用2008R2还是2019还是2022”。我的建议很直接能用新版就用新版老机器装2008R2也没问题但要注意几个关键配置否则后面连接会遇到一堆莫名其妙的问题。WINCC7.5和SQLSERVER的搭配官方有矩阵表我们现场最常见的配置是WINCC7.5SP2配SQLSERVER2016或2019。注意WINCC在安装时会要求本机装一个对应的SQLSERVER实例比如“WINCC”实例这个实例是WINCC自己用的和我们外接的业务数据库不是一回事。我们通过VBS访问的业务数据库可以建在WINCC本机实例里也可以建在独立的SQLSERVER服务器上。一般来说单机项目直接建在本机省事多台WINCC客户端共用数据时建议单独搞一台数据库服务器。环境配置时有几个开关必须打开SQLSERVER服务要启动SQLSERVER代理服务如果不需要作业调度可以不管。身份验证模式改成“SQL Server和Windows身份验证模式”免得VBS用SQL账号连不上。启用TCP/IP协议并把端口固定为1433。默认情况下SQLSERVER Express版或某些安装配置TCP/IP可能是关闭的VBS连的时候就会报“命名管道提供程序”或“TCP/IP提供程序”错误。Windows防火墙放行1433端口否则跨电脑连接必失败。创建SQL登录账号我这边的习惯是项目里统一用一个账号比如“szguest”密码单独管理不要直接用sa这种危险账号做业务连接。首次配置完成后建议先用SSMS手动连一次确认账号能登录、能看到自己建的库和表再去写VBS。别一上来就调试脚本那会把“账号不对”“密码不对”“表不存在”“权限不足”全混在一起很难定位。2.3 VBS连接SQLSERVER的标准姿势VBS访问SQLSERVER本质上就是通过ADODB接口操作。这部分代码是整个项目的地基我会在项目里单独写一个公共模块所有脚本开头都引用来复用。标准连接代码是这个样子的Dim gConn Set gConn CreateObject(ADODB.Connection) gConn.ConnectionString ProviderSQLOLEDB.1; _ Persist Security InfoFalse; _ User IDszguest; _ Password你的密码; _ Initial CatalogRecipeDB; _ Data Source127.0.0.1\MSSQLSERVER; gConn.CommandTimeout 10 gConn.Open关于Data Source这一项很多人搞不明白写法。如果是默认实例可以直接写成IP地址比如“192.168.0.10”如果是命名实例写法是“IP\实例名”比如“192.168.0.10\MSSQLSERVER”或者“192.168.0.10\WINCC”。我见过不少同事在这里把反斜杠写错或者把本机服务器名和IP混着写连接特别不稳定。连接字符串里的Provider如果写成“SQLNCLI11”或者“MSDASQL”在某些机器上没有装对应驱动就会报错。SQLOLEDB是微软比较老的Provider兼容性反而好基本所有Windows系统都自带所以我项目里就用它不会引入额外依赖。如果你用的是SQLSERVER2019之后的版本用SQLOLEDB同样没问题放心用。打开连接后执行SQL语句有两种常见方式一种是直接用Connection对象的Execute方法适合INSERT、UPDATE、DELETE这类不需要返回结果集的语句另一种是用Recordset对象适合SELECT查询。后面章节细说。3. VBS脚本核心代码拆解从变量导入到自动报表3.1 变量导入从PLC到数据库的完整链路“变量导入”这个说法在项目里有两种理解一种是把PLC变量导入到数据库另一种是把数据库的配方参数导入到WINCC变量。我这个项目里两步都有所以我把这块拆成“写库”和“读库”两个方向来讲。写方向就是生产过程中把WINCC变量里PLC反馈的实际值写入SQLSERVER记录表。核心逻辑是先读WINCC变量再拼SQL语句最后执行。WINCC VBS中读变量的标准姿势是用HMIRuntime.TagsDim tagTemp, tagPress Set tagTemp HMIRuntime.Tags(TempAct) Set tagPress HMIRuntime.Tags(PressAct) tagTemp.Read tagPress.Read Dim sqlInsert sqlInsert INSERT INTO T_Record (BatchNo, ProductCode, TempAct, PressAct, SaveTime) VALUES ( _ HMIRuntime.Tags(BatchNo).Value , _ HMIRuntime.Tags(ProductCode).Value , _ CDbl(tagTemp.Value) , _ CDbl(tagPress.Value) , _ Now _ ) gConn.Execute sqlInsert这里有几个非常容易踩的细节第一个字符串数据必须用单引号包起来。BatchNo和ProductCode在SQL里是NVARCHAR类型如果忘记加引号SQL就会报“列名无效”之类的错误。我早期经常在拼字符串时漏掉引号一漏就是语法错误而且还不容易看出来排查半天。第二个数值型数据尽量用CDbl转换一下。WINCC变量读出来Value属性的类型不固定有时是浮点数有时是字符串。直接拼接进SQL可能因为小数点分隔符的问题在非中文系统上把“85.5”拼成“855”或者“85,5”导致入库数据完全不对。用CDbl强制转成数值可以规避这个坑。第三个不建议一次性把几十个变量都用这种方式拼接代码会非常冗长。我在实际项目里是维护了一个“变量-字段”对应关系的数组循环处理Dim varNames, fieldNames varNames Array(TempAct, PressAct, TimeAct, SpeedAct) fieldNames Array(TempAct, PressAct, TimeAct, SpeedAct) Dim sqlFields, sqlValues sqlFields BatchNo, ProductCode sqlValues HMIRuntime.Tags(BatchNo).Value , _ HMIRuntime.Tags(ProductCode).Value Dim i For i 0 To UBound(varNames) Dim tagVal Set tagVal HMIRuntime.Tags(varNames(i)) tagVal.Read Dim numVal If IsNumeric(tagVal.Value) Then numVal CDbl(tagVal.Value) Else numVal 0 End If sqlFields sqlFields , fieldNames(i) sqlValues sqlValues , numVal Next gConn.Execute INSERT INTO T_Record ( sqlFields ) VALUES ( sqlValues )这样后续新增变量只需要维护数组不用大改代码。代码的可维护性对于工控项目来说非常重要因为现场动不动就加传感器、加变量你不可能每次都去翻那段几百行的SQL拼接逻辑。读方向就是从数据库读配方参数加载到WINCC变量再下发到PLC。这种业务一般在按钮事件里执行用Recordset读取Dim rs Set rs CreateObject(ADODB.Recordset) Dim sqlSelect sqlSelect SELECT * FROM T_Recipe WHERE ProductCode HMIRuntime.Tags(SelectedProduct).Value rs.Open sqlSelect, gConn, 1, 1 adOpenKeyset, adLockReadOnly If Not rs.EOF Then Dim tagSet Set tagSet HMIRuntime.Tags(TempSet) tagSet.Value rs.Fields(TempSet).Value tagSet.Write Set tagSet HMIRuntime.Tags(PressSet) tagSet.Value rs.Fields(PressSet).Value tagSet.Write End If rs.Close Set rs Nothing这里我建议用Recordset而不是Connection.Execute来跑查询因为Execute直接返回的结果集合在VBS里处理起来相对麻烦。 Recordset对象可以先判断EOF再一行一行取字段逻辑更直观。3.2 自动生成配方报表查询和导出Excel是怎么实现的报表生成是整个项目的重头戏。操作员在画面上输入批号点击生成报表系统从SQLSERVER查数据然后把结果写入Excel。先说查询。查询逻辑比较固定的场景可以直接拼SQL如果有多个条件注意条件的组合。我最常用的是按批号或者按时间范围两个维度Dim whereClause whereClause 11 If Trim(HMIRuntime.Tags(QueryBatchNo).Value) Then whereClause whereClause AND BatchNo HMIRuntime.Tags(QueryBatchNo).Value End If If Trim(HMIRuntime.Tags(QueryStartTime).Value) Then whereClause whereClause AND SaveTime HMIRuntime.Tags(QueryStartTime).Value End If If Trim(HMIRuntime.Tags(QueryEndTime).Value) Then whereClause whereClause AND SaveTime HMIRuntime.Tags(QueryEndTime).Value End If Dim sqlQuery sqlQuery SELECT * FROM T_Record WHERE whereClause ORDER BY SaveTime DESC用“11”这种写法是因为后面所有条件都可以用AND拼接不用去判断是不是第一个条件逻辑上省事。对于报表这种内部使用的查询完全够用。查询结果处理有两条路如果只是简单显示在WINCC画面上可以用WINCC自带的表格控件绑定查询结果如果要生成一份带格式的Excel文件就得用Excel对象模型。我项目里最终交付的是一份汇总Excel所以我用VBS启动Excel按行写入数据Dim objExcel, objWorkbook, objSheet Set objExcel CreateObject(Excel.Application) objExcel.Visible False Set objWorkbook objExcel.Workbooks.Add Set objSheet objWorkbook.Worksheets(1) 写表头 objSheet.Cells(1,1).Value 批号 objSheet.Cells(1,2).Value 产品编号 objSheet.Cells(1,3).Value 操作员 objSheet.Cells(1,4).Value 设定温度 objSheet.Cells(1,5).Value 实际温度 objSheet.Cells(1,6).Value 判定 ...类似于手工填表 从Recordset循环写数据 Dim row row 2 Do While Not rs.EOF objSheet.Cells(row,1).Value rs.Fields(BatchNo).Value objSheet.Cells(row,2).Value rs.Fields(ProductCode).Value objSheet.Cells(row,3).Value rs.Fields(OperatorName).Value objSheet.Cells(row,4).Value rs.Fields(TempSet).Value objSheet.Cells(row,5).Value rs.Fields(TempAct).Value objSheet.Cells(row,6).Value rs.Fields(JudgeResult).Value row row 1 rs.MoveNext Loop 保存文件 objWorkbook.SaveAs D:\Reports\ HMIRuntime.Tags(QueryBatchNo).Value .xlsx objWorkbook.Close objExcel.Quit Set objSheet Nothing Set objWorkbook Nothing Set objExcel Nothing写Excel之前确认运行WINCC的电脑上装了Office或者WPS并且Excel组件可用。我踩过一次很惨的教训项目快交付了客户工控机上没装Office脚本一执行到CreateObject(Excel.Application)直接崩溃。后来我就养成了习惯项目需求阶段就确认客户端办公环境或者干脆把报表逻辑改成直接生成CSV文件CSV用Excel也能打开兼容性最好。如果非要带格式的Excel又不想依赖Office环境可以考虑在服务器端装Office或者用其他报表组件但这些是后话了。3.3 触发方式让整个系统自动跑起来脚本写好了接下来要解决“什么时候执行”的问题。WINCC中脚本触发方式我用得最多的是这三种。第一种是事件触发最典型的场景按下画面按钮执行配方加载或者报表生成脚本。这种直接在画面的按钮控件上右键“属性→事件→鼠标按下”然后在VBS脚本里写逻辑即可。第二种是周期触发用于生产数据的自动采集。在WINCC全局脚本Global Script里创建VBS脚本设置周期触发器比如每分钟执行一次。这样PLC反馈的实际值就会按固定频率写入数据库。需要注意周期不能设太短否则数据量增长很快数据库压力大也不能太长否则实时追溯数据丢失。一般工艺参数记录1分钟到5分钟一次的频率就差不多。第三种是变量触发当某个WINCC变量值变化时触发脚本。比如PLC那边报“生产完成”信号信号一变WINCC变量跟着变VBS脚本就执行一次报表生成。这种触发方式很实用省掉了轮询效率也高。设置办法是在全局脚本的触发条件里选“变量”指定对应的WINCC变量名即可。变量触发虽然在WINCC里不是太难配但第一次用还是容易漏掉“初始触发”选项导致变量值已经变化但脚本不执行。设置变量触发时最好勾上“启动时触发一次”或者确认当前值已经满足条件免得丢了第一条记录。3.4 源码级别的功能模块清单为了让大家有个整体概念我把这套系统在WINCC里的脚本模块划分列出来方便对照自己项目去搭建模块类型触发方式核心作用DB_ConnectVBS公共模块脚本开头调用建立全局SQL连接统一管理连接串DB_WriteProcessVBS函数周期触发把当前变量写入生产记录表Recipe_LoadVBS函数画面按钮按产品编号读取配方并写入WINCC变量Recipe_SaveVBS函数画面按钮把画面上的配方参数保存到数据库Rpt_QueryVBS函数画面按钮按批号/时间查询数据库记录Rpt_ExportExcelVBS函数画面按钮查询结果写入Excel并保存WinCC_InitTagsVBS函数画面打开事件初始化WINCC内部变量公共连接模块我强烈建议单独放不要每个脚本都写一遍连接字符串。后期如果数据库服务器地址变了或者密码改了你只需要改一个地方否则几十个脚本翻到吐。这种细节就是项目上了以后维护省不省心的关键。4. 实操过程全记录我从建库到跑通的完整步骤4.1 数据库环境搭建和连接测试第一步编辑器问题。SQLSERVER建表我习惯用SSMS图形化操作但表结构这种脚本化的东西我会保存成.sql文件放到项目文档里。前面已经给了建表SQL直接在SSMS里执行就行。第二步确认账号权限。在SSMS里右键登录名新建登录名szguest勾选SQL Server身份验证默认数据库选RecipeDB。权限这里我给了db_datareader和db_datawriter两个角色足以支撑读写不需要更高权限。给一个只读报表账号也行但项目初期调试频繁给读写省事。第三步先写一个最小的VBS测试脚本验证ADODB连接能不能通。测试脚本可以直接用系统自带的cscript跑不用先拉进WINCCDim conn Set conn CreateObject(ADODB.Connection) conn.ConnectionString ProviderSQLOLEDB.1;User IDszguest;Password你的密码;Initial CatalogRecipeDB;Data Source127.0.0.1\MSSQLSERVER; conn.Open If conn.State 1 Then WScript.Echo 连接成功 Else WScript.Echo 连接失败 End If conn.Close Set conn Nothing保存成test_conn.vbs在命令提示符里执行cscript test_conn.vbs这一步能尽早暴露连接字符串、账号密码、实例名的问题。等这个通了再往WINCC里搬。我在很多项目里都是这样先做最小化验证的省掉一大堆联调时间。第四步把连接模块移植到WINCC。在WINCC工程里新建全局脚本VBS模块把连接代码结构化然后新建画面放一个测试按钮调一下测试函数运行时点击看弹窗或者返回值是否正常。4.2 写脚本配触发挂画面脚本开发顺序我建议按这个来先做配方保存再做配方加载再做生产记录写库最后做报表导出。每一步都单独测试通过再往下走。配方保存这块我在画面上放一排输入输出域分别绑定TempSet、PressSet等内部变量。操作员输入参数后点击“保存配方”按钮脚本把画面变量拼成INSERT语句。代码和前面写库逻辑类似只是数据来源从PLC变量换成了画面输入输出域。加载配方时画面上放一个组合框或输入域用来输入产品编号。按下加载按钮VBS从数据库查询该产品配方把结果写入内部变量。因为内部变量和输入输出域绑定画面会立刻显示新配方同时如果这些内部变量又关联了外部变量PLC那边也能同步收到数据。生产记录写库一般是周期脚本我在WINCC全局脚本里新建一个脚本命名为WriteProcessData触发类型选“周期”我用的是每分钟执行一次。脚本里读取当前批号、产品编号、各实际值写入T_Record。注意一点批号在WINCC内部变量里每次生产前由操作员输入如果生产中途没有切换产品批号不变那么每分钟都会插入一批数据。这个数据量你可以算一下一天24小时每分钟一条就是1440条一个月4万多条完全没问题。如果你不需要每分种都记录可以在PLC里加一个“采集使能”信号脚本里判断信号为True才写库更灵活。报表导出这块画面上放输入域“批号查询”和一个“生成报表”按钮。点击按钮后脚本把查询条件拼进SQL查出来的记录逐行写入Excel然后保存到D盘或者网络路径。这里有个体验细节Excel生成时间可能几秒到十几秒最好在画面上加一个文本显示“正在生成报表请稍候”等脚本跑完再改成“生成完成文件名.xlsx”。别让操作员以为界面卡死了。4.3 从头到尾跑一遍确认每个环节的数据流转整套脚本挂完之后我是按这个清单做的联调验证在画面上输入新产品配方点保存打开SSMS检查T_Recipe里有没有新记录。重新打开画面输入该产品编号点加载配方确认画面输入输出域的参数自动变化。启动生产过程等周期脚本跑几分钟检查T_Record里有没有按分钟写入数据。结束生产输入批号点生成报表确认Excel文件生成内容与数据库一致。把Excel的表头、列顺序和格式检查一遍确认符合报表格式要求。这几个步骤只要有一个不通就回到对应模块去查。联调阶段别急着把几十个功能一次性做完再测每做一个模块就验证一个最后集成时才不会手忙脚乱。5. 常见问题速查表与排查实战5.1 我遇到的高频问题汇总这里我把开发这套系统和运维阶段碰到的典型问题整理成一张表。多数问题不是代码逻辑复杂而是环境和细节列出来给大家一个快速索引。问题现象根本原因解决办法VBS连接报“未找到提供程序”机器缺少SQLOLEDB或连接串Provider写错用ProviderSQLOLEDB.1确认系统版本换用SQLNCLI11连接超时或拒绝访问TCP/IP未开启、端口没放行、服务器未启动SQLSERVER配置管理器启用TCP/IP固定端口1433防火墙放行登录失败提示用户sa登录失败SQLSERVER是Windows身份验证模式SSMS里把服务器身份验证改为SQL Server和Windows混合模式SQL语法错误提示“列名无效”字符串没加单引号被当成列名所有字符串值用单引号包起来数值入库变成0tag.Value不是数值IsNumeric判断失败先判断类型字符串转不了就给出报警中文乱码表和字段是VARCHAR没有用NVARCHAR关键文本字段改成NVARCHAR连接串加数据库编码设置WINCC运行时画面内MsgBox弹出但无响应WINCC脚本里弹窗阻塞了主线程尽量不用MsgBox优先级高的问题用日志文件记录Excel生成失败CreateObject出错没装Office或Excel组件异常改用CSV输出或安装Office后重新注册Excel.Application数据插入重复周期脚本重复执行触发器设了多份或全局脚本加载了多次检查WINCC全局脚本的触发器确认只有一条周期配置报表查询没有数据查询条件里的时间格式与数据库不一致统一用“YYYY-MM-DD HH:MM:SS”格式避免中文日期格式差异5.2 几个提高效率的开发技巧分享几个我实际用得比较多的技巧不一定写在文档里但对生效率提升很明显。技巧一日志机制。VBS脚本调试最痛苦的是出错不知道错在哪一步。我在最开始的连接模块里就加了个日志函数Sub WriteLog(msg) Dim fso, f Set fso CreateObject(Scripting.FileSystemObject) Dim logPath logPath D:\Logs\wincc_ Year(Now) Month(Now) Day(Now) .log Set f fso.OpenTextFile(logPath, 8, True) f.WriteLine Now - msg f.Close End Sub然后每执行完一个关键步骤就调用WriteLog写一行。线上出现问题直接翻日志能立刻定位脚本执行到了哪里数据库有没有写入是哪一行报错。技巧二把复杂的SQL先在SSMS里跑通再粘回VBS。我见过不少同事在VBS里调试SQL报错了也不清楚是SQL错了还是VBS语法错了。正确做法是先拿真实的表名和字段在SSMS里把SQL写对、把结果查出来再把SQL复制到VBS脚本里把变量拼接部分替换成实际变量。这样调试思路清晰能把SQL语法错误和VBS语法错误分开处理。技巧三变量命名和数据库字段名保持一致。WINCC变量名、数据库字段名、Excel表头尽量对应一致。我在项目里WINCC变量TempAct、数据库字段TempAct、Excel表头“实际温度”是一一对应的。虽然字段名是英文但代码写起来省心遇到问题也好排查不用来回翻译。技巧四脚本里的共享连接不要每次开关。全局脚本里用公共gConn第一次创建后复用而不是每个函数都新建连接、关闭连接。频繁开关SQL连接不仅慢而且在高并发时容易把数据库连接池打满。WINCC是单用户操作还好但为了稳妥脚本开头检测一下连接状态如果没打开就打开这样全局只要维护一条连接。5.3 关于学习VBS的零基础建议最后说点大实话。很多年轻工程师看到VBS就觉得是“老古董”不想学但我一直认为VBS在WINCC项目里依然是性价比非常高的脚本语言。不需要编译不需要额外运行库WINCC自带运行时就能执行入门门槛非常低。我当年就是靠着改别人写好的报表脚本一行一行查帮助文档慢慢摸熟VBS的。想上手这套方案的我的建议是从三个小练习开始第一个练习在WINCC画面放一个按钮点击后弹出一个框显示当前日期时间。这个练的是WINCC事件和基础语法。第二个练习写一个脚本读取三个WINCC变量值并求和显示在画面上。这个练的是HMIRuntime.Tags的读写。第三个练习把求和结果写入SQLSERVER一张表。这个练的是ADODB连接和INSERT语句。这三个练习做完你就已经把WINCC访问数据库的完整路径打通了。后面的配方管理、报表生成本质上都是在这个基础上做扩展而已。我在做这套项目的过程中对“自动化工程师到底要不要懂数据库”这个问题也有了更明确的答案懂点数据库绝对不吃亏尤其是SQL的基本语法和表设计思路至少在报表和追溯需求面前不会被厂商掣肘。WINCC SQL VBS这套组合看起来要学的东西不少但拆开看每一块都是成熟稳定的技术难点在于把它们串起来。只要愿意花一天时间把最小demo跑通后面就是填肉的事。最后再说一个小技巧做这套系统之前一定先想好报表的最终格式因为数据库表结构的设计是围绕报表展开的表建好了再返工代价比改脚本大得多。
RELATED

相关推荐

深入解析 oh-my-pi 会话标题生成协议:`<title>` 标记指令的设计与实现

深入解析 oh-my-pi 会话标题生成协议:`<title>` 标记指令的设计与实现

深入解析 oh-my-pi 会话标题生成协议&#xff1a;<title> 标记指令的设计与实现 【免费下载链接】oh-my-pi ⌥ Coding agent with the IDE wired in 项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi title-marker-instruction.md 是 oh-my-pi 编码代理…

📅 2026/9/11 5:47:48
巴西节点GPU集群上线:南美智算布局与Windows本地模拟部署实践

巴西节点GPU集群上线:南美智算布局与Windows本地模拟部署实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/9/11 5:47:48
子数组问题三连击:LeetCode 560、239、76 的前缀和、单调队列与双指针

子数组问题三连击:LeetCode 560、239、76 的前缀和、单调队列与双指针

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/9/11 5:47:48
MORE NEWS

更多资讯

📰

Polaris CTF Web题解:信息泄露、SQL注入、文件上传与命令执行实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

AI编程进阶:从写代码到重构工作流的实战路径

1. 这不是“学完30天就能写代码”的速成幻觉&#xff0c;而是真实踩出来的学习路径图谱“30天AI编程入门总结&#xff1a;接下来应该学什么”——这个标题乍看像一份打卡式学习报告&#xff0c;但如果你真把它当成“30天通关秘籍”&#xff0c;那从第一天起就走偏了。我带过62个…

📰

AI Agent全流程实战:LangGraph状态机与Function Calling工业级落地

1. 项目概述&#xff1a;这不是一个“调用API”的故事&#xff0c;而是一场精密的神经反射弧重建你有没有试过让AI帮你订一杯咖啡&#xff1f;不是简单问“附近哪家咖啡好”&#xff0c;而是说&#xff1a;“我刚开完会有点累&#xff0c;想喝点提神但不刺激的&#xff0c;最好…

📰

Process Hacker 资源监控完整指南:3分钟上手

Process Hacker 资源监控完整指南&#xff1a;3分钟上手 【免费下载链接】systeminformer A free, powerful, multi-purpose tool that helps you monitor system resources, debug software and detect malware. Brought to you by Winsider Seminars & Solutions, Inc. …

📰

从零跑通 Claudian 多人协作:实时评论与 AI 辅助编辑实操指南

从零跑通 Claudian 多人协作&#xff1a;实时评论与 AI 辅助编辑实操指南 【免费下载链接】claudian An Obsidian plugin that embeds Claude Code/Codex as an AI collaborator in your vault 项目地址: https://gitcode.com/GitHub_Trending/cl/claudian Claudian 是一…

📰

嵌入式Linux下手写Modbus RTU主站:串口配置、CRC16与传感器读取实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬