尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
WinCC中使用VBScript与SQL Server实现报表查询:从连接数据库到导出CSV
简介这是一份以电子文档形式整理的西门子WINCC SQL报表查询实现教程面向工业自动化工程师与组态软件开发者重点解决在WINCC人机界面中借助VBS脚本和ActiveX控件完成生产数据入库、查询与报表展示的问题。文档从SQL Server 2005数据库创建讲起内容依次覆盖新建数据库、定义表格字段、编写WINCC全局脚本写入数据再到报表画面组态中使用表格显示控件和日期选择控件实现按日期查询、按钮触发显示以及导出为电子表格后打印整体流程清晰可循。压缩包仅含1个文档文件大小1.11MB累计已有1680人学习下载。附录给出了数据库写入与查询的完整VBS脚本示例可直接参考改造针对表格显示控件无法正常注册使用的常见环境问题也给出了控件注册命令的详细解决方法帮助读者避开实操配置坑点。1. 为什么非要用 VBScript 在 WINCC 里写 SQL 报表先绕开三个最常见的弯路做过程控制的工程师迟早会撞上同一个需求现场几十台设备跑了一天报警、产量、温度曲线全躺在数据库里领导第二天早上要报表而你手里的 WINCC 画面除了趋势控件和归档表格拿不出能自动汇总、筛选、导出 Excel 的东西。于是有人去翻 WinCC Online Help有人去装 Report Generator有人用 WinCC 自带的 OLEDB Provider 在外部写程序——结果不是授权没到位就是报表格式对不上现场习惯最后所有人都回到同一个解法在 WINCC 画面里用 VBScript 写 SQL 查询把结果丢给表格控件。这套方案的真正价值不是它比 Report Generator 功能多而是它不依赖额外授权、不要求现场装报表软件、不会因为画面发布之后就改不了脚本。你只需要三样东西一个能跑脚本的 WINCC 画面、一个能放数据的表格控件常见的是微软的 MSFlexGrid 或 MSHFLexGrid也有不少人用 Siemens 自己的 Control Tool 里的控件、一段能连上 SQL Server 的 VBScript。看起来简单但实际做的时候坑几乎都埋在“控件拿不到数据”“脚本报错却查不到原因”“SQL 语句里中文乱码”这三件事上。这篇文章我把整个实现过程、参数设置和踩过的坑一次说清楚。适合看这个方向的人已经在用 WINCC 7.x、维护或开发过程画面手头有 SQL Server 或 Windows 认证的数据库需要做日报/周报/历史报警查询。如果你刚碰 WINCC连 C 脚本和 VBScript 都分不清建议先跑通一个最小例子再往下读。2. 先把架构和原理捋清楚WINCC 里的 VBScript 凭什么能查 SQL Server2.1 WINCC 脚本体系里为什么选 VBScript 而不是 C 脚本WINCC 从 6.0 开始就内置了两套脚本环境C 脚本C Script和 VBScript。C 脚本更适合做画面对象的消息触发、变量读写和简单数学计算但一旦涉及字符串拼接、ADO 对象调用、动态创建控件实例写起来就特别别扭。VBScript 的优势恰好在这里体现它天生就是面向对象的脚本语言创建 ADODB.Connection、ADODB.Recordset、调用控件方法这些操作语法直接调试时还能用 MsgBox 弹中间结果而 C 脚本里弹窗要调用 WinCC 的 MessageBox 函数麻烦得多。还有一个关键区别VBScript 可以直接访问 Windows 脚本宿主提供的对象模型而 C 脚本做不到。这一点直接决定了 SQL 查询功能的实现路径——你在 WINCC 画面里写的 VBScript 本质上和 Windows 下任意一个 .vbs 文件没有太大区别只是运行在 WINCC 的进程里、能同时读取 WINCC 的变量归档和画面对象。所以你可以把这段脚本理解成一个跑在 WINCC 内部的“小工具”通过 ADO 去连数据库再把查询结果填到画面上的表格控件里。在实际的项目里我通常的做法是把所有 SQL 查询逻辑集中写在一个全局脚本或画面脚本里从按钮事件调用。不要在每一个按钮事件里都写一遍连接字符串和 SQL 语句否则后期维护字段映射时会疯掉。这算是第一个原则脚本分层连接与查询分离。2.2 ADO SQL Server这套查询链路的工作流程整个查询链路一共四步和你在任何开发环境里写数据库程序没有本质区别只是运行环境变成了 WINCC 画面第一步创建 ADODB.Connection 对象指定连接字符串包括数据库服务器地址、数据库名称、认证方式Windows 认证或 SQL 认证。 第二步打开连接。 第三步创建 ADODB.Recordset 或直接执行 SQL 语句把结果集拿到内存里。 第四步把 Recordset 的内容逐行写入表格控件对应的单元格。这套链路里有三个最容易被忽视的细节。第一个是连接字符串里的 ProviderWINCC 项目常用的是 SQLOLEDB但如果你用 SQL Server 2008 以上版本SQLNCLI 或 MSOLEDBSQL 更合适这直接关系到能否读到 VAR 表的归档数据。第二个是 Recordset 的游标类型如果只用默认的只读游标在某些控件绑定场景下会导致无法获取行数建议显式指定 adOpenKeyset。第三个是表格控件的填充方式——很多人试图用数据源绑定DataSource 属性直接显示查询结果但对 MSFlexGrid 这类控件数据源绑定经常因为列类型不匹配崩溃老老实实循环写单元格反而最稳定。2.3 关键选型表格控件用哪个数据怎么走WINCC 画面里能放哪些控件取决于你的 WINCC 版本和安装时选了哪些选件。常见的选择有三个MSFlexGrid、MSHFlexGrid微软的、Siemens WinCC Dashboard Control西门子的。MSFlexGrid 是最老牌的虽然界面丑了点但胜在稳定、方法齐全、网上资料多。MSHFlexGrid 是 MSFlexGrid 的升级版支持 ADO 数据绑定和分层显示但绑定模式在 WINCC 里兼容性不如老版本。西门子自己的控件和其他选件绑定更紧密但需要额外授权而且上手难度高。我个人的建议是别折腾控件选型画面里放一个 MSFlexGrid通常 ActiveX 控件注册后名为 MSFlexGridLib.MSFlexGrid 或类似名称然后所有数据填充都用脚本循环写。具体做法是先设置固定行数FixedRows和总行数Rows、列数Cols然后按行按列写入 TextMatrix 或设置 Text 属性。这样做的性能虽然不如数据源绑定但查询结果最多几千行报表场景完全够用而且调试起来清清楚楚。3. 做一张能查 SQL 报表的画面数据库准备与第一个最小脚本3.1 建表和测试数据先把 SQL Server 这边搞定不管 WINCC 那边脚本怎么写数据库这边得先有个能查的表。大多数场景是查 WINCC 的变量归档日志即 RT_xxx 表但为了不受归档表结构和权限影响建议先在 SQL Server 里建一张自己的业务表插几行测试数据把脚本链路跑通后再换回归档表。下面这段 SQL 是典型的简化示例实际项目中你会新建一个作业记录表来存产量和报警计数。-- 建一张简单的作业记录表用来做报表查询测试 CREATE TABLE dbo.Report_Test ( RecordID INT IDENTITY(1,1) PRIMARY KEY, ProductName NVARCHAR(50), DeviceName NVARCHAR(50), OutputQty INT, AlarmCount INT, RecordTime DATETIME ); -- 插入几行测试数据日期可以用 GETDATE() 生成当天时间 INSERT INTO dbo.Report_Test (ProductName, DeviceName, OutputQty, AlarmCount, RecordTime) VALUES (N产品A, N设备1, 120, 3, GETDATE()), (N产品B, N设备2, 80, 0, GETDATE()), (N产品A, N设备2, 95, 1, GETDATE());这里有个很容易忽略的事情字段类型尽量用 NCHAR、NVARCHAR 而不是 CHAR、VARCHAR因为在 WINCC/VBScript 环境下中文字符串的编码常用 UTF-16如果你在数据库连接字符串里没有指定字符集字段类型又是 VARCHAR查询结果里中文就会变成问号或乱码。后面避坑章节会专门说。3.2 在 WINCC 画面里放控件并注册名称数据库表建好了接下来回到 WINCC 图形编辑器。新建一个画面从“对象选项板”的“控件”里拖一个 MSFlexGrid 到画面中央把它拉到你想要的表格大小。然后右键控件在属性对话框里把控件名称改成一个有意义的标识符比如 FrxReportGrid修改控件名称这个动作极其重要因为后面 VBScript 里访问控件全靠这个名字。很多人直接在脚本里写 ScreenItems(MSFlexGrid1)结果发布到别的机器上控件实例名不一致脚本立刻报错。建议从一开始就统一命名规则报表相关控件一律用 Frx 开头后面跟用途。3.3 第一个查询脚本简单查询并填充表格现在写第一个能跑的脚本。在画面里放一个按钮按钮的鼠标点击事件里写 VBScript。下面是一个最简版本只做一件事查询 Report_Test 表的所有数据并填进表格。 获取画面中的表格控件 Dim oFrx Set oFrx ScreenItems(FrxReportGrid) 创建 ADO 连接和记录集对象 Dim oCn Dim oRs Set oCn CreateObject(ADODB.Connection) Set oRs CreateObject(ADODB.Recordset) 连接字符串注意服务器名、库名要改成实际的 这里用 Windows 集成认证所以不需要 UID/PWD Dim sConn sConn ProviderSQLOLEDB;Data Sourcelocalhost;Initial CatalogTestDB;Integrated SecuritySSPI SQL 查询语句先只查全表验证链路 Dim sSQL sSQL SELECT ProductName, DeviceName, OutputQty, AlarmCount, RecordTime FROM dbo.Report_Test 打开连接并执行查询 oCn.Open sConn oRs.CursorLocation 3 3 adUseClient客户端游标方便统计行数 oRs.Open sSQL, oCn, 3, 1 3adOpenKeyset, 1adLockReadOnly 先把表格清空设置行列数 行数 记录集行数 固定行(表头) 1 Dim nRowCount, nColCount nColCount oRs.Fields.Count nRowCount oRs.RecordCount 2 1 行表头 1 行空余 oFrx.Rows nRowCount oFrx.Cols nColCount oFrx.FixedRows 1 写表头 Dim i For i 0 To nColCount - 1 oFrx.TextMatrix(0, i) oRs.Fields(i).Name Next 写数据 Dim r r 1 Do While Not oRs.EOF For i 0 To nColCount - 1 oFrx.TextMatrix(r, i) CStr(oRs.Fields(i).Value) Next r r 1 oRs.MoveNext Loop 清理对象 oRs.Close oCn.Close Set oRs Nothing Set oCn Nothing注意代码里有两个小地方是我故意写出来的oCn.Open 和 oRs.Open 的参数。很多网上流传的脚本版本在打开记录集时只写 SQL 和连接对象两个参数导致后续读 RecordCount 得到 -1或者光标定位出错。这里显式指定 CursorLocation、CursorType、LockType 是为了绕开这个老坑。代码写完后运行 WINCC 画面点按钮如果一切正常表格里应该出现三行测试数据。如果不正常先检查连接字符串里的 Data Source 和 Initial Catalog 是否写对再检查 SQL Server 是否允许 Windows 集成认证的远程连接。WinCC 运行时用的登录账户必须是 SQL Server 里有权访问该数据库的账户这个细节经常被漏掉——你本机调试没问题一部署到工控机上就报“无法登录”十有八九是这个问题。3.4 参数化查询怎么把画面上的输入条件传给 SQL上面的例子只解决了“查全表”但报表功能的核心是条件查询——按时间范围、按产品名、按设备名筛选。这时就要把画面上的输入框内容拼进 SQL 语句。常见的做法是用输入输出域或组合框然后在脚本里读它们的 Text 属性。下面的代码演示带时间范围的查询。这里有一个大坑WINCC 里的日期时间格式和 SQL Server 的格式不一定一致。你从输入域里拿到的是一个字符串直接拼到 SQL 里经常因为格式对不上导致查询返回空。最稳妥的做法是在脚本里把字符串先转成标准格式再用参数化方式传给 SQL。 从画面上的两个输入域取开始时间和结束时间 Dim dtStart, dtEnd dtStart ScreenItems(IOStartTime).Text dtEnd ScreenItems(IOEndTime).Text 拼 SQL注意时间条件用的是 和 而不是 BETWEEN Dim sSQL sSQL SELECT ProductName, DeviceName, OutputQty, AlarmCount, RecordTime _ FROM dbo.Report_Test _ WHERE RecordTime dtStart AND RecordTime dtEnd 这种方式虽然简单但有一个安全性隐患——SQL 注入以及一个实用性隐患——日期格式。比如你从输入域拿到的是 2024-05-20 08:00:00看起来没问题但如果你在输入域里填了 2024-05-20 8:00 这种短格式SQL 语句可能就会报转换失败。更复杂的场景是 WINCC 输入域内部对日期的处理还可能自动加上毫秒或时区信息结果查出来的数据和你预想的不一致。我的建议是如果条件只涉及日期时间就不要从输入域拿字符串而是在脚本里用 Now 或 DateAdd 函数生成标准时间然后 FormatDateTime 处理后再拼进去。如果条件涉及文本比如设备名则一定要用参数化查询。ADO 的 Command 对象支持参数化虽然 VBScript 里写起来稍微繁琐但能避免乱码和注入问题。后面避坑章节会展示一种折中方案。4. 从固定报表到灵活查询把表格控件和筛选条件联动起来4.1 设计一个实用的报表查询界面布局画面上只有一个查询按钮和一张表格用起来还是太裸。实际项目里查询界面通常长这样顶部一行条件区——开始日期、结束日期、产品下拉框、设备下拉框、查询按钮、导出按钮中部是表格区域底部是本页数据统计。WinCC 的输入输出域直接支持日期时间类型的显示和输入下拉框可以用组合框控件ComboBox或 WINCC 自带的对象。这里有几个布局细节值得注意第一不要把开始日期和结束日期放在同一行且没有分隔操作工容易点混最好中间加一个带箭头的静态文本。第二下拉框的选项不要写死在属性里建议在画面打开事件里用脚本从数据库读取一次这样以后设备列表变了不用动画面。第三表格控件默认显示的行列数都偏小一定要在画面属性或打开事件里设置好列宽——VBScript 里设置列宽是 oFrx.ColWidth(i)单位是缇Twip1 厘米约等于 567 缇。设置列宽的代码可以放在画面的“打开画面”事件OnOpen里这样每次打开报表画面表格就自动格式化好。 画面打开事件设置表格列数和列宽 Dim oFrx Set oFrx ScreenItems(FrxReportGrid) 假设要显示5列列宽依次设置 oFrx.Cols 5 oFrx.ColWidth(0) 2000 产品名称 oFrx.ColWidth(1) 2000 设备名称 oFrx.ColWidth(2) 1500 产量 oFrx.ColWidth(3) 1200 报警次数 oFrx.ColWidth(4) 3500 记录时间 表头背景色和字体可以一起设置 oFrx.FixedRows 1 oFrx.Row 0 oFrx.CellBackColor 8421504 灰色背景RGB 值转十进制关于 CellBackColor 的 RGB 值VBScript 里使用 Long 整型表示颜色公式是 R G256 B65536比如浅灰色 RGB(192,192,192) 对应 12632256。如果你直接填 VB 里那种 H00C0C0C0在 WINCC 脚本里可能会解析异常所以建议直接用十进制数。4.2 把查询脚本拆成函数让按钮事件只负责调用当查询参数变多SQL 语句变长把所有代码都塞进按钮事件里会非常难看而且排错极其痛苦。我习惯的做法是写一个独立函数 FillReportGrid(sWhere)接收一个 WHERE 条件的字符串内部完成连接、查询、填充。然后按钮事件里只负责拼条件。下面给出一个更完整的函数版本说明如何把上一章的脚本重构成可维护的结构。这里我把连接字符串做成一个函数方便统一修改数据库实例名。 全局脚本里写一个获取连接字符串的函数 Function GetSQLConnStr() 生产环境服务器名和库名集中在这里改 GetSQLConnStr ProviderSQLOLEDB;Data Source192.168.1.10;Initial CatalogFactoryDB;Integrated SecuritySSPI End Function 填充报表函数参数是拼好的 WHERE 条件不含 WHERE 关键字 Sub FillReportGrid(sWhere) Dim oFrx, oCn, oRs, sSQL, i, r, nCols Set oFrx ScreenItems(FrxReportGrid) Set oCn CreateObject(ADODB.Connection) Set oRs CreateObject(ADODB.Recordset) 基础 SQL后面按情况接 WHERE sSQL SELECT ProductName, DeviceName, OutputQty, AlarmCount, RecordTime FROM Report_Test If Len(sWhere) 0 Then sSQL sSQL WHERE sWhere End If oCn.Open GetSQLConnStr() oRs.CursorLocation 3 adUseClient oRs.Open sSQL, oCn, 3, 1 表头 nCols oRs.Fields.Count oFrx.Rows oRs.RecordCount 2 oFrx.Cols nCols oFrx.FixedRows 1 For i 0 To nCols - 1 oFrx.TextMatrix(0, i) oRs.Fields(i).Name Next 数据行 r 1 Do While Not oRs.EOF For i 0 To nCols - 1 注意日期字段要格式化后再显示 If oRs.Fields(i).Type 135 Then 135 adDBTimeStamp oFrx.TextMatrix(r, i) FormatDateTime(oRs.Fields(i).Value, 0) Else oFrx.TextMatrix(r, i) CStr(oRs.Fields(i).Value) End If Next r r 1 oRs.MoveNext Loop oRs.Close oCn.Close Set oRs Nothing Set oCn Nothing End Sub这段代码里有一个细节值得重点说oRs.Fields(i).Type 135 是 ADODB 里的时间戳类型。如果你直接把 datetime 字段的 Value 赋给 TextMatrix显示出来的可能是类似 2024-05-20 08:00:00 的原始值但有些环境下 SQL Server 返回的是带有小数秒的格式还有时区转换问题。通过 FormatDateTime 格式化后显示就稳定了。重构后按钮事件里只需要这么做 查询按钮点击事件 Dim sWhere sWhere 如果开始时间不为空就附加条件 If Len(ScreenItems(IOStartTime).Text) 0 Then sWhere sWhere RecordTime ScreenItems(IOStartTime).Text End If 如果结束时间不为空继续附加条件 If Len(ScreenItems(IOEndTime).Text) 0 Then If Len(sWhere) 0 Then sWhere sWhere AND sWhere sWhere RecordTime ScreenItems(IOEndTime).Text End If 调用填充函数 FillReportGrid sWhere看起来清爽很多。但注意上面拼接 WHERE 的代码仍然没有处理 SQL 注入和格式问题。如果现场操作员水平参差不齐输入的日期格式五花八门查询就会经常翻车。下一章专门说这些坑。4.3 下拉框选项从数据库动态加载前面提到下拉框不要写死。用组合框控件在画面打开事件里查一次设备表把设备名逐条 AddItem 进去。这样的好处是设备增减后报表界面不用改。 画面打开事件加载设备下拉框 Dim oCmb, oCn, oRs, sSQL Set oCmb ScreenItems(CmbDevice) Set oCn CreateObject(ADODB.Connection) Set oRs CreateObject(ADODB.Recordset) oCn.Open GetSQLConnStr() sSQL SELECT DISTINCT DeviceName FROM Report_Test ORDER BY DeviceName oRs.Open sSQL, oCn, 3, 1 oCmb.Clear Do While Not oRs.EOF oCmb.AddItem oRs.Fields(0).Value oRs.MoveNext Loop oRs.Close oCn.Close Set oRs Nothing Set oCn Nothing值得注意的是组合框的 AddItem 方法在 WINCC 的控件里第一个选项默认索引是 0如果你之后要用 ListIndex 属性作为条件值注意别读错。5. WINCC 做 SQL 报表查询的避坑指南五个我翻过车的细节5.1 连接字符串的 Provider 版本不对导致查不到归档表现象 脚本在开发环境跑得好好的部署到现场工控机上查询 HISTORIAN 数据时返回空记录集但直接连业务表又没问题。 原因 现场机器的 SQL Server 2008 或 2012 环境不支持你开发机上用的 SQLOLEDB 老驱动或者 ODBC 数据源指向了错误的实例名。我遇到过一次开发机用的 ProviderSQLOLEDB而现场是 SQL Server 2014 的默认实例改成命名实例Data Source 里只写了机器名导致找不到实例。 解决 在 GetSQLConnStr 里显式写清实例名比如 Data Source192.168.1.10\SQLEXPRESS或者干脆用逗号写端口例如 Data Source192.168.1.10,1433。另外如果现场没有 OLEDB 驱动改用 ProviderSQLNCLI11 或 MSOLEDBSQL但在老 Windows 上注意驱动是否真的注册了。5.2 中文乱码SQL 语句里带中文条件查不到数据现象 按下查询按钮表格是空的但把所有条件去掉却能看到中文数据。把条件里的设备名在 SQL Server Management Studio 里手动执行没问题在 WINCC 里查就空。 原因 这是最典型的字符集冲突。VBScript 字符串是 Unicode拼接成 SQL 后传给 OLEDB 驱动时默认代码页可能不是中文代码页导致 SQL 里的中文字面量在 SQL Server 端和表里的 NVARCHAR 不匹配。 解决 两个办法一起上。第一把字段类型和 SQL 里的字符串常量都加上 N 前缀比如 sSQL sSQL WHERE DeviceName N strDevice 。第二在 ADODB.Connection 对象的连接字符串里加 Character Set 参数或者最简单的方式是用参数化查询。我用参数化解决了这个坑代码会稍微长一点但再没出现过乱码。5.3 表格行数不刷新上一次查询数据多下一次查询数据少现象 第一次查询返回 100 行表格显示 100 行第二次查询条件更严格只返回 5 行但表格底部还留着原来 95 行的旧数据看起来像没查对。 原因 MSFlexGrid 的 Rows 属性一旦被设置成 100如果 RecordCount 2 小于 100控件不会自动删掉多余行。我只在第一次填表时设置了 Rows后面没有在每次填充前重新设置。 解决 在 FillReportGrid 函数开头就要无条件设置 Rows 和 Cols并且先全部清空。最彻底的方法是 oFrx.Clear。然后重置行列数这样能保证控件完全重画。5.4 运行时提示 ActiveX 控件未注册现象 WINCC 开发环境里按住 Ctrl 键运行时画面正常一旦发布到另一台操作员站上画面里的表格控件显示成一个红叉脚本按钮点了没反应。 原因 这台操作员站上没注册 MSFlexGrid 这个 ActiveX 控件或者 WINCC 安装时没有勾选“ActiveX 控件”组件。注意WinCC 运行版装完后MSFlexGrid 默认不一定被注册。 解决 在操作员站上以管理员身份命令行运行 regsvr32 MSFLXGRD.OCX或者更省事的方式是重新安装 WINCC/补充安装选件时把 ActiveX 支持勾上。还有开发机和运行机的 WINCC 版本必须一致否则即使注册了版本不同也可能出现兼容性错误。5.5 WINCC 脚本里执行耗时 SQL 卡死画面现象 数据量一大按下查询按钮整个画面卡住十几秒鼠标转圈操作工以为死机了反复点按钮最后结果出来前界面早已失去响应。 原因 VBScript 是单线程的脚本执行期间 WINCC 的画面刷新被阻塞。查询一个几十万行的归档表尤其还带排序和聚合耗时自然很长。 解决 给 SQL 加上限制返回行数和索引优化。常用手段是 SELECT TOP 1000或者在业务表上按 RecordTime 建索引。如果产品要求大量数据就把查询拆成“先查汇总”和“点明细再查”两步。实在要在运行时优化体验可以在脚本开头设置 ScreenItems(FrxReportGrid).Redraw False填充完再设 True同时用 Screen 的修改消息提升响应。但说实话报表查询十几秒的大查询最好的办法就是限制范围。这五个坑解决了报表功能基本就能稳定运行了。但如果你想让它更贴近日常使用还有两个小进阶可以做——导出 Excel 和加一个查询进度提示。6. 把报表做得更好用导出 Excel 和查询性能的实战技巧画面里的表格只能在屏幕上看着领导往往要 Excel 文件。在 VBScript 里导出 Excel 有几种办法其中一种是用 Excel.Application 对象那需要现场装了 Office另一种是把表格内容直接写成 CSV 文件然后用户用 Excel 打开。工业现场很多时候操作员站上压根没装 Office所以 CSV 方式反而是最通用的。下面是一个把表格内容存成 CSV 文件的子过程。这样导出的文件既可以用记事本打开也可以用 Excel 双击打开不会因为 Office 版本问题报错。 导出表格到 CSV 文件 Sub ExportGridToCSV(sFilePath) Dim oFrx Dim i, r Dim sLine Set oFrx ScreenItems(FrxReportGrid) 用 FileSystemObject 创建文件 Dim fso, f Set fso CreateObject(Scripting.FileSystemObject) Set f fso.CreateTextFile(sFilePath, True) 遍历表格所有行每行拼接成 CSV 格式 For r 0 To oFrx.Rows - 1 sLine For i 0 To oFrx.Cols - 1 转义如果内容里有逗号需要用引号包起来 Dim sCell sCell oFrx.TextMatrix(r, i) If InStr(sCell, ,) 0 Or InStr(sCell, ) 0 Then sCell Replace(sCell, , ) End If sLine sLine sCell If i oFrx.Cols - 1 Then sLine sLine , End If Next f.WriteLine sLine Next f.Close Set f Nothing Set fso Nothing End Sub这段代码有三个值得注意的点第一CSV 的换行符默认是 CRLF第二如果单元格内容里有英文逗号必须用双引号包裹否则 Excel 打开会错列第三WinCC 运行时脚本的文件操作权限要够建议导出到 C 盘的某个固定目录避免写到受保护的文件夹时失败。调用方式如下 导出按钮事件生成带时间戳的文件名 Dim sFile sFile C:\ReportExport\Output_ FormatDateTime(Now, 0) .csv 注意文件名里不能有冒号需要替换 sFile Replace(sFile, :, ) sFile Replace(sFile, /, ) ExportGridToCSV sFile MsgBox 导出完成 sFile这里有一个细节FormatDateTime(Now, 0) 返回的日期时间字符串里带斜杠和冒号这些字符在 Windows 文件名里是非法的所以必须先 Replace 掉。这也是一个常见的导出坑我最初写的时候直接生成文件名结果 fso.CreateTextFile 报“路径中文件名非法”。另一个实用技巧是给耗时查询加一个简单的进度提示不过 VBScript 里没有多线程能力所以只能退而求其次在查询开始前用静态文本显示“正在查询请稍候……”查询结束后改成“共返回 N 条记录”。虽然不能实时刷新但至少能拦住 90% 的重复点击。 查询按钮事件改造 ScreenItems(TxtStatus).Text 正在查询请稍候... FillReportGrid sWhere Dim nRowCount nRowCount ScreenItems(FrxReportGrid).Rows - ScreenItems(FrxReportGrid).FixedRows - 1 ScreenItems(TxtStatus).Text 查询完成共 CStr(nRowCount) 条记录关于性能优化我最后补充一点如果数据表已经很大比如几十万行无论怎么优化脚本查询都会慢。更合理的做法是在 SQL 层做聚合例如把产量按小时汇总后在表格里只显示汇总结果。明细数据留给单独的“查明细”按钮。这样报表界面操作流畅领导要的数字也能快速看到。这套方案我在多个项目里都落地过从最初踩中文乱码的坑到后来把 CSV 导出和参数化查询收拾利索大概花了两天时间打磨。现在每当现场要“再加一个报表”我只需要新建一个画面、复制脚本、改一下 SQL 和字段映射就行半小时交活。有些细节如果你照着本文一次跑通自然明白哪些步骤可以省如果中途报错回看避坑那一章基本都能找到答案。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

