☰
WinCC用户归档实战:批次追溯与报表查询全流程
2026/10/28 13:51:42 网站建设 项目流程

简介:这是一份围绕西门子WinCC用户归档功能的实践案例包,面向工业自动化监控系统工程师、WinCC项目开发者以及希望系统掌握数据归档的学习者,重点解决生产实时数据存储、历史数据检索与归档策略设计等实际问题。压缩包共290个文件、约36.21MB,以rpl、mdf、ldf、dum、sav、ini、pdl、xml、cfg等类型为主,涵盖归档数据、数据库文件、项目配置、操作画面与脚本示例,便于还原案例环境并按模块查阅。目前已有1153人学习,说明其在用户归档主题下具有一定参考热度。案例围绕动作与标准模块的协同展开,涉及触发条件设置、数据过滤转换与压缩、归档间隔和保留期限设计等内容,并配有示例项目及脚本代码,可供读者对照理解完整归档系统的搭建思路、配置要点与排错方向。目录结构较完整,适合按归档配置、数据库文件与画面脚本分层学习,也可用于课堂演示或项目迁移时参考。

1. 从一张手写单据说起:WinCC 用户归档到底解决什么问题

车间主任拿着一沓手写单据来问:三个月前那批料的反应温度是多少、谁操作的、最后判定是合格还是返工?趋势控件翻不到那么早,变量记录一压缩,峰值早就被抹平了,报警记录里只有越限那几条。这类“按批次、按单据、按工单查一整条结构化记录”的需求,WinCC 用户归档就是为此准备的:一条业务记录就是一条数据行,能按任意字段过滤、能导出成表、能留几年不丢。做 SCADA 上位机、配方管理、批次追溯、质检记录的人可以直接参考;如果你只是想让曲线好看,变量记录就够了,不必加用户归档这一步。

2. 需求与结构设计:归档表、变量与画面三层怎么划分

动手建表之前,先把“谁在用、按什么查、查完干什么”这三件事问清楚,否则后面字段加一个改一个,归档表改结构是最麻烦的活。我一般会先跟使用方确认三个场景:班组长按时间段查当班所有批次、质检按批号查单条记录并打印签字、工艺按产品型号统计某参数的历史分布。三个场景对应三种查询方式,字段和索引基本就定下来了。

2.1 先定字段:一条批次记录到底要存什么

字段设计的原则是“存现场事实,不存事后算出来的东西”。温度、压力、开始时间、操作员这些是事实,要落库;平均值、合格率这类可以由查询时再算,存进去反而会因为统计口径变了而失真。下面这张表是一个典型的批次归档结构,字段名统一用英文,界面显示名在控件里配别名,避免中文域名在脚本里出问题。

域名类型长度示例说明
BatchNo文本标签32B20240612-001批号,业务主键,唯一
Product文本标签32P-A102产品型号
Temp浮点数—86.5反应温度,单位 ℃
Pressure浮点数—0.42压力,单位 MPa
Operator文本标签32op01操作员账号,取自登录用户
StartTime日期时间—2024-06-12 08:00:00批次开始时间
EndTime日期时间—2024-06-12 16:30:00批次结束时间
Result文本标签8OK判定结果

关于时间字段,通常的做法是直接用日期时间类型,这样在查询条件和排序上可以直接比较,不用做字符串转换;如果项目里已经有固定格式的文本时间戳(比如从 PLC 带上来的一串字符),存文本也能跑,但排序和范围筛选要多写一步转换,长期维护会难受。文本域的长度不要卡着实际长度给,批号定 32 位、型号定 32 位,留点余量,后面加个后缀不至于要改表。

业务主键和数据库主键要分开看:BatchNo 负责唯一性校验,是给人看的;归档表自己还会有一个自增的记录号,是给程序用的。这两个不要混,混了以后并发写入迟早出事。

2.2 三层分工:变量层、脚本层、画面层谁管什么

结构上建议切成三层,每层只干一件事,出了问题能快速定位是哪一层。

