尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

西门子WinCC历史数据写入SQL Server:VBS脚本+ADO存储方案详解

发布时间:2026/9/26 5:46:56

资讯中心
01
ARTICLE

西门子WinCC历史数据写入SQL Server:VBS脚本+ADO存储方案详解

西门子WinCC历史数据写入SQL Server:VBS脚本+ADO存储方案详解
最近一直在搞西门子博图 WinCC 的历史数据存储发现群里问得最多的就是怎么把实时变量怼进 SQL 数据库。这个问题看着简单真正做起来牵扯到 SQL Server 建库、ODBC 配置、WinCC 脚本定时触发、连接断开重连这些环节光一个 32 位 ODBC 就能卡住一半人。今天我就把整套流程从头到尾盘一遍把我实际调试过程中踩过的坑、试过的方案、最后稳定运行的配置都写出来给正在做上位机数据采集的同行一个可以直接抄作业的参考。这套方案适合的读者你在用西门子博图 WinCCTIA Portal 里的 WinCC Professional 或 WinCC Comfort做上位机监控现场有几十上百个温度、压力、流量、电机电流这类实时变量需要存进 SQL Server 供后续做报表、趋势分析、MES 对接。如果你只是做简单趋势曲线WinCC 自带的归档其实够用但如果要跟第三方系统做接口、要用 SQL 查询做统计汇总那自定义写 SQL 数据库就是绕不开的路。1. 整体设计与方案拆解1.1 为什么放着自带归档不用偏要写 SQLWinCC 本身就带历史数据归档功能Professional 版的归档存在项目自带的 SQL Server 实例里用自带的 Trend Control 直接拉曲线很方便。但我个人做过几个项目之后发现它有明显的局限性第一归档数据是存在 WinCC 项目内建的 Runtime 数据库里第三方系统想直接读数据库做报表要么通过 WinCC OPC UA 的 Historical Access 接口要么用 WinCC 自带的报表控件灵活度不够第二如果客户要求历史数据至少保存三年WinCC 归档库膨胀之后查询会明显变慢第三自带的归档系统一旦项目运行起来迁移、备份、恢复到另一台机器都比较麻烦。所以很多现场集成商都会做一个自定义的数据存储方案WinCC 脚本定时把变量值写入 SQL Server 的指定库表。这样数据库是独立的DBA 可以直接用标准 SQL 做查询、建索引、做数据清理客户要什么报表开发工程师直接写 SQL 就行完全不依赖 WinCC 的展示控件。这也是我推荐用这种方式的主要原因——不是自带归档不行而是自定义 SQL 存储的开放性和可控性更好。1.2 整体技术路线脚本 ADO 定时触发器整个方案的技术栈非常简单核心就三块WinCC 变量实时数据源、VBS 脚本数据搬运工、SQL Server数据落脚点。WinCC 自带的全局脚本引擎支持 VBScript 和 C 脚本我推荐用 VBScript 做这件事因为字符串拼接、ADO 连接、Excel 导出这些操作 VBS 写起来直观语法也比 C 脚本简单得多。脚本通过 ADOActiveX Data Objects接口连接 SQL Server不需要额外装什么插件Windows 系统自带 ADODB 组件。触发方式上用 WinCC 全局脚本的定时器触发器我一般在 Global Script Runtime 里建一个周期触发的脚本10 秒或者 5 秒跑一次具体看现场数据的实时性要求用类似“心跳包”的方式把最新的变量值写进 SQL Server。这么做的好处是逻辑完全独立——无论操作员有没有对着画面操作后台脚本自己跑自己的不会因为画面切换、报表打开而中断。整个链路就是“变量变化/时间到 - 脚本触发 - 读取变量 - 组装 SQL - 执行 INSERT”只要这一条链路通畅数据就不会丢。2. SQL Server 建库建表与 ODBC 配置2.1 建库建表字段怎么设计才能兼顾查询和存储先说建表。我在 SQL Server Management Studio 里面手工建库库名可以根据项目来比如 HistoryDB然后建一张历史存储表。现场变量如果是几十个可以每个变量一张表也可以所有变量共用一张宽表。我的经验是如果变量数量少二三十个以内且数据类型相对一致用一张宽表最省事如果变量数量多、类型杂有温度、有压力、有开关量用窄表加个 TagName 字段反而更灵活。下面是我常用的一张窄表结构这个结构我前后用了好几个项目查询和存储性能都比较均衡CREATE TABLE dbo.TagHistory ( Id BIGINT IDENTITY(1,1) NOT NULL PRIMARY KEY, TagName NVARCHAR(80) NOT NULL, TagValue FLOAT NOT NULL, Quality INT NOT NULL DEFAULT 0, CreateTime DATETIME NOT NULL DEFAULT GETDATE() ); CREATE NONCLUSTERED INDEX IDX_TagHistory_Time ON dbo.TagHistory (CreateTime ASC); CREATE NONCLUSTERED INDEX IDX_TagHistory_TagName ON dbo.TagHistory (TagName ASC);我把 TagValue 统一用 FLOAT好处是所有模拟量温度、压力、流量、液位都能直接装整数型也不会有精度问题。开关量、状态量这些离散信号我会在脚本层直接转成 0 或 1 再存类型不会冲突。索引只加了时间和标签名两个非聚集索引因为实际查询场景无非是“按时间范围查某个变量的变化曲线”或者“按变量名统计某段时间内的均值”这两个索引足够了没必要建太多索引拖慢插入速度。这里插一个题外话很多人问 SQL Server 2012 的数据库备份能不能拿到 SQL Server 2008 上还原。答案是低版本绝对不能还原高版本备份文件这个兼容性是单向的。如果你现场还有老版本 2008 的服务器最好统一数据库版本否则备份恢复那天一定会炸。2.2 32 位 ODBC新手最容易在这里卡三天WinCC 是 32 位应用程序即使你的博图装在 64 位 Windows 上进程也还是 32 位而 64 位 Windows 自带两个 ODBC 管理器64 位的在“管理工具”里打开32 位的要运行C:\Windows\SysWOW64\odbcad32.exe。如果你配置 DSN 用的是 64 位 ODBC 管理器WinCC 脚本运行时会报“找不到数据源名且未指定默认驱动程序”。这个坑我当年第一次做的时候踩过查了很久才发现是位数不匹配。配置步骤是这样的先运行odbcad32.exe注意是 SysWOW64 目录下的在“系统 DSN”选项卡里添加一个指向 SQL Server 的 DSN比如叫 WinCC_History。驱动就选 “SQL Server Native Client 11.0”或者“ODBC Driver 17 for SQL Server”配置服务器地址、登录账号、默认数据库指向 HistoryDB。测试连接成功后点确定后面脚本里直接用这个 DSN 名连接。但其实我想说做了几个项目之后我已经不怎么用 ODBC DSN 了。VBS 里用 ADODB 直接写连接字符串指定 ProviderSQLOLEDB不依赖 DSN。这样省掉 ODBC 配置环节脚本在任何一台电脑上都能跑不用每部署一台机器就去配置数据源。后面给的代码就是这条路。3. 脚本逻辑与核心代码实现3.1 项目函数数据库连接复用避免反复开关连接写 VBS 脚本的第一个关键决定就是连接对象是每次脚本运行都新建还是全局复用。我一开始图省事每个定时器脚本里都现开现关连接结果发现两个问题第一SQL Server 的连接握手开销不小10 秒一次的高频插入会白白耗费大量资源第二连接开得多了SQL Server 端会积累大量 TIME_WAIT 连接如果不及时释放最终会导致“连接数不足”的报错。后来我改成在项目运行期间保持一个全局连接对象定时脚本里每次都复用这个连接只有连接断开时才重新建立。WinCC 的全局脚本里可以用Option Explicit声明模块级变量只要把这个连接对象定义在脚本最外层整个 Runtime 周期内它都活着。下面是我在项目函数里写的连接初始化代码你可以直接复制到博图的 Global Script 里Option Explicit Dim g_adoConn Dim g_connStr g_connStr ProviderSQLOLEDB;Data Source.;Initial CatalogHistoryDB;User IDsa;Passwordyourpass; Function InitDBConnection() On Error Resume Next If IsObject(g_adoConn) Then If g_adoConn.State 1 Then InitDBConnection True Exit Function End If End If Set g_adoConn CreateObject(ADODB.Connection) g_adoConn.ConnectionString g_connStr g_adoConn.ConnectionTimeout 10 g_adoConn.Open If Err.Number 0 Then g_adoConn.CommandTimeout 30 InitDBConnection True Else InitDBConnection False End If End Function这里有几个细节要特别说明。Data Source.表示连接本机默认实例如果现场是另一台服务器就写成Data Source192.168.1.10,1433或者Data Source服务器名\实例名。Initial Catalog就是数据库名一定要和实际库名对上否则连接没问题但后面 INSERT 会报对象名无效。g_adoConn.State 1里的 1 是 ADODB 库中 adStateOpen 的枚举值VBS 里有些环境不认识常量名直接写数字反而最保险——这个坑是 VBS 脚本在不同环境下运行差异导致的我踩过之后就不再引用 ADODB 常量了。3.2 全局脚本定时插入的核心逻辑有了连接接下来就是怎么把变量值读出来塞进去。WinCC 读取变量的方式有两种一种是通过HMIRuntime.Tags(标签名).Read另一种是通过变量对象直接读值。前者会走脚本引擎和变量管理器的完整通道后者更快但不适合所有场合。我实测下来如果只是周期读取HMIRuntime.Tags(Tag_Flow).Read足够稳定每秒读几百个变量都不成问题。下面是我在全局脚本里实际用的定时写入代码这个脚本周期触发负责采集三个变量的最新值并写入 SQL 历史表Sub SaveTagHistory() On Error Resume Next If Not InitDBConnection() Then Exit Sub End If Dim objTag1, objTag2, objTag3 Dim val1, val2, val3 Set objTag1 HMIRuntime.Tags(Tag_Flow) Set objTag2 HMIRuntime.Tags(Tag_Pressure) Set objTag3 HMIRuntime.Tags(Tag_Temp) val1 objTag1.Read val2 objTag2.Read val3 objTag3.Read Dim strSQL strSQL INSERT INTO dbo.TagHistory (TagName, TagValue, Quality, CreateTime) VALUES strSQL strSQL (Tag_Flow, val1 , 0, GETDATE()), strSQL strSQL (Tag_Pressure, val2 , 0, GETDATE()), strSQL strSQL (Tag_Temp, val3 , 0, GETDATE()) g_adoConn.Execute strSQL If Err.Number 0 Then 连接可能已断开强制下次重建 On Error Resume Next g_adoConn.Close Set g_adoConn Nothing End If End Sub串成一条多值 INSERT 是我做性能优化后得出的经验。如果每写一个变量就执行一次 Execute10 秒周期几十个变量就会产生几十次数据库往返而用一条语句插多行SQL Server 只需要解析一次速度提升非常明显。实测下来同样的数据量多值 INSERT 的耗时只有逐条插入的三分之一左右。另外注意我在 INSERT 语句里用了Quality字段固定填 0。如果你现场的值来自 OPC UA 通信质量戳可能携带通信状态信息那可以单独读取通信质量字段再写入。这个字段先留着后续要排查数据质量时就会感谢自己当初多写了这一列。3.3 数据积压与丢失没有你想的那么吓人但也不能不管写 SQL 数据库最怕的就是数据库暂时连不上导致脚本执行失败、数据段丢失。有人会想加一个本地缓存机制先写入本地文件等数据库恢复了再补录。对于大多数中小型项目我认为这个复杂了。SQL Server 连接中断一般是短时的比如数据库服务重启、网络闪断中断十几秒到几分钟损失一两笔数据对历史趋势分析基本无感。但如果你的场景是计量结算、环保数据上报这类不允许丢失数据的场合那确实要做补采机制。我的折中做法是脚本里检测到 Execute 报错时把当前时间戳和变量的最新值写入 WinCC Runtime 自带的诊断日志文件用HMIRuntime.Trace打印后续人工或写个小工具做数据补齐。这个方案不增加现场复杂度又能给运维留一条后路。等到你应用场景真需要严格补采再上本地 SQLite 缓存也不迟没必要一上来就把架构搞得很重。实际情况中我反而更担心脚本执行超时导致后续触发器堆积。WinCC 全局脚本是串行执行的如果上一个周期还没跑完下一个周期触发会被排队积累多了脚本运行会越来越慢最终可能出现“脚本没响应”的提示。为了避免这个我倾向于把采集周期拉长到 10 秒以上并且脚本里不要做太多无关操作保证单次执行在 1 秒以内。如果确实需要毫秒级高频采集那 WinCC 全局脚本不是你的首选方案直接用 PLC 的 DB 块加 SIMATIC S7-1500 的 SQL 指令或者单独做采集站更合理。4. 调试路上的坑现场故障排查实录4.1 从启动到落库全链路排查表我在几个不同现场调试这套方案时积累了一张排查表按“从 WinCC 到 SQL Server”的链路顺序整理。只要数据没写进去按这个顺序查基本一轮就能锁定问题。故障现象排查思路常用解决方法脚本根本不动看 WinCC 全局脚本运行状态看是否有语法错误在脚本里加 Trace 输出确认定时器触发器是否已激活连接失败提示 80004005检查连接字符串里服务器名、账号、密码先用 UDL 文件测 ADO 连接确认 SQL Server 允许远程连接能连接但 INSERT 报错检查表名、字段名是否写错先在 SSMS 里手工执行同样 SQL验证语法数据写入但不更新检查定时器是否被其他脚本阻塞看脚本执行耗时把周期拉长系统运行几天后写库变慢检查表是否膨胀、索引碎片定期重建索引、归档老数据这套排查逻辑的核心思想是“分环节验证”先保证脚本能读变量再保证连接能打开再保证 SQL 语句能执行三个环节都通了数据自然会落库。不要一上来就怀疑是 WinCC 脚本引擎有问题十次里面有八次都是连接字符串或者 SQL 语句的小错误。4.2 几个实际遇到的“鬼打墙”问题第一个让我印象深刻的坑是 64 位系统下 ODBC 位数问题。当时给现场一台新电脑部署项目脚本报错“找不到 Microsoft OLE DB Provider for SQL Server”服务器环境都是新的怎么会缺组件后来一看是这台电脑只装了 64 位 ODBC 驱动X64 和 X86 两套驱动都有但我的连接字符串里 ProviderSQLOLEDB 需要 32 位版本的 OLEDB 提供程序。解法是在连接字符串里换成ProviderSQLNCLI11或者安装 SQL Server Native Client 的 32 位版本。这个坑最容易出现在 Windows 10/Server 2016 之后的干净系统上老系统反而没事。第二个是脚本偶发不执行。我最初用 WinCC 内置的定时器做 5 秒触发现场运行一天后发现有个别时段数据缺失用 Trace 一查发现脚本执行了但没走到 INSERT。后来定位到是因为 WinCC 变量Read方法偶发会抛错比如变量还没有被激活或者超时脚本里又有On Error Resume Next导致错误被吞掉了、后面的 INSERT 根本没执行。解决方式是在读取变量前检查Err.Number如果读值失败就直接跳过本次写入并打印一条 Trace这样至少不会把损坏的数据写进库里。第三个是关于 WinCC 8.1 授权问题的连锁反应。有一次客户现场用的是 WinCC 8.1装完授权后全局脚本运行不了一查是授权不完整导致脚本引擎根本没有运行权限。这个问题不常见但如果你的博图版本是 WinCC 8.1 而且授权是后补的注意确认全局脚本 Runtime 的授权项是否存在。顺带说一句TIA Step7 Pro WinCC V15.1/V16/V17 的授权机制类似授权不全不只是打不开项目的问题脚本引擎也会受牵连。4.3 画面和组态的“周边坑”也不容忽视写 SQL 存储方案的时候难免会顺手改一下 WinCC 画面期间也踩了不少组态细节的坑。比如 WinCC 里用“组显示控件”显示历史趋势时发现曲线对不上时间轴排查半天发现根本原因是组显示控件的时间范围在运行版里默认只显示最近 15 分钟而我的 SQL 数据是 10 秒一条导致曲线看起来像一条直线。其实这不是数据问题是显示控件的时间区间没有跟随源数据范围更新。还有一次客户反映 WinCC 画面整体往右偏移了检查下来是分辨率适配的问题——画面是在 1920×1080 的电脑上做的运行在 1366×768 的触摸屏上WinCC 没有自动缩放。解决方法是在画面属性里设置适应窗口模式Fit to Window同时把画面对象的坐标改成相对布局而不是绝对像素坐标。这些东西跟 SQL 存储没关系但在现场调试时经常会一起爆发所以列出来给你们提个醒。另外注意WinCC 的 C 脚本里设置 RGB 颜色时误用 VB 的 RGB 函数会报“脚本语句未结束”或者编译错误。C 脚本里应该用RGB(r, g, b)宏或者直接用十六进制值 0xRRGGBB。看起来是小事但在现场没有 VS 调试环境时这类语法错误排查起来特别费时间。5. 升级扩展从单机存储到系统集成的路径5.1 数据量大了怎么处理写库方案跑通后很多人接着会问数据积累几个月后表体积越来越大查询越来越慢怎么办我建议分两步走。第一步是表分区或者按日期分表比如建表结构的时候预留按月分表的空间TagHistory_202502、TagHistory_202503脚本里根据GetDate()自动选择写入哪张表。第二步是定期归档和清理用 SQL Server 的作业计划把三个月前的数据导出到备份库或者压缩文件再从主表里删除。这些操作用 T-SQL 的存储过程就能做WinCC 这边完全不用改动。如果你的项目需要把数据接入 MES 或者 ERP那最好在 SQL 层做视图或者存储过程供上层系统调用千万不要让 MES 直接读 WinCC 的运行库。把数据写到独立的历史库之后你完全可以把库表结构给客户的信息化部门让他们自由发挥做报表。我在一个项目里就是直接把 HistoryDB 开放给客户的 BI 工具做连接他们自己写了报表展示每台设备的 OEE 和能耗趋势这个体验比 WinCC 自带的报表好太多了。5.2 如果用 MySQL 或达梦改动大吗有些客户不想用 SQL Server授费原因或信创要求问能不能改成 MySQL 或者达梦。从 VBS 的角度看ADODB 支持的 Provider 可以换比如 MySQL 用ProviderMSDASQL加 MySQL ODBC 驱动达梦也有自己的 ODBC 驱动。核心的改动点是连接字符串、可能的 SQL 语法差异比如达梦对某些标准 SQL 的支持度不同以及数据类型映射。这个工作量不大但确实需要逐一验证。如果你要跑国产数据库适配一定要先在桌面端用 ADO 连接测试通了再上 WinCC否则在博图里调试数据库驱动问题极其痛苦。6. 写在最后的几个体会这套 WinCC 写 SQL 的方案我在三四个项目里应用过从食品饮料产线到污水厂工艺监控稳定性一直很可靠。踩过这么多坑之后我最大的体会是这类跨系统集成的问题表面看是脚本怎么写实际上是对两端技术的掌握——SQL Server 一边要知道连接串、驱动、权限、索引这些基础WinCC 一边要懂脚本引擎、触发器机制、变量读取的边界只有两头都打通了中间才能顺畅。最后分享一个小技巧调试阶段可以在 WinCC 脚本里临时加一个自己的调试开关变量比如内部变量 DBG_Switch为 1 时把每次 INSERT 前的 SQL 语句都写到 Trace 文件里这样 SQL 写错了能立刻看到是什么语句。项目稳定后把这个开关关掉即可不影响运行。希望这篇内容能帮你少走几天的弯路有问题欢迎在评论区交流。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。