KServe V1beta1RolloutSpec 深度解析:用 maxSurge 与 maxUnavailable 掌控模型服务的滚动发布

KServe V1beta1RolloutSpec 深度解析:用 maxSurge 与 maxUnavailable 掌控模型服务的滚动发布

模型推理服务云原生后端微服务MLOps人工智能 【免费下载链接】kserve Standardized Distributed Generative and Predictive AI Inference Platform for Scalable, Multi-Framework Deployment on Kubernetes 项目地址: https://gitcode.com/gh_mirrors/ks/kserve 点…

📅 2026/10/11 19:42:00
上海大学答辩PPT模板使用指南:母版、占位符与排版技巧

上海大学答辩PPT模板使用指南:母版、占位符与排版技巧

简介:上海大学答辩通用演示文稿模板,面向本校学生在毕业答辩、学术汇报、开题答辩及周会汇报等场合。模板内置标题页、目录页与多种内容页样式,支持文字输入、图表展示、列表和引用排版,可通过母版视图调整各级文本样式&#xff0…

📅 2026/10/11 19:37:00
剧场订票系统核心设计:座位锁定、事务一致性与并发压测实践

剧场订票系统核心设计:座位锁定、事务一致性与并发压测实践

简介:面向C#与MySQL学习者的剧场订票管理系统完整工程,适合计算机相关专业课程设计、毕业设计或数据库应用开发入门参考。系统围绕剧场售票场景,覆盖电话订票、今明后三日内座位预约、以彩色图形展示已订座位、观众资料修改、撤销与改订及报表…