第一层是变量层,负责把现场的批次号、产品型号、当前登录用户、开始结束时间攒成一组内部变量,命名统一加前缀,比如 @BatchNo、@ProductCode、@BatchStartTime。变量层不写库,只做数据缓存。

第二层是脚本层,负责校验和写入。校验包括:批号不能为空、温度在合理区间、结束时间晚于开始时间。校验不通过直接返回并置错误位,不往库里塞脏数据。写入就是组装一条记录然后提交。

第三层是画面层,只做两件事:触发脚本、展示结果。查询画面、结果控件、导出按钮都归这一层。画面脚本里不要写业务逻辑,否则以后换界面就得重写一遍。

三层之间的调用关系可以用一张表说清楚,配置和排查时对着看:

层承载对象职责出错时的表现
变量层内部变量 / 外部变量缓存现场数据与登录信息记录里字段为空
脚本层全局脚本(C 或 VBS)校验、组装、写入、置错误位写入返回失败或数据异常
画面层查询画面、归档控件触发、过滤、展示、导出界面卡顿或查不到数据

这种拆法的好处是,同一个写入脚本可以被按钮调用,也可以被定时任务调用,画面怎么改都不影响落库逻辑。血泪经验是:把逻辑全塞在按钮的单击事件里,后来要在批次结束时自动写一条,只能复制一份代码出来,两份代码慢慢就跑偏了。

2.3 归档策略:循环覆盖、分段与保留期

用户归档在后台对应一张实际的数据表,数据量会一直涨。一个班 20 批、一天三班、一年 300 天,就是一万八千条,几年下来十几万条不算多,但如果每条还带十几个浮点域,查询不加过滤就会明显变慢。上线前就要把保留策略定下来,通常有三种做法:按条数限制、按时间分段、定期导出后清理。

按条数限制最简单,归档属性里设一个上限,超了覆盖最旧的,适合只关心近几个月的场景。按时间分段更规范,一年一个归档或者一月一个归档,查询时按时间段选对应归档,单表体积可控,缺点是查询跨年要写切换逻辑。定期导出后清理适合有审计要求的场景,每月把数据导成表格归档到文件服务器,再从用户归档里删掉。

主键这块要专门提一句:不要自己在脚本里维护流水号。计数器变量在重启、多客户端并发、项目复制这几种情况下都会翻车,撞号之后写入直接失败,而且失败得很安静,现场看着按钮点了没反应。用归档自带的自增记录号,业务唯一性靠批号加时间组合来保证,省心得多。

3. 归档表建立与读写实现:从向导配置到脚本落库

结构定完就进入实现。用户归档的落地路径其实有四条:控件直接绑定、C 脚本写入、VBS 写入、作业定时处理。四条路不是互斥的,常见的组合是用脚本写、用控件查、用作业做定期导出。

3.1 建表:用户归档编辑器的操作顺序

打开项目管理器里的用户归档编辑器,先建归档,再建域。归档名建议加统一前缀,比如 UA_Batch,一眼能看出这是用户归档而不是变量记录。建域的时候按顺序填:域名、数据类型、长度、显示名。浮点域要留意小数位,显示位数在控件里配,存储精度按实际需要给,不要一股脑全给最高精度,导出的时候表格会很难看。

建完之后有两件事必须做:一是给归档配一个唯一的索引字段,批号和时间各建一个,查询条件基本都落在两个字段上;二是在归档属性里确认记录数上限和覆盖策略,默认值往往和实际需要差很远。做完这些,先别急着写脚本,在编辑器里手动插几条测试数据,用控件读一下,确认整条链路通了再往下走。

3.2 控件读写:用户归档控件的绑定与列配置

在画面里插入用户归档控件,配置归档名、要显示的列、列宽和表头文字。控件本身就有读写能力,选中一行可以直接编辑并提交,适合做小规模的数据维护界面,比如配方参数调整。但批次记录这种由流程自动产生的数据,一般把控件设成只读,只用来查询展示。

