☰
WinCC用户归档实战:从建表到SQL查询的完整指南
2026/10/10 15:22:57 网站建设 项目流程

简介:WinCC用户归档案例是一份面向工业自动化工程师的SCADA数据管理实践资源,聚焦西门子WinCC中用户归档功能与动作、标准模块的协同应用。资源通过具体项目演示如何配置归档触发条件,利用动作响应变量变化或按钮事件来启动归档,同时调用标准模块完成数据过滤、格式转换与压缩存储,并讲解归档间隔、保留期限、存储介质等策略设计,帮助读者从配置到调试完整掌握用户归档系统。包内共290个文件,以rpl脚本为主,辅以mdf/ldf数据库、pdl画面、cfg配置及备份文件,整体36.21MB,工程结构清晰便于按模块检索学习。目前已有1150人学习浏览,内容覆盖工程文件、脚本代码与配置说明,适合具备一定WinCC基础、希望提升数据管理与归档能力,应用于生产追溯、报表分析和故障排查的组态工程师参考。

1. WinCC 用户归档:一张被历史追溯逼出来的数据库表

项目上线还没满三个月,业主就打电话要调数据:上个月 12 号夜班,2 号罐液位在 23:40 前后波动了 0.5 米,当时有没有人操作过?WinCC 变量记录能画趋势,但变量记录只存过程值——谁在什么时候改了哪个参数、批号多少、操作员是谁,它一概不管。这种问题只能靠用户归档解决。用户归档说白了就是 WinCC 内置 SQL Server 里的一张业务表:字段自己定,脚本往里面 INSERT,再按条件 SELECT 出来做追溯、报表和审计。这篇案例把用户归档从组态建表、C 脚本写入、表格查看、SQL 直查到现场排错完整走一遍,适合做批次追溯、操作审计、产线报表的工程师照着重现。

2. 用户归档是什么:一张藏在 WinCC 里的 SQL Server 用户表

动手设计上位机数据方案之前,先得把 WinCC 里几个「归档」的关系弄清楚,否则需求写到一半就会发现选错了对象。

2.1 三种归档的分工:变量记录存过程值,用户归档存业务数据

经典 WinCC 里容易混淆的是三样东西:变量记录、报警记录和用户归档(User Archive)。变量记录管过程值,按周期或变化把变量值存进归档数据库,趋势控件画曲线用的就是它。报警记录管报警事件,报警控件显示的就是它。用户归档是第三个,它跟过程值没有直接关系,管的是「业务数据」:批次号、操作员、配方名称、备注、设备状态切换记录这些。

这三个东西的界限,用一个场景就能说清楚。现场要追溯「这批料生产时 2 号罐温度波动是谁造成的」:温度曲线是变量记录的活,报警有没有触发是报警记录的活,而「当时操作员是谁、执行了哪一步操作、填了什么备注」只能放用户归档。

项目变量记录报警记录用户归档
存储内容过程值(模拟量、开关量)报警事件业务数据(文本、数值、时间)
表结构WinCC 自动生成WinCC 自动生成用户自定义字段
默认查询方式趋势控件、变量记录控件报警控件用户归档控件、ODBC/SQL
典型用途趋势曲线、历史数据报警列表、事故追忆批次追溯、操作审计、报表

其实很多项目选变量记录还是用户归档,一开始是拍脑袋定的。我的判断标准很简单:这条数据后续要跟业务对象(订单、批次、操作员)绑定做筛选,就放用户归档;只是单纯按时间画曲线,放变量记录。两者不是替代关系,变量记录画趋势图很方便,但没法回答「这批料一共消耗了多少蒸汽、哪个班组的废品率最高」这类问题。用户归档的价值就在于可以用 BatchNo 把多条记录串起来,形成一条完整的业务链。

用户归档之所以做追溯方便,是因为它的字段是开放的。变量记录哪怕再丰富,也只能存「什么变量、什么时间、什么值」;用户归档可以存「哪条产线、哪个批次、谁操作的、中间改过几次配方、最终结果如何」。这个自由度,是它存在的根本理由。