📅 2026/10/11 19:37:00
MORE NEWS

更多资讯

📰

Agent技能工程:可验证、可监控、可复用的智能体能力单元设计

1. “agent-skills”不是新词,而是智能体能力工程的实践切口“agent-skills”这个词乍看像某个开源库的包名,或是某次技术分享里一闪而过的术语缩写。但过去两年在多个跨领域项目中反复遇到它——不是作为概念被宣讲,而是作为实际开发中必须拆…

📰

模塑玻璃瓶缺陷识别数据集:28类缺陷与YOLOv5实战

简介:这份资源是面向工业质检与计算机视觉方向的模塑玻璃瓶缺陷识别数据集,适合从事缺陷检测算法研发、YOLO模型训练及产线视觉方案验证的工程师与学习者使用。数据集覆盖黑点、泡泡颈、破损、刮痕、裂缝等28类常见玻璃瓶缺陷,标注信息完整&a…

📰

误差椭圆详解:从协方差阵到点位精度分析

1. 为什么笔记十二要单独写误差椭圆误差理论与测量平差基础这门课,大家最熟悉的肯定是协方差传播、权、条件平差、间接平差这些大块头。等这些基础过了之后,随之而来的一个非常实际的问题就是:平差算出的坐标点,到底有多可靠&…

📰

MySQL查询结果加序号全解析:从ROW_NUMBER到用户变量与分组排名

说实话,数据库开发里最容易被低估的需求,就是“给查询结果加个序号”。听起来不就是一列 1、2、3、4 吗?可真到动手写的时候,版本差异、排序稳定性、分页跳号、分组重排,随便一个细节都能让你在测试环境折腾半天。我这…

📰

森林害虫目标检测数据集实战:YOLOv8训练与避坑指南

简介:这份森林害虫目标检测数据集面向林业智能监测、农业AI应用开发及生态科研人员,聚焦松毛虫、松墨天牛、卷叶蛾三类常见且危害严重的森林害虫识别难题。数据集共1715张实际场景采集的JPEG图片,按训练集1199张、验证集257张、测试集259张划…

📰

时间序列研究全景解析:从基础模型到流匹配与VLM的实战指南

1. 时间序列研究的版图变迁与选题逻辑时间序列这个方向,这几年在顶会上的存在感肉眼可见地变强了。早些年做时序的人多少有点“边缘感”,投稿时经常被分到偏应用的track,审稿人一句“novelty不够”就能把工作打回去。但这两年情况完全反过来了…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

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

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

📞 💬