控件配置里有一个容易忽略的点:过滤条件。默认是装载整张表,数据量小的时候看不出来,几万条之后画面打开要等十几秒,用户会以为死机了。通常的做法是画面打开时先给一个默认过滤,比如只查当天,再让用户改条件重新查。过滤属性在属性面板里的名称各版本略有差异,按实际显示填,写完先拿一条已知数据验证过滤是否生效。

3.3 C 脚本写入:一次完整落库的代码与参数说明

写入用全局脚本里的 C 脚本,触发点可以是批次结束按钮,也可以是某个状态变量的上升沿。下面这段是完整的一次落库过程,重点看三处:取数前的校验、逐域赋值、返回值判断。

// 批次结束时调用:校验 -> 组装 -> 提交 -> 留痕 // 归档名 UA_Batch 和域名必须与用户归档编辑器中定义的一致 #include "apdefap.h" void WriteBatchRecord(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName) { char szBatchNo[32]; double dTemp, dPressure; BOOL bOk = FALSE; /* 1. 取数并校验,脏数据不落库 */ strcpy(szBatchNo, GetTagChar("@BatchNo")); /* 批号来自内部变量 */ dTemp = GetTagFloat("BatchTemp"); /* 反应温度 */ dPressure = GetTagFloat("BatchPressure"); /* 压力 */ if (strlen(szBatchNo) == 0 || dTemp < -50 || dTemp > 500) { SetTagBit("BatchWriteErr", 1); /* 置错误位,画面提示 */ return; } /* 2. 组装一条记录,逐域赋值 */ if (!uaArchiveCreateTag("UA_Batch")) return; uaArchiveSetFieldValue("UA_Batch", "BatchNo", szBatchNo); uaArchiveSetFieldValue("UA_Batch", "Product", GetTagChar("@ProductCode")); uaArchiveSetFieldValue("UA_Batch", "Temp", dTemp); uaArchiveSetFieldValue("UA_Batch", "Pressure", dPressure); uaArchiveSetFieldValue("UA_Batch", "Operator", GetTagChar("@CurrentUser")); /* 按项目实际变量名替换 */ uaArchiveSetFieldValue("UA_Batch", "StartTime", GetTagChar("@BatchStartTime")); uaArchiveSetFieldValue("UA_Batch", "EndTime", GetTagChar("@BatchEndTime")); uaArchiveSetFieldValue("UA_Batch", "Result", GetTagChar("@BatchResult")); /* 3. 提交,返回值必须判 */ bOk = uaArchiveWriteTag("UA_Batch"); if (!bOk) { SetTagBit("BatchWriteErr", 1); /* 写失败留痕,便于事后追查 */ } else { SetTagBit("BatchWriteErr", 0); SetTagBit("BatchSaved", 1); /* 通知画面刷新列表 */ } }

参数和行为说明:uaArchiveCreateTag的作用是创建一条待写记录,它的参数是归档名,返回失败通常意味着归档名写错或者归档不存在。uaArchiveSetFieldValue三个参数分别是归档名、域名、值,赋值顺序无所谓,但域名必须和编辑器里完全一致,大小写敏感这一点踩过坑。uaArchiveWriteTag才是真正落库的动作,前面只赋值不提交,数据是不会进表的——这是新手最常犯的错误,代码看着跑完了,库里一条没有。

取当前登录用户那段,不同项目里内部变量名不一样,有的叫 @CurrentUser,有的是自定义的用户名变量,按现场实际替换,不要照抄。另外这段脚本里所有字符串域都要注意长度,批号超了 32 位会被截断,截断后查询就对不上了。

3.4 定时作业与备份导出

作业(Job)在用户归档编辑器里配置,可以设成定时触发,也可以设成事件触发。典型用法是每天凌晨把前一天的数据导出一份到指定目录,导完再按保留策略清理。配置作业的时候要确认三件事:导出路径对运行账户有写权限、文件名里带日期避免覆盖、导出失败要有日志。