2.2 归档表的字段设计:类型、主键、时间戳

在 WinCC Explorer 里右键「用户归档」新建一个归档,起名叫 BatchArchive,激活项目之后,SQL Server 里就多了一张表,表名是 UA#BatchArchive。注意这个 # 号,它是 WinCC 生成表名的固定格式,也是后面 ODBC 踩坑的根源之一。

字段类型方面,WinCC 组态界面里可选的是文本、整数、浮点、日期时间这几类,够用了。常见的坑是设计阶段想把批次号建成数值字段——如果批次号有前导零或者带字母,必须用文本;如果只用来做自动递增的流水号,才考虑整数。

字段建议参考这个配置:

字段名类型说明
WriteTime日期时间写入时间,默认取服务器当前时间
TagName文本变量名,方便之后按变量过滤
TagValue浮点值,按实际量程选类型
Operator文本操作员,从运行系统读取
BatchNo文本批号,用于追溯
Remark文本备注,长度够用就行

关于主键,WinCC 用户归档默认不带主键约束,插入没问题,但数据量大了之后查询会变慢。我一般会在运行一段时间后,手动在 WriteTime 上建一个非聚集索引。这个索引在 WinCC 重新生成归档之后会被丢掉,到时候要重新建,属于部署文档里必须写的一行。

写时间戳时,最稳妥的是在 INSERT 里用 GETDATE(),让 SQL Server 自己取服务器时间。别在 C 脚本里拼字符串时间,格式一错,SQL 就执行失败。服务器时间和现场时间不一致的问题,第 5 章会专门说。

数据存在哪?经典 WinCC 的项目数据库,SQL Server 实例名一般是 .\WINCC,数据库名形如 CC_项目名_计算机名。这一层信息平时用不上,等你要用外部工具直查归档表时,全靠它定位。

2.3 两条读取通路:ODBC 脚本与 SQL 直连

访问用户归档有两条路。一条是 WinCC 自带的 ODBC 数据源,DSN 名字就叫 WinCC,脚本里用「DSN=WinCC;UID=sa;PWD=你的密码」连上即可,这是最省事的方式,代码见第 3 章。另一条是绕过 WinCC,直接用 SQL Server 客户端(SSMS 或 Excel ODBC)连接 .\WINCC 实例,用 SQL 查询归档表。这一条适合报表开发和运维排查,第 6 章专门讲。

需要提醒的是,TIA Portal 里精智面板的用户归档和经典 WinCC 不是一套东西。精智面板的用户归档数据存在面板本地,通过面板的「数据记录」控件查看,机制和经典 WinCC 的 SQL 表不一样。本文后面的代码和 SQL 都是针对经典 WinCC 的,用到 TIA 时注意区分。

3. 把用户归档跑起来:建表、写 INSERT、设触发

这一章从零开始做一个能用的用户归档,以经典 WinCC V7 为例,按「组态建表 → 脚本写入 → 触发设置」三步走。做完之后,运行系统里每点一次按钮,归档就多一条记录。

3.1 在组态里新建用户归档并定义字段

打开 WinCC Explorer,左侧树里找到「用户归档」,右键选择「新建」,出现归档属性页。先起名 BatchArchive,然后在「字段」页里按第 2 章那张表把字段加进去。每个字段定义完类型和长度,保存。

激活项目后,WinCC 会自动在项目数据库里创建 UA#BatchArchive 这张表。想确认表是否存在,可以在 WinCC 的「信息视图」看选件诊断,也可以直接用 SSMS 连上去查,连接信息在第 6 章。

这里有一个细节:组态时字段名如果用了中文,SQL 查询时也要用方括号包住。公司内部规范建议字段名统一用英文,省得后面写 SQL 和报表时光顾着转义。

3.2 用 C 脚本写一条 INSERT:ODBC 直连项目数据库

