做上位机项目这么多年,配方管理一直是个绕不开的活儿。尤其这两年食品、医药、汽车零部件这类多品种小批量的产线越来越多,操作工换型时要调一堆参数,品控那边又要追溯每一批产品到底用的什么配方、参数值是多少。我最初接这类需求的时候,也是老老实实在WINCC里写C脚本、VBS脚本,用ADO连数据库做增删改查。说实话,那套做法能用,但真的磨人:变量名一改,脚本里的SQL就得跟着改;项目版本一升级,脚本可能全线崩掉;最难受的是换人维护,新来的同事看着几百行脚本一脸懵。
后来在一个项目的收尾阶段,我试着换了一条路子:全程不碰脚本源码,利用WINCC自带的变量导入导出功能批量建好配方变量,再通过SQL查询直接读取WINCC后台数据库里的配方数据,自动生成配方报表。这一套跑下来,项目交付时间提前了将近一周,客户自己也能维护。这篇文章我就把完整的思路、实操步骤和踩过的坑都整理出来,希望对正在跟配方报表死磕的兄弟们有点帮助。
1. 先厘清需求:配方报表到底要解决什么问题
1.1 配方和报表在产线里的真实角色
先说配方。在工业现场,配方就是一组工艺参数的集合,比如杀菌段的温度、压力、时间,注塑机的料筒温度、注射速度、保压压力,或者化工投料的比例系数。一套产品对应一套参数,换产品就换配方,这就是配方的核心价值。WINCC里的配方组件,就是把散落在各个变量里的参数打包管理起来,操作工在画面上选中某个配方,一键下载,PLC里的参数就全部更新到位。
报表则是把配方使用情况记录下来形成可查的证据链。哪个班次、哪个操作工、在什么时间、下载了哪套配方、各参数最终值是多少,这些数据要能回溯。客户体量小一点的,要求Excel表就行;体量大、有审计要求的,可能要PDF归档、要签字确认。但不管形式怎么变,核心需求就两句话:配方参数要能批量维护,配方使用记录要能自动出报。
1.2 传统做法为什么让人头大
我最早做配方报表,走的都是老路子:在按钮的VBS脚本里写ADO连接,用SQL语句往数据库插入配方记录,或者从配方表里SELECT出来填到报表控件里。这套方案有几个特别现实的问题:
- 变量多的时候,配方定义本身就繁琐,脚本里还要逐变量处理,工作量翻倍。
- 每次需求微调,比如多加一个参数、改一个报表字段,都要进脚本编辑器改代码、编译、重新激活,调试一轮下来大半天就没了。
- WINCC版本升级或者SQL Server版本变化时,脚本引用的组件版本对不上,经常出现莫名其妙的数据库连接失败。
- 维护交接困难。脚本是"源码",写的人当时记得,半年后再看连自己都费劲。
所以我在想,能不能反过来:配方参数的录入交给WINCC原生的导入导出功能,报表生成交给SQL查询和外部报表工具,中间尽量少写甚至不写代码。沿着这个思路,我把整个流程重新梳理了一遍,发现其实WINCC从底层架构上就支持这种"低代码"玩法,只是很多人没往这个方向用。
2. 底层原理:WINCC的数据与“自动生成”凭什么成立
2.1 WINCC和SQL Server的天然绑定
很多不熟悉WINCC底层的人会忽略一个关键事实:WINCC安装的时候,会强制装一个配套版本的SQL Server。也就是说,你的WINCC项目从建立开始,就运行在一个关系型数据库之上。WINCC的项目数据、变量归档、报警记录、配方数据,全部存放在SQL Server的数据库实例里。
这一点是整个"不写源码"方案的地基。因为数据都在SQL Server里,那你完全可以绕开WINCC的界面,直接用SQL工具去查、去取、去定时导出。WINCC在这里的角色变成了"数据产生器"和"数据展示器",而报表这种分析工作,完全可以交给数据库和报表工具来做。
WINCC的数据库实例命名一般遵循"计算机名\WINCC"或者"计算机名\WINCC@"的格式,具体取决于版本。项目相关的数据库名称是创建项目时自动生成的,通常类似"CC_项目名_创建时间戳"。一个项目里往往有好几个库,分别存放组态数据、归档数据、报警数据和配方数据。
2.2 配方数据在数据库里长什么样
配方数据在WINCC数据库里的存放方式,很多人没认真研究过。简单来说,配方组、配方、配方项这些对象,在数据库中有对应的系统表来存储。不同版本的WINCC表名会有差异,比如有的版本配方表名以"PDSRC_"开头,有的则存在"RCIPE"相关的表里。表结构大致包含:配方组ID、配方ID、配方名称、变量名称、变量值、版本号等字段。
这给我们提供了一个思路:要让配方数据变成报表,不用非要从WINCC界面里"导出来",直接查数据库表就能拿到结构化数据。不过我也要说实话,直接查WINCC的系统表有几个不便:一是表名和字段名在不同版本里不完全一致,二是系统表里还混着很多内部关联字段,查询需要做一些过滤。所以我在实际项目中更喜欢用WINCC的"用户归档"功能来处理报表数据,用户归档可以自定义表结构,字段完全可控,而且运行时可以配合控件做数据录入。
| 数据存放方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| WINCC系统配方表 | 原生存储,无需额外配置 | 表名随版本变化,字段含内部信息 | 直接查配方定义数据 |
| 用户归档自定义表 | 表结构自定,查询简单 | 需要组态用户归档并配置动作 | 做正式的报表数据源 |
| 归档变量历史表 | 记录所有历史变化 | 同变量反复归档,数据量大 | 追溯参数变化趋势 |
2.3 为什么能做到“不改源码”
这里说的"源码",主要指WINCC里的C脚本和VBS脚本。传统的做法要在脚本里写数据库连接字符串、SQL语句、报表导出逻辑,改一处就可能动全身。而我这套方案把各个环节替换成了WINCC原生功能加SQL工具:
- 变量录入环节:用WINCC的"导入/导出"功能,在Excel里维护变量清单,一次性导入。
- 配方管理环节:用WINCC配方组件自带的编辑器完成配方创建和下载,不写一行脚本。
- 报表数据生成环节:数据已经在SQL Server里,用ODBC连接、SQL查询、SQL Agent定时任务或者Excel Power Query去拉取,全部是配置和查询操作。
整个链路中,唯一的"代码"可能就是一条SQL查询语句,而SQL语句不算程序源码,它只是数据查询的配置条件。你改SQL里一个变量名,比改脚本里的字符串拼接要直观太多。
3. 实操第一步:变量批量导入,把配方变量一次性建好
3.1 先做一份规范的变量清单
做变量导入之前,第一步必须是整理变量清单。我的做法是先在Excel里建一个表格,把配方涉及的参数变量全部列出来。清单至少包含四列:变量名称、数据类型、初始值、注释。如果变量是外部变量,还要加一列地址,比如DB块路径、偏移量。
比如一个杀菌釜项目,配方变量清单可以长这样:
| 变量名称 | 数据类型 | 初始值 | 注释 |
|---|---|---|---|
| Recipe_Temp_Sterilize | 浮点数32位IEEE754 | 0.0 | 杀菌温度 |
| Recipe_Press_Hold | 浮点数32位IEEE754 | 0.0 | 保压压力 |
| Recipe_Time_Sterilize | 无符号32位数 | 0 | 杀菌时间 |
| Recipe_Time_Exhaust | 无符号32位数 | 0 | 排气时间 |
| Recipe_Cycle_Count | 有符号32位数 | 0 | 循环批次 |
命名规范这一块务必重视。车间里的变量命名一开始不统一,后面做报表的时候取名乱七八糟,映射关系能把你逼疯。我通常建议用"Recipe_前缀+参数名"这种命名法,一眼就能看出这是配方相关变量,后续SQL查询也方便按前缀过滤。
3.2 用CSV/Excel完成批量导入
变量批量导入说起来简单,实际操作有个关键技巧:不要直接拿自己编的Excel去导入,而是先让WINCC导出一个标准模板,再在模板基础上来填。原因很简单,WINCC的导入文件格式比较固定,自己瞎编的列名和列顺序很容易导致导入报错。
具体操作流程如下:
- 在WinCC Explorer里新建一个连接,比如"Recipe_Station",然后在连接下手动创建两三个示例变量,变量类型要与清单中的类型一致。
- 右键点击变量管理,选择"导出",将当前变量表导出为CSV或者Excel文件。这一步是为了拿到标准模板。
- 用Excel打开导出的文件,仔细观察它的列结构,包括变量名称、数据类型、地址、初始值、上下限、注释等。
- 把你整理的变量清单按模板格式填入,注意数据类型字段必须用WINCC能识别的写法,比如"浮点数32位IEEE754"直接下拉选择模板中已有的值,千万别手打。
- 保存文件,回到WinCC Explorer,右键点击变量管理下的目标连接,选择"导入",选中刚才编辑好的文件。
- 导入完成后,逐个检查导入结果。重点看数据类型有没有变、地址是否匹配、有没有导入失败的变量。
这里有个细节:导入时如果提示"变量已存在",说明你模板里的变量名与项目中已有变量重名。没关系,导入选项里通常可以选择合并或者覆盖,根据实际情况处理就行。
3.3 把变量关联到配方组
变量建好之后,接下来就是在WINCC里配方组件中把这些变量组织起来。在WinCC Explorer的变量管理区域,找到"配方"标签页,右键新建配方组,比如"杀菌工艺参数组",然后在配方组里创建具体的配方,比如"产品A杀菌参数"、"产品B杀菌参数"。
每个配方都要添加变量项。添加的时候可以直接从变量列表里把刚刚导入的Recipe_前缀变量选进来。这一步不需要写脚本,界面点点选选就完成了。每个配方可以设置一组默认值,运行的时候操作工在配方视图控件里选中配方,点击"下载",这些默认值就会写入PLC对应地址。
配方组件还有一个容易被忽视的好处:配方数据支持"上传",也就是从PLC当前值反向更新到配方。这个功能在做参数反写、设备调试的时候特别方便。报表的场景里,配方下载后记录的数据,实际就是配方表中的值。
4. 实操第二步:SQL查询自动生成配方报表
4.1 选好报表生成通道
配方报表的生成通道,我实测下来有四种可行方案,适用场景各不同:
| 方案 | 实现方式 | 自动化程度 | 适用人群 |
|---|---|---|---|
| 直接用SSMS管理工具查询 | 打开SQL Server Management Studio,连接WINCC库,手动执行SQL | 手动 | 临时查一次两次 |
| Excel通过ODBC连接查询 | Excel数据选项卡里用ODBC连接WINCC数据库,查询配方表,再做透视表 | 半自动,刷新即可 | 需要经常出Excel报表 |
| SQL Agent定时任务 | 在SQL Server Agent里建作业,定时执行查询,导出CSV或写入报表库 | 全自动 | 每天/每班自动出报告 |
| Power BI / 水晶报表 | 连接数据库做可视化报表 | 半自动 | 管理看板、数据分析 |
我在实际项目中首选的组合是"SQL Agent定时任务 + Excel模板联动":SQL Agent负责每天定时把配方记录查询出来,导出成CSV或者写入一张报表数据表;Excel通过ODBC读取这张表,做美化、加公司抬头、设置打印格式。这样既保证了自动化,又兼顾了报表的美观和灵活性。
4.2 连接WINCC数据库
不管选哪种方案,第一步都是能连上WINCC背后的SQL Server。这里有几个关键信息必须先搞清楚:
- 实例名:通常是"计算机名\WINCC",如果本机装了多个实例,要看WINCC实际使用的实例。
- 数据库名:打开WinCC Explorer的项目属性,或者在SQL Server Management Studio里连上实例后,数据库列表里找"CC_"开头的库。
- 认证方式:WINCC项目数据库默认用Windows身份认证,也可以启用SQL Server混合认证,用sa账户登录。
配置ODBC连接的时候,驱动选择SQL Server Native Client或ODBC Driver 17 for SQL Server,服务器填实例名,数据库选具体库。配置完可以点"测试连接",能通就说明链路OK。
如果连接失败,大概率是这三类原因:SQL Server服务没启动、实例名写错、认证方式不对。排查的时候先用SSMS本地连一把,SSMS能连上,ODBC就放心去配。
4.3 写一条通用查询语句
配方数据报表的核心SQL语句,我给大家一个通用的模板思路。假设配方组件创建的配方数据存储在系统的配方表里,或者你把配方记录写入了用户归档表,查询逻辑大同小异:
SELECT t1.RecipeName AS 配方名称, t1.VariableName AS 参数名称, t1.VariableValue AS 参数值, t1.DownloadTime AS 下载时间, t1.Operator AS 操作人员 FROM RecipeRecordDB.dbo.TBL_RecipeLog AS t1 WHERE t1.DownloadTime >= CONVERT(datetime, '2025-01-01', 120) ORDER BY t1.DownloadTime DESC;在实际项目里,我一般会把这类SQL语句写在一个"查询模板"里,存成.sql文件或者放在报表配置表中。以后客户要求调整报表条件,比如只看某班次的数据、只看某个产品配方,只要在Excel参数表里改一下日期、品名,SQL模板通过这些参数动态拼一下就行。全程不用碰WINCC画面脚本,也不用重新激活项目。
4.4 定时自动生成
定时生成报表这一步,SQL Agent是最稳的。操作逻辑不复杂:在SQL Server Agent里新建一个作业,作业步骤里写我们的查询SQL,输出方式选"输出到文件",指定CSV文件的路径和文件名;再配一个计划,比如每个班次结束后跑一次,或者每天早上六点自动生成前一天的报表。
SQL Agent作业的注意事项主要有几个:第一,代理账户必须有权限访问WINCC数据库和输出文件目录;第二,输出的CSV文件命名建议带日期,比如"RecipeReport_20250115.csv",不然每天覆盖同一个文件,历史数据就丢了;第三,SQL Agent服务要设置成自动启动,不然机器重启后任务就断了。
如果不想碰SQL Agent,用Excel Power Query也能做半自动方案。Excel里创建查询,连接WINCC数据库,写好SQL,保存后每次打开Excel点一下"刷新",数据就自动更新。这个小方案特别适合那些只需要"偶尔看一下"的管理人员,无需任何额外部署。
5. 常见问题与排查实录
这套方案虽然避开了脚本,但实际跑起来还是会遇到一些幺蛾子。我把几个高频问题整理一下,按我踩坑的频率排序。
| 问题现象 | 根本原因 | 解决办法 |
|---|---|---|
| 变量导入时报"变量已存在"或格式错误 | Excel模板列顺序/数据类型填写不规范 | 始终从WINCC导出的模板改数据,不要自己造文件 |
| 连接WINCC数据库失败 | SQL Server服务未启动,或实例名写错 | 先用SSMS本地连,确认实例和库名再配置ODBC |
| SQL查询提示"找不到对象" | 配方表名随版本变化,或者库选错了 | 在SSMS里边刷新边查,先看库表清单,确认是"CC_"开头的项目库 |
| 中文乱码 | ODBC连接字符集设置不对 | ODBC连接串里加Character Set=utf8,或者统一用NVARCHAR字段 |
| 报表里数值保留多位小数 | 浮点显示格式问题 | 查询时用CONVERT或ROUND控制小数位数,或Excel里设置格式 |
| SQL Agent作业跑完没生成文件 | 输出文件路径权限不足 | 给SQL代理账户NTFS写权限,并且确认输出目录存在 |
| sa密码过期导致连接失败 | SQL Server配置了密码过期策略 | 修改SQL Server登录策略,或改用Windows认证方式 |
5.1 变量导入最常见的坑
变量导入这块,新手最容易犯的错误就是图省事,直接从Excel复制粘贴到WINCC导入文件里,结果类型字段内容和WINCC模板不一致,导入直接报错。我的经验是:模板文件里有一个"类型"列,必须用WINCC能识别的类型缩写,比如浮点数是"FLOATING_POINT_32"或者对应的显示字串。最好的办法是先用鼠标在WINCC里新建一个变量,把类型选好,然后导出模板,再看模板里这个类型是怎么表示的,照抄即可。
另外就是外部变量的地址问题。地址格式必须与通讯驱动匹配。比如通过SIMATIC S7协议连接,地址要写成"DB1.DBD4"这种形式;如果用的是KepServerEx这类OPC网关发布的变量,地址可能又是另一种格式。导入前最好先手动创建一个外部变量测试通讯是否正常,再接批量导入。
5.2 数据库连接和权限问题
很多项目现场是不允许随便开SQL Server外部连接的,尤其是甲方有信息安全要求的时候。我的建议是:优先用Windows身份验证连本机库,在报表服务器上设置固定账户访问,不要到处用sa密码。另外,如果是SQL Server 2012以上版本,密码过期策略是默认开启的,如果建了SQL账户做定时报表,密码到期那天任务就会挂掉。排查这类问题,看SQL Agent作业历史里的报错信息是"Login failed for user"还是"password expired",基本一目了然。
5.3 配方表版本差异
前面提过,WINCC不同版本的配方表名可能不一样。我自己就遇到过V7.0和V7.5项目库里的配方表结构有明显差异。如果你在SSMS里找表找得眼花,教你一个笨但有效的办法:在SSMS里按配方名称关键词搜索,比如查一个已知配方的名称字符串,顺着结果就能锁定配方相关表。或者干脆用用户归档自定义表,自己建表结构,不受系统表版本变化影响,这是最稳的方案。
6. 我的一些经验总结
这套"变量导入 + SQL查询自动出配方报表"的方案,我后来在几个项目里都复用过,总体感觉是:非常适合多品种、多配方、参数数量大、报表格式经常调整的场景。它的核心优势不是做了什么高深的技术,而是把频繁变动的需求从程序开发领域转移到了配置和查询领域——改动成本从"改脚本重新编译"降到了"改Excel和SQL"。
一个项目能不能用这套方法,有时候不是技术问题,而是思路问题。每次遇到配方报表的活,我会先问自己一句:数据是不是已经在数据库里了?如果已经在,那我为什么要写一大堆脚本来搬运一份本来就存在的数据?搞明白这一点,很多看似复杂的报表需求都会变得简单。
最后分享一个小习惯:我会把整套方案的操作步骤写成一页纸,放在项目交付文档里。内容包括如何改变量清单、如何刷新报表、如何排查连接故障。客户接手以后,普通电工按文档就能完成日常维护,这比留一堆源代码给人家翻要有用得多。如果你还没试过这条路子,下次遇到配方报表的需求,不妨先从导入配方变量开始,你会回来感谢我的。