备份这块很多人交给数据库管理员去做,但项目交付时对方往往不知道这张表有多重要。我的做法是在归档属性里把表名记到交付文档里,注明这是业务数据表,备份策略要覆盖它;同时配一个导出作业,双保险。导出格式选表格文件就行,方便业务方直接打开看,比让他们去连数据库现实得多。

4. 查询与报表落地:筛选条件、视图与打印的完整链路

写入通了只是完成一半,用户真正每天面对的是查询界面。查询做不好,前面存得再规范也没人用。

4.1 查询画面的交互:时间段加批号的三段式筛选

查询画面不要做成一个大表单堆十几个输入框,按使用频率分三段:第一段是时间段,默认当天,带快捷按钮(今天、昨天、本周);第二段是精确条件,批号、产品型号,支持模糊匹配;第三段是结果区,带总条数和导出按钮。

时间段是必须给的,不能让用户不填就直接查全表。批号输入框做模糊匹配,用户往往只记得后几位。产品型号用下拉框,数据源从归档里取一次去重值缓存起来,不要每次打开画面都查一遍。结果区显示的列不要太多,八到十列刚好,其余字段放到详情弹窗里看。

4.2 过滤与分页:别让控件一次吃十万行

归档控件一次性装载整张表是性能翻车的主要原因。正确的做法是把筛选条件下推到查询里,只把命中的记录交给控件。下面这段是查询按钮的逻辑,用过滤条件重新装载数据。

' 查询按钮:按时间段与批号重新装载归档控件 Dim ctrl, szFrom, szTo, szBatch, szFilter Set ctrl = ScreenItems("uarBatch") ' 画面上的用户归档控件 szFrom = FormatDateTime(ScreenItems("dtpFrom").Value, vbShortDate) szTo = FormatDateTime(ScreenItems("dtpTo").Value, vbShortDate) szBatch = Trim(ScreenItems("txtBatch").Value) ' 时间段必填,批号为空则不参与过滤 szFilter = "StartTime >= '" & szFrom & " 00:00:00' AND StartTime <= '" & szTo & " 23:59:59'" If Len(szBatch) > 0 Then szFilter = szFilter & " AND BatchNo LIKE '%" & szBatch & "%'" End If ctrl.Filter = szFilter ctrl.Requery ' 触发重新查询

说明几点:过滤字符串里的时间要和字段类型对上,日期时间域用带时分秒的完整格式,纯日期比较容易漏掉当天最后几条。批号用 LIKE 做模糊匹配,代价是用不上索引,所以时间段这个前置条件一定要有,靠它先把数据量压下来。控件的过滤属性名和 Requery 方法在不同版本里可能有差异,配置时以属性面板和帮助文档为准,逻辑是不变的:先设条件,再触发重查。

数据量确实大(十万条以上)的时候,控件这条路会吃力,这时候改用脚本按页读:设好过滤和排序,用归档读取函数从头开始定位,跳着读若干条,只把当前页塞进表格控件。分页做起来麻烦,但用户感知差别很大。

4.3 报表输出:打印与导出两条路

报表有两条路可选,取决于业务方要不要签字。要签字的走打印,用报表编辑器做模板,把查询条件作为参数传进去,生成固定格式的记录单,带表头、带页码、带签字栏。不要签字的走导出,直接导成表格文件,让业务方自己再加工。

打印这条路要多花时间调格式,行高、列宽、分页位置都得试,尤其是记录条数不固定的时候,容易出现一条记录被切到两页。我的习惯是先拿十条、一百条、一千条三种数据量各打一遍,确认分页没问题再交付。导出这条路的坑少一些,但要注意文件名和编码,文件名带时间和条件摘要,避免业务方下载一堆同名文件分不清。

5. 避坑与排查:用户归档最容易翻车的五个点

这套东西跑通不难,稳定运行难。下面五条是按出现频率排的,每条按现象、原因、解决写。