写入用标准 ODBC API。C 脚本编辑器的「动作」里新建一个脚本,挂在按钮的鼠标点击事件上:

#include "apdefap.h" #include "windows.h" #include "sql.h" #include "sqlext.h" void OnClick(char* lpszScreenName, char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName) { SQLHENV henv = SQL_NULL_HENV; SQLHDBC hdbc = SQL_NULL_HDBC; SQLHSTMT hstmt = SQL_NULL_HSTMT; SQLRETURN rc; // 连接字符串:DSN 是 WinCC 安装时自动建的,指向当前项目数据库 char szConn[128] = "DSN=WinCC;UID=sa;PWD=你的sa密码"; char szSQL[600]; // 取画面上的变量值,拼进 SQL double dTemp = GetTagFloat("Tank1_Temp"); sprintf(szSQL, "INSERT INTO [UA#BatchArchive] " "(WriteTime, TagName, TagValue, Operator, BatchNo) " "VALUES (GETDATE(), 'Tank1_Temp', %.2f, 'OperatorA', 'B20251108-01')", dTemp); // 初始化 ODBC 环境 SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0); SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); // 无提示方式连接,运行时不弹 ODBC 对话框 rc = SQLDriverConnect(hdbc, NULL, (SQLCHAR*)szConn, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { SQLFreeHandle(SQL_HANDLE_DBC, hdbc); SQLFreeHandle(SQL_HANDLE_ENV, henv); return; } SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); rc = SQLExecDirect(hstmt, (SQLCHAR*)szSQL, SQL_NTS); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { // 失败时把 szSQL 写进日志文件,粘到 SSMS 里手工执行 SQLFreeHandle(SQL_HANDLE_STMT, hstmt); SQLDisconnect(hdbc); SQLFreeHandle(SQL_HANDLE_DBC, hdbc); SQLFreeHandle(SQL_HANDLE_ENV, henv); return; } SQLFreeHandle(SQL_HANDLE_STMT, hstmt); SQLDisconnect(hdbc); SQLFreeHandle(SQL_HANDLE_DBC, hdbc); SQLFreeHandle(SQL_HANDLE_ENV, henv); }