5.1 写入侧:写不进、写重、写空

现象一:脚本执行完没报错,库里查不到记录。原因基本是两个,一是只调用了赋值函数没调用提交函数,数据还在缓存里;二是归档名或域名拼错,赋值悄悄失败但没检查返回值。解决:在提交后立刻判返回值,失败置错误位并在画面提示;另外在开发阶段每写完一条就去编辑器里手动查一下,别等交付时才发现。

现象二:同一条记录库里出现两条甚至多条。原因是触发点重复。按钮被连点、状态变量的上升沿抖动、批次结束信号持续为真,都会导致脚本被执行多次。解决:写入前先用批号查一次是否已存在,存在就跳过;或者在脚本入口加一个写入中标志位,写完再复位。仅仅靠按钮防抖不够,自动触发那条路径才是重灾区。

现象三:记录写进去了,但有几个字段是空的。原因是赋值时取数的变量还没准备好,比如批次结束瞬间先写归档、后写结束时间,取到的就是空值。解决:在赋值前统一检查关键变量是否有效,无效就延时重试一次;或者把写入触发点挂到“所有数据都就绪”的那个信号上,而不是流程结束信号本身。

5.2 运行侧:查不出、越查越慢、换机就废

现象四:查询画面打开要等十几秒,条件改了也不见快。原因是控件首次装载没加过滤,直接拉了全表;或者过滤条件里的字段没有索引,每次都在做全表扫描。解决:画面打开时给默认时间过滤,索引字段优先覆盖批号和时间;记录数超过一个量级就上分页。

现象五:项目从这台机器复制到另一台,归档功能整体失效。原因是归档依赖后台数据库实例和运行账户配置,直接拷贝项目文件夹带不过去。解决:用项目复制器做迁移,复制完在新机器上重新确认归档连接和作业路径;运行账户权限也要一并检查,权限不足时表现是能查不能写,或者反过来,很容易误判成脚本问题。

提示:交付前把“归档表名、作业名、导出路径、运行账户”这四项写进交付文档,后面接手的人能少走很多弯路。

6. 验收与答辩:一份能自证的归档功能检查清单

功能做完不等于能交付,验收这一步要能拿出证据。我一般按下面这张清单逐项过,每项都要有可复现的操作和明确的通过标准,答辩时被问到“你怎么证明它可靠”,直接把清单和测试记录拿出来就行。

验收项操作方法通过标准
单条写入手动触发一次批次结束库中新增一条,八个字段全部有值
重复触发连续点击写入按钮三次只产生一条记录,界面有防重提示
异常数据批号置空后触发写入不落库,错误位为 1,画面提示明确
时间查询按当天、本周、跨月各查一次结果条数与手工统计一致
大数据量造十万条记录后打开查询画面默认过滤下加载时间可接受
打印输出选十条记录打印分页正确,表头签字栏完整
断电恢复运行中断电重启已写入数据不丢,可继续写入
项目迁移复制到另一台机器运行查询、写入、导出三项均正常

验收时有两个技巧值得说。一是造数据要提前做,十万条测试数据不是临时能点出来的,写个循环脚本批量插,插完再测查询,这样测出来的性能才是真实的。二是留一份“失败案例”的记录,比如故意把归档名写错一次、故意断电一次,把报错信息和恢复过程记下来,答辩时讲这些比讲功能列表有说服力得多,因为提问的人最想知道的正是“出问题你怎么办”。

还有一个细节容易被忽略:验收当天要现场演示,不要放录屏。现场演示最能暴露问题,比如授权状态、运行账户、网络连接这些环境因素,演示时出一次小问题并当场排查掉,反而比一路顺利更让人信服。我通常会准备一台备用机,环境配好但不启动,主用机出状况时能马上切过去。

从那以后我每次交付带归档的项目,不管工期剩多少,都强制走一遍这份清单,尤其是断电恢复和项目迁移这两项——它们平时看不出来,一出事就是大事。希望帮到你。

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

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

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

立即咨询