代码逻辑分四段:拼 SQL、连接、执行、清理。重点是表名 [UA#BatchArchive] 的方括号——省略它,SQL Server 会把 UA#BatchArchive 当成临时表,直接报错。PWD 不是操作系统密码,是安装 WinCC/SQL Server 时给 sa 设的密码,忘了就用 sa 在 SSMS 里重新设置一次。

SQLDriverConnect 里的 SQL_DRIVER_NOPROMPT 是关键参数,运行时如果连接失败,它只返回错误码,不会弹出 ODBC 配置框,避免操作员误触。第四段的四个 SQLFreeHandle/SQLDisconnect 是把环境句柄、连接句柄、语句句柄依次释放,漏掉任何一个,长时间运行都会造成连接泄漏。

执行失败时最有效的排查不是看错误码,而是把 sprintf 拼出来的 szSQL 原样复制到 SSMS 里跑一遍。SSMS 报什么错,原因就在那。

提示:表名加方括号是硬性规则,改成你自己的归档名时,[UA#XXX] 的 XXX 要跟 WinCC 里显示的名字完全一致,包括大小写。

3.3 触发方式与写入频率:别把数据库当 PLC 变量表刷

写入脚本挂在哪,决定了归档数据的质量。我的习惯是分三种场景:

触发方式实现位置典型场景注意点
按钮动作C 脚本 OnClick操作确认、批次完成脚本里做好防连点
周期定时器Global Script C 定时器生产数据的周期性快照周期别小于 5 秒
变量变化回调VBS SetTag 联动设备状态切换防止无限递归

周期写入时要注意频率。很多人第一次写用户归档,上来就放一个 500ms 定时器,结果运行一小时后数据库膨胀、系统卡顿。用户归档本质是 SQL 写库操作,不是采集器。采集过程值用变量记录,用户归档记录的是「发生了什么」,粒度到秒级已经非常细了。

如果确实要高频批量写,就把多次 INSERT 合并成一条:

INSERT INTO [UA#BatchArchive] (WriteTime, TagName, TagValue) VALUES (GETDATE(), 'Tank1', 25.10), (GETDATE(), 'Tank2', 30.25), (GETDATE(), 'Tank3', 28.40);

一条语句插几十行,比循环几十次单条 INSERT 快一个数量级。我一般是攒够 20 条再执行一次,配合事务提交,归档线程基本不会成为瓶颈。现场还有更极端的做法:数据先攒在文件或内部数组里,每 5 分钟批量落一次库,适合归档量特别大的项目。

4. 把归档数据读出来:查询脚本、表格控件与历史趋势曲线

数据写进去了,下一步是让它变成能看的东西。这一章给三条路:脚本查询、用户归档控件、历史趋势曲线的绕法。

4.1 用 VBS 脚本查询归档:ADODB 的读取套路

WinCC 运行系统里除了 C 脚本,VBS 脚本读归档更顺手。ADODB 是 Windows 自带组件,在 WinCC 的 VBS 编辑器里直接能用:

Dim conn, rs, sql Set conn = CreateObject("ADODB.Connection") conn.ConnectionString = "DSN=WinCC;UID=sa;PWD=你的sa密码" conn.Open ' 按变量和时间范围取归档,注意时间要用本地时间字符串 sql = "SELECT WriteTime, TagName, TagValue, Operator, BatchNo " & _ "FROM [UA#BatchArchive] " & _ "WHERE TagName = 'Tank1_Temp' " & _ "AND WriteTime >= '2025-11-07 00:00:00' " & _ "AND WriteTime < '2025-11-08 00:00:00' " & _ "ORDER BY WriteTime" Set rs = conn.Execute(sql) Do While Not rs.EOF ' 生产环境把这行换成填充表格控件/写文件 MsgBox rs.Fields("WriteTime") & " | " & rs.Fields("TagValue") & " | " & rs.Fields("Operator") rs.MoveNext Loop rs.Close conn.Close Set rs = Nothing Set conn = Nothing

这段脚本把一段时间内某个变量的全部归档记录读出来。注意 WHERE 里 WriteTime 用的是字符串比较,SQL Server 会自动转成日期时间类型。查询条件最好精确到秒,否则 00:00:00 到 00:00:00 这种边界值会漏记。

rs.Fields 里的字段顺序取决于 SELECT 语句里写的顺序,不是表结构顺序。想要稳,就在 SELECT 里明写字段名,别用 SELECT *。代码里 rs.Fields("…") 的拼写要跟组态字段一字不差。我习惯先把结果集循环一次,把字段名打印出来确认无误,再写正式读取逻辑。

MsgBox 这一行在生产项目里不要出现。实际落地我一般是把读到的每一行拼成字符串,塞到画面上的 ListView 控件,或者直接写进 CSV 文件供 Excel 打开。

4.2 用户归档控件:不写代码的表格查看方式

如果只是想在画面上看归档数据,不需要写脚本。WinCC 图形编辑器对象选项板的「控件」组里有一个用户归档控件(UserArchive Control),拖到画面上,在属性里选择 BatchArchive,勾选要显示的字段,运行系统里就能看到一张可翻页、可过滤的表格。

这个控件适合给操作员看「最近做了什么」,但它默认不带复杂的聚合查询,想看「三个月里哪几个批次废品率超过多少」,还是走 SQL 查询更现实。所以我一般这样分工:画面实时查看用控件,追溯报表用 SQL 查询导出。

4.3 历史趋势曲线:为什么趋势控件画不了归档,怎么绕

「用户归档画成趋势曲线」这个需求,我在批次追溯项目里几乎每次都会被提出来。很多人在这一步翻车:想把用户归档的数据画成历史趋势曲线,结果发现 WinCC 的趋势控件(在线趋势控件)死活不出线。原因在于趋势控件的数据源只认变量记录,用户归档表不在它的数据源列表里。这不是配置错了,是设计上就不通。

要画用户归档的历史曲线,常见做法是绕道:把归档数据查出来,导出 CSV,用 Excel 插入折线图。代码就是在 4.1 的 VBS 基础上加文件输出:

Dim fso, f Set fso = CreateObject("Scripting.FileSystemObject") Set f = fso.CreateTextFile("C:\temp\archive_export.csv", True) f.WriteLine "WriteTime,TagValue,Operator" ' rs 是上面查询的结果集 Do While Not rs.EOF f.WriteLine rs.Fields("WriteTime") & "," & rs.Fields("TagValue") & "," & rs.Fields("Operator") rs.MoveNext Loop f.Close

导出之后,Excel 打开 CSV,选中时间和值两列插入折线图,就是一条标准的历史趋势曲线。WinCC 历史趋势曲线脚本如果指的是这一步,本质上不复杂,难点在导出前把时间、过滤条件处理好。

另一种不推荐的做法:把归档值先写回一个内部变量,再让变量记录把内部变量采下来,用趋势控件画。这个方案能出曲线,但是双写数据库,变量记录和用户归档各存一份,数据一致性全靠脚本保障,现场出过对不上的问题。除非客户明确要求画面里直接出线,否则我不用这招。先确认客户要的是「曲线」还是「数据可查」,多数时候他要的是能回答问题,Excel 表格加折线图就够。

5. 用户归档避坑与排查:五个现场踩过的坑

下面五条基本是现场复现率最高的,每一条我都实打实处理过。

5.1 执行 SQL 报 0x80040E14,归档写不进去

现象:脚本挂在按钮上了,点击后归档里没有新增记录,排查时发现 ODBC 执行返回 SQL_ERROR,错误码 0x80040E14。 原因:九成是表名没加方括号。UA#BatchArchive 里的 # 号会被 SQL Server 解析成临时表前缀,不加方括号,SQL 直接被拒。剩下一成是字段名跟组态里实际定义的不一致,特别是手写 SQL 时记错大小写。 解决:所有 SQL 里的表名一律写成 [UA#BatchArchive]。更稳的做法是先把拼好的 SQL 输出到日志,粘到 SSMS 手工执行,以 SSMS 的实际报错为准。这套问题的玄学成分很低,基本就是表名的锅。

5.2 归档里的时间比现场时间晚 8 小时

现象:归档查询出来,WriteTime 显示的时间和现场对不上,普遍晚 8 小时;后半夜 0 点写的记录,日期经常串到前一天。 原因:经典 WinCC 的变量记录时间戳内部按 UTC 处理,用户归档里我用 GETDATE() 取的是服务器本地时间。如果服务器系统时区设的是 UTC,或者项目组态时启用了 UTC 时间处理,两边就差 8 小时。 解决:统一时区口径。归档写入固定用 GETDATE() 取服务器本地时间,查询条件也传本地时间字符串,不要混用。条件允许的话,在归档里额外存一个本地时间字符串字段,Excel 打开直接看,省得每次转换。

5.3 DSN=WinCC 连不上,报数据源名称未找到

现象:C 脚本和 VBS 脚本写的一样,一台电脑能连,另一台连不上;64 位系统上外部程序连更是必现。 原因:经典 WinCC 自带的 DSN 注册在 32 位 ODBC 里。外部程序如果是 64 位进程,在 ODBC 管理器里看不到 WinCC 数据源,自然报数据源名称未找到。另外,同一台电脑装了多个 WinCC 版本,DSN 可能被后装的版本覆盖,指向了另一个项目的数据库。 解决:用 C:\Windows\SysWOW64\odbcad32.exe 打开 32 位 ODBC 管理器检查 DSN。外部程序要连的话,改用完整连接串,不依赖 DSN:

Driver={SQL Server};Server=.\WINCC;Database=CC_项目名_机器名;Uid=sa;Pwd=密码

项目名和机器名在 WinCC Explorer 标题栏能看到。

5.4 TIA Portal V15.1 找不到许可证 WinCC Comfort

现象:TIA V15.1 里打开精智面板项目,编译没问题,但激活运行时报找不到许可证 WinCC Comfort;用用户归档功能的项目尤其明显。 原因:最常见的是授权版本对不上——装的是 V15.1 软件,Automation License Manager 里读进去的却是 V14 或 V13 的授权,西门子授权按版本号认,直接失效。另一种是 ALM 服务被安全软件停掉,授权没被加载。 解决:打开 Automation License Manager 检查授权状态,版本不匹配就卸载旧授权重新读入 V15.1 授权。服务问题就把 ALM 相关服务设为自动启动并手动拉起。精智面板项目里用户归档功能占用的 PowerTags 数量计入授权额度,归档字段多、变量多的项目,要确认购买授权覆盖了实际用量。

5.5 运行一年后归档表膨胀,查询越来越慢

现象:归档表积累几百万行之后,用户归档控件打开要十几秒,导出 CSV 直接卡住。 原因:没有索引。WinCC 建的用户归档表默认不带索引,全表扫描在数据量小的时候无所谓,几百万行以上就顶不住了。更坑的是,WinCC 升级或重新生成项目后,手动加的索引会被表重建丢掉。 解决:在 WriteTime 和 TagName 上建非聚集索引。

CREATE NONCLUSTERED INDEX IX_UA_BatchArchive_WriteTime ON [UA#BatchArchive] (WriteTime);

索引建完,按时间过滤的查询速度能差一个数量级。治本的办法是定期清理:三个月前的数据导出归档后删除,或者按年分表。索引脚本和清理策略要写进部署文档,这些血泪经验不写下来,下次升级还得再踩一遍。

6. 用 SQL 直查归档表:不需要打开 WinCC 也能拿数据

用户归档最大的好处,是它不在 WinCC 里「锁死」。只要项目数据库在线,SSMS 直接连上去就能查,很多临时要数据的场合根本不用开 WinCC。

连接信息对照表:

项值备注
SQL Server 实例.\WINCC远程电脑改成 IP\WINCC
数据库CC_项目名_计算机名在 WinCC Explorer 标题栏看
登录名sa安装时的 sa 密码
目标表dbo.[UA#BatchArchive]# 号加方括号

典型查询:

SELECT WriteTime, TagName, TagValue, Operator, BatchNo FROM [CC_BatchPlant_PC01].[dbo].[UA#BatchArchive] WHERE TagName = 'Tank1_Temp' AND WriteTime >= '2025-11-01 00:00:00' AND WriteTime < '2025-12-01 00:00:00' ORDER BY WriteTime;

在 SSMS 里跑出结果,就说明整个归档链路是通的。把这段 SQL 存成视图,还能在 Excel 的「数据 → 从 SQL Server」直接连接刷新。Excel 的连接向导里,服务器名填 .\WINCC,数据库选 CC_项目名_计算机名,表和视图都能当数据源,表名同样要写成 [UA#BatchArchive] 带方括号。业主说报表要更新,我都是把这个连接方式交出去,他自己刷新就行。

注意:WinCC 项目没激活或者运行系统没起来时,数据库可能处于独占状态,外部连接会被拒绝,这是正常的,激活后再查。

有一次业主凌晨打电话要三天前每个操作步骤的精确时间,我远程打开 SSMS,SELECT 结果导出 CSV 发过去,全程没动 WinCC 画面。从那以后我每次做完用户归档项目,都强制走一遍「先建表、再写脚本、SSMS 裸查验证」的流程,确认 SQL 能查到数据才算交付完。希望帮到你。

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

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

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

立即咨询