技术论坛

 回复:技术专题探讨-WinCC实现报表的不同方法及其应用

返回主题列表
作者 主题
万泉河
至圣

经验值:29190
发帖数:10900
精华帖:131
楼主    2009-02-23 09:43:28
主题:技术专题探讨-WinCC实现报表的不同方法及其应用【已结束】
在工业生产中,一项非常重要的工作:抄表。在手动年代,需要人工记录、统计并出报表。进入自动控制的年代,升级成为计算机控制的自动报表,既减轻劳动强度,又减少出错几率。

而这项工作也就当仁不让地摆在工控工作者面前,因而也就成就了论坛上经久不息的热点话题:WINCC报表!

经过长时间的准备工作,我们现对此话题集中展开一次大型的专题讨论活动,持续至3月18日 。把各行各业中用到的,形形色色的不同形式的报表在WINCC项目中的应用力求讨论清楚。针对不同的行业报表,可以有不同的解决方案,最终形成不同的设计结果。

这次活动,我们成功争取到SIEMENS官方技术支持工程部门的鼎力支持,承诺将会有数名专业的WINCC系统工程师全程参与到话题的讨论过程中来。并对讨论过程中出现的共性技术难题设法给出解决方案,对一些得到的共识进行总结,形成结论。除此之外,我们也事先沟通、联系了论坛内外众多WINCC高手以及编程高手、热心网友,到期都会积极参与到这个活动中来。

作为专题讨论的第一步,是收集各行各业的报表需求,然后进行整理和分类汇总,以便于后期有针对性的进行技术方案的讨论。

所以前期,请大家踊跃发言,提供您所处行业所需的报表模板,可以是您见过、做过的各种自动报表的结果,也可以是尚未能够实现的在目标格式,甚至可以是旧手工抄表的表格。模板格式可以是通用图形文件,EXCEL文件、PDF文件等等。通过传附件形式传到本帖。未具备传附件积分资格的,请事先联系我们,可以为您申请临时的上传附件资格。针对表格不同复杂程度,可以配加适当的文本描述,以便于别人理解。
管理员注:本帖已被纳入此次探讨发帖整理之需求总结,请点此详阅
微信公众号:PLC标准化编程,ZHO6371995
凌波微步
奇侠

经验值:8842
发帖数:2715
精华帖:72
    2009-02-23 15:00:08
精华帖  主题:回复:技术专题探讨-WinCC实现报表的不同方法及其应用
我先上传一个报表吧!考虑到WINCC中实现此报表难度较大,通过是其他工程师利用VB程序编制而成的!
点击此处查看附件

这个报表的数据采集没有难度;唯一的难度在于4班3倒后,每个月班的出勤日是不一样的,这样对于月报来说,计算出本月每个班的出勤日是需要些算法的。



管理员注:本帖已被纳入此次探讨发帖整理之需求总结,请点此详阅
不以物喜,不以己悲; 达则兼济天下,穷则独善其身。
WinCC训练营讲师
游侠

经验值:344
发帖数:35
精华帖:1
    2009-02-26 09:53:03
精华帖  主题:回复:技术专题探讨-WinCC实现报表的不同方法及其应用
数据采集和存储是出报表的前提和基础。
格式化输出是最终的显示问题。
我们常常遇到的问题是,如何把数据完美的表现在表格上。
容易把需求放在表格设计的灵活性上,而忽视了数据的存储问题。

其实在出报表之前,有很多的环节可以对数据进行统计分析和汇总。
比如说,在采集时确定好累计还是平均,然后设计数据的存储和归档模式。

另用数据库和SQL语句的强大功能,可以提前实现数据的汇总分析。毕竟wincc继承了强大的数据库功能。

那么最终在把数据展现在报表上就会方便一些。
当然报表的格式限制了我们可能采用的方式。
对于有固定结构的行式报表,实现方式比较多。直接连接数据库查询,
或者WinCC自带的在线表格控件个人认为都可以实现的。关键就是边角的美观问题。
对于复杂的表格样式,其实无非就是数据填充问题,
关键是我们在什么地方对数据进行分析更合理更方便!

管理员注:本帖已被纳入此次探讨发帖整理之理论探讨,请点此详阅
n次看你的背影
奇侠

经验值:7974
发帖数:2321
精华帖:73
    2009-03-03 01:11:59
精华帖  主题:回复:技术专题探讨-WinCC实现报表的不同方法及其应用
呵呵,看到各位大侠对报表做了很多方面的深刻讨论,也让我学习了很多。不过本人功底差,对数据库基本不懂。确实用数据库存储数据是比较安全的,但通过数据库来查询得出的“报表”,应该称之为查询结果吧。失去了报表本身的意义了。
较长一段时间,我也在思考和寻找WinCC里面做复杂报表的方法。WinCC自带的报表编辑器确实功能有限,还好WinCC本身功能是强大的,可以通过脚本来完成复杂报表功能。目前我也是这么做的。
我个人认为,在WinCC里面做复杂报表,并不急于去组态和编程;而是先弄清楚原始手工报表的制作过程。报表也就是时间和各类数据的交集的一张表格,手工报表就是通过人工将数据填入相应的格子里面,手工报表就是这么朴素。不过手工报表有n张相同的纸,拿在手上就好像一本书,或者像一块大砖头。呵呵!
目前我报表的思路如下:
1、用excel我们也做一个符合自己实际需要报表(日报)的空白模板,我称它为Day_Report.xls;相信各位大侠的excel表格都比我做的精美;我不懂关系数据库,但各位大侠肯定比我精通excel各单元格之间的加、减、乘、除,甚至更加复杂的运算,并把运算结果放在你需要放置的单元格内,关系数据之间的运算,要在excel模板里面预先设置好。我们要充分利用excel强大的数据处理能力!!!
2、在WinCC里面写一个全局脚本,在每天的00:00:01触发,执行复制Day_Report.xls并以此刻的年月日加载到模板文件名里面,将复制新生产的“Day_Report年月日.xls”存盘到你指定的目录。这样当天的空白日报文件也就有了。全局脚本代码如下:(本人测试通过,仅供参考)

#include "apdefap.h"

int gscAction( void )
{
#pragma code ("kernel32.dll")//调用动态链接库
VOID GetLocalTime(LPSYSTEMTIME lpSystemTime);
#pragma code ()
#pragma code("Shell32.dll")//调用动态链接库
VOID ShellExecuteA(HWND, LPCTSTR , LPCTSTR , LPCTSTR , LPCTSTR , INT);
#pragma code()
char FileName[30] = ""; char DateTime[30] = "";
SYSTEMTIME sysTime;
__object* pExcel = NULL; //建立 pExcel 指针 用来对 EXCEL 进行操作
HWND handle=NULL;
handle=FindWindow(NULL,"WinCC-运行系统 - ");
GetLocalTime(&sysTime);
sprintf(FileName,"d:\\Day_Report_%02d-%02d-%02d.xls",sysTime.wYear,sysTime.wMonth,sysTime.wDay);

pExcel = __object_create("Excel.Application");
pExcel->Visible = 0;//控制生成的excel文件是否可见,当1时,生成excel文件时可见.
pExcel->Workbooks ->Open ("d:\\Day_Report.XLS");

pExcel->ActiveWorkbook->SaveAs(FileName);//存盘
//pExcel->ActiveWorkbook->PrintPreview();//可以预览
//pExcel->ActiveWorkbook->PrintOut();//直接打印
pExcel->Workbooks->Close();//关闭文件
pExcel->Quit();//退出Excel
__object_delete(pExcel);

return 0;
}

3、再写一个全局脚本,整点触发,把你需要记录的变量写到“Day_Report年月日.xls”相应的单元格里面并存盘;这样就完成了报表的数据存储和打印。也就是说,我们可以在电脑里面存放一份报表,并打印一份报表。同样也实现了数据的存储。
相关脚本代码如下:(当时是以分钟来做测试的,仅供参考;注意此段代码缺少对其它excel进程的判断,在此脚本执行前,不要有其它excel应用!切记哦!!!呵呵。)
#include "apdefap.h"

int gscAction( void )
{
int i;
#pragma code ("kernel32.dll")//调用动态链接库
VOID GetLocalTime(LPSYSTEMTIME lpSystemTime);
#pragma code ()
#pragma code("Shell32.dll")//调用动态链接库
VOID ShellExecuteA(HWND, LPCTSTR , LPCTSTR , LPCTSTR , LPCTSTR , INT);
#pragma code()
char FileName[30] = "";
SYSTEMTIME sysTime;
__object* pExcel = NULL; //建立 pExcel 指针 用来对 EXCEL 进行操作
HWND handle=NULL;
handle=FindWindow(NULL,"WinCC-运行系统 - ");
GetLocalTime(&sysTime);
//***********************************
SetTagWord("Minute",sysTime.wMinute);
i=GetTagWord("Minute")+3;
if (i>26) { GetTagWord("Minute") ;}
else if (i<=26)
{
sprintf(FileName,"d:\\Day_Report_%02d-%02d-%02d.xls",sysTime.wYear,sysTime.wMonth,sysTime.wDay);
pExcel = __object_create("Excel.Application");
pExcel->Visible = 0;//控制生成的excel文件是否可见,当1时,生成excel文件时可见.
pExcel->Workbooks ->Open (FileName);
pExcel->Worksheets("sheet1")->Range("X1")->Value=GetTagChar("@ServerName");//Return-Type: char* 读取当前计算机名
pExcel->Worksheets("sheet1")->Range("X2")->Value=GetTagChar("@CurrentUser");//Return-Type: char* 读取当前操作员
pExcel->Worksheets("sheet1")->Cells(6,i)->Value=GetTagChar("TAG1");
pExcel->Worksheets("sheet1")->Cells(7,i)->Value=GetTagFloat("TAG2");
pExcel->Worksheets("sheet1")->Cells(8,i)->Value=GetTagFloat("TAG3");
pExcel->Worksheets("sheet1")->Cells(9,i)->Value=GetTagFloat("TAG4");
pExcel->Worksheets("sheet1")->Cells(10, i)->Value=GetTagFloat("TAG5");
pExcel->Worksheets("sheet1")->Cells(11, i)->Value=GetTagFloat("TAG6");
pExcel->ActiveWorkbook->Save;//As(FileName);//存盘~
//pExcel->ActiveWorkbook->PrintPreview();//可以预览
//if (i>=27) { pExcel->ActiveWorkbook->PrintOut(); }//直接打印
pExcel->Workbooks->Close();//关闭文件
pExcel->Quit();//退出Excel
__object_delete(pExcel);
}

return 0;
}

日报有了,班报、月报,应该也就没有问题了吧!希望大家有什么好东东也一起拿出来分享一下,个人的智慧是有限的,大家的力量是无穷的。不要吝啬,多交流才有进步!

阿弥陀佛!我希望我能给那些热爱工控的人们一点点帮助!!
管理员注:本帖已被纳入此次探讨发帖整理之方案汇总,请点此详阅
佛对我说:“你的痛苦来自于你的欲望,没有欲望也就没有痛苦!”
天涯宿命
游民

经验值:139
发帖数:6
精华帖:2
    2009-03-04 22:30:56
精华帖  主题:回复:技术专题探讨-WinCC实现报表的不同方法及其应用
我是这样做的,通过VBS把WINCC实时数据些到我建立好的SQL数据库中,然后在WINCC界面上做一个查询按钮,按你所要的日期或时间从数据库中读出相应数据。下面,我把查询的部分代码贴出。
Sub OnLButtonDown(ByVal Item, ByVal Flags, ByVal x, ByVal y)
Dim strDate,strTime
Dim strcn,cn
Dim rs
Dim strSQL
Dim comm
Dim i
‘建立数据库连接
strcn="Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=DBNAEM;Data Source=dbserver\wincc"
Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
Set comm=CreateObject("ADODB.Command")
cn.ConnectionString=strcn
cn.cursorlocation=3
cn.Open
comm.commandtype=1
comm.activeconnection=cn
'**********************************************************
'**********************************************************
Dim StrYear
Set StrYear = HMIRuntime.Tags("StrYear")
stryear.Read
Dim StrMonth
Set StrMonth = HMIRuntime.Tags("StrMonth")
strmonth.Read
Dim StrDay
Set StrDay = HMIRuntime.Tags("StrDay")
strday.Read

strDate=stryear.Value +"-"+strmonth.Value+"-"+strday.Value

Dim StrHour
Set StrHour = HMIRuntime.Tags("StrHour")
StrHour.Read
Dim StrMinute
Set StrMinute = HMIRuntime.Tags("StrMinute")
StrMinute.Read

strTime=StrHour.Value+":"+StrMinute.Value
'*************************************************************
建立EXCEL对象
Dim objexcelApp
Set objexcelApp=CreateObject("excel.application")
With objexcelApp
.visible=True
.workbooks.open"d:\SPSQLServer_2008\ExcelReport\SOURCE.xls"打开EXCEL模板
.activeworkbook.activesheet.select
.displayalerts=False
End With
'****************************************************************
查询数据库中相应数据,然后写到相应的EXCEL单元格中。
i=4 表示第四行
strSQL="select * from Station_1 where St1_Date='"&strDate&"'and St1_Time='"&StrTime&"'"
comm.commandtext=strSQL
Set rs=comm.execute
If Not rs.eof Then
With objexcelApp.worksheets(1)
objexcelApp.Worksheets(1).cells(i,3).value=rs.fields(0).value
objexcelApp.Worksheets(1).cells(i,4).value=rs.fields(1).value
objexcelApp.Worksheets(1).cells(i,5).value=rs.fields(2).value
objexcelApp.Worksheets(1).cells(i,6).value=rs.fields(3).value
objexcelApp.Worksheets(1).cells(i,7).value=rs.fields(4).value
objexcelApp.Worksheets(1).cells(i,8).value=rs.fields(5).value
objexcelApp.Worksheets(1).cells(i,9).value=rs.fields(6).value
objexcelApp.Worksheets(1).cells(i,10).value=rs.fields(7).value
objexcelApp.Worksheets(1).cells(i,11).value=rs.fields(8).value
objexcelApp.Worksheets(1).cells(i,12).value=rs.fields(9).value
objexcelApp.Worksheets(1).cells(i,13).value=rs.fields(10).value
objexcelApp.Worksheets(1).cells(i,14).value=rs.fields(11).value
objexcelApp.Worksheets(1).cells(i,15).value=rs.fields(12).value
objexcelApp.Worksheets(1).cells(i,16).value=rs.fields(13).value
objexcelApp.Worksheets(1).cells(i,17).value=rs.fields(14).value
objexcelApp.Worksheets(1).cells(i,18).value=rs.fields(15).value
objexcelApp.Worksheets(1).cells(i,19).value=rs.fields(16).value
objexcelApp.Worksheets(1).cells(i,20).value=rs.fields(17).value
objexcelApp.Worksheets(1).cells(i,21).value=rs.fields(26).value
objexcelApp.Worksheets(1).cells(i,22).value=rs.fields(20).value
objexcelApp.Worksheets(1).cells(i,23).value=rs.fields(21).value
objexcelApp.Worksheets(1).cells(i,24).value=rs.fields(22).value
objexcelApp.Worksheets(1).cells(i,25).value=rs.fields(23).value
objexcelApp.Worksheets(1).cells(i,26).value=rs.fields(25).value
End With
End if
i=5
。。。。。。。。。。
。。。。。。。。。。
i=N
rs.close
cn.close
Set rs=Nothing
Set comm=Nothing
Set cn=Nothing
Set objexcelApp=Nothing
End Sub

管理员注:本帖已被纳入此次探讨发帖整理之方案汇总,请点此详阅
失去的是记忆,留下的依然是记忆
天涯宿命
游民

经验值:139
发帖数:6
精华帖:2
    2009-03-05 22:31:08
精华帖  主题:回复:技术专题探讨-WinCC实现报表的不同方法及其应用
quote:以下是引用万泉河在2009-03-05 10:29:05的发言:
你的思路非常清晰,就是说实时数据先进入了数据库,在需要的时候再通过查询、整理送到excel,和前面的很多帖子不同。虽然同样都是EXCEL的应用。

显然,你在数据库里的数据结构和excel里的数据结构不同,但我看主要是次序的不同。
否则的话,我想可以直接使用DAT@MONITOE来实现。另外也可以用工业数据桥实现。
仅供你参考,扩展思路。

另外数据写入数据库部分的详细过程和代码能不能再交待一下?我认为那里也同样有一些可以探讨的地方。


你说的工业数据桥,其实是很好的工具,唯一遗憾的是不是免费使用的。呵呵,下面把写入数据库的代码贴出来,供大家参考,不足之处请指教。
代码行很宽,会影响论坛页面显示,特拷贝到记事本中,
请下载查看(由于上传格式限制,需要解压)。点击此处查看附件
以上是根据实际工程需要才这么做的,因为工程的实际情况和客户的要求注定了有时候报表的形式不是唯一的,或局限在一个范围呢,因为客户会根据自己想的要求你来做。这个工程现场控制器在一期的项目里就达到二十多,并且各个地方是分散在一个城市里的,客户要求所有的站要根据某一时刻的查询显示在一张EXCEL表里,这样的要求最终促成了,以上的解决办法。
管理员注:本帖已被纳入此次探讨发帖整理之方案汇总,请点此详阅
失去的是记忆,留下的依然是记忆
四书五经
侠圣

经验值:3667
发帖数:762
精华帖:58
    2009-03-05 22:50:46
精华帖  主题:回复:技术专题探讨-WinCC实现报表的不同方法及其应用
针对凌波微步大侠的报表格式,我也做了一下实验,首先是数据存储,定义表格结构如下:

字段解释如下:
ID:自动编号字段,每增加一条记录自动加1;
OP:当前操作员(即当前班次)
DT:采样的时间//此字段设置索引,对查询速度有很大的提高,特别是数据记录很多的时候。
P1:1号压力值
...
P3:3号压力值
T1:1号温度值
...
T3:3号温度值

在全局动作中写入如下代码:
Function action
Dim objConnection
Dim strConnectionString
Dim P1101VALUE,P1102VALUE,P1103VALUE,T1101VALUE,T1102VALUE,T1103VALUE
Dim strSQL
Dim objCommand
Dim DsnStr
Dim dt
Dim UserName
DsnStr=HMIRuntime.Tags("@DatasourceNameRT").Read '取当前的DSN值

strConnectionString = "Provider=MSDASQL;DSN="&DsnStr&";UID=;PWD=;"
HMIRuntime.Trace strConnectionString

dt=Now()

P1101Value = HMIRuntime.Tags("P1101_PV").Read
P1102Value = HMIRuntime.Tags("P1102_PV").Read
P1103Value = HMIRuntime.Tags("P1103_PV").Read
T1101Value = HMIRuntime.Tags("T1101_PV").Read
T1102Value = HMIRuntime.Tags("T1102_PV").Read
T1103Value = HMIRuntime.Tags("T1103_PV").Read
UserName = HMIRuntime.Tags("@CurrentUserName").Read '取当前操作员

HMIRuntime.Trace p1101value
strSQL = "INSERT INTO WINCC_DATA (OP,DT,P1,P2,P3,T1,T2,T3) VALUES ("
strsql=strsql+"'"& UserName &"'"
strsql=strsql+",'"&dt&"'"
strSql=StrSql+","& P1101Value &""
strSql=StrSql+"," & P1102Value &""
strsql=strsql+","& P1103Value &""
strsql=strsql+","& T1101Value &""
strsql=strsql+","& T1102Value &""
strsql=strsql+","& T1103Value &")"
Set objConnection = CreateObject("ADODB.Connection")
objConnection.ConnectionString = strConnectionString
objConnection.Open
Set objCommand = CreateObject("ADODB.Command")
HMIRuntime.Trace "Ok"
HMIRuntime.Trace strsql
objCommand.ActiveConnection = objConnection
objCommand.CommandText = strSQL
HMIRuntime.Trace "Ok1"
objCommand.Execute
Set objCommand = Nothing
objConnection.Close
Set objConnection = Nothing

End Function
设置每30秒触发一次。把数据写入数据库中。接下来是如何实现报表的格式,采用EXECL不是一个好方法,因为对于求平均值和最大值/最小值来说,要先把数据写入EXECL中,然后才能再EXECL中做统计计算。在这里我们使用SQL语句的强大的数据统计功能,在WINCC的报表编辑器中有一个动态对象:ODBC数据库域。这个对象是WINCC5.1所没有的。这个对象中可以使用标准SQL语句。

如上图所示,select avg(p1) from wincc_data where op='甲' and dt>='2009-03-01' and dt<'2009-04-01'---是一个求甲班3月份一号压力平均值的语句。 这个动态控件可以把这个语句的执行结果直接显示出来,而且从图中也可以看出,通过下方的变量功能可以使用一个WINCC的字符串类型的变量动态化SQL语句,这样稍微写一些代码结合界面选择就可以实现不同月份的查询。
另 select max(p1) from wincc_data where op='甲' and dt>='2009-03-01' and dt<'2009-04-01'是求甲班3月份一号压力的最大值,Min是求最小值。在报表编辑器的多放一些这样的控件,再把这些控件排列成表格的形式就可以了。
在这里需要注意的是每个控件都执行一次SQL语句,都要连接一下数据库,如果有100个这样的控件,就需要执行100次查询,当然100次查询对于本地SQL数据库来说是一点问题都没有的。如果数据表中数据记录很多,查询次数也很多的话,可能预览的时候会有一定的查询等待时间。呵呵,我们以前在网络SQL数据库上,数据表中有几万条记录,循环执行几百次的查询,执行起来有明显的等待,不过后来用存储过程来做就好多了。
以上写数据库的代码,我调试过了是正确的。select 语句也是没问题的,求平均值,最大/最小值也是对的。但我只是在报表编辑器中做了两行记录。共12个查询,而且只以3月份为例。呵呵,速度很快。


管理员注:本帖已被纳入此次探讨发帖整理之方案汇总,请点此详阅
虚心+学习
游侠

经验值:499
发帖数:110
精华帖:6
    2009-03-09 16:23:37
精华帖  主题:回复:技术专题探讨-WinCC实现报表的不同方法及其应用
我来谈一下我的报表,wincc从5.0一直用到今天,做了不下10几个项目,尝试了很多报表的做法,如VB前台画面、水晶报表、网页报表、wincc自带报表、EXCEL报表等,数据库从开始的ACCESS、SQL server自定义数据库、最终将报表定型在EXCEL+在用户归档,为什么要这么做,主要是为了考虑这样做花的精力少,省时省力,用户归档的数据可以冗余,而且让公司代码水平不高的年轻人可以很快上手。首先是整点数据的采集存储,我是采用用户归档,在用户归档里建张存储实时数据的表,变量的存储按照串行的方式存储,另外再建张表,用来保存需要归档的变量的信息:归档名、显示在表头的中文名、单位,小数点位数等信息。存储数据的过程是先将需要存储的变量名读出,再一个变量一条保存到数据库里。这样的好处就是,代码写好后不再需要改动,其他工程师到现场只有将需要的归档变量填在“归档变量名”表里就行了。
报表输出采用填EXCEL单元格的方式,这样好处是充分利用EXCEL的强大统计计算功能,如日报里的班累计、合计、平均等实现起来非常简单。
下面是我最近帮一个朋友做的印度烧结的报表,供大家斧正:
在用户归档中加入如下2个表:
创建2个归档,归档类型:无限制;通讯:无;控制变量:无;标记:上一次修改。
gdblm:别名:归档变量名
字段名 数据类型 长度 别名
BLWB 字符串 30 变量文本
DW 字符串 10 单位
Tag_name 字符串 30 变量名

ZDGD:整点归档
字段名 数据类型 长度 别名
BM 字符串 30 别名
RQ 日期/时间 日期
SJ 日期/时间 时间
Tag_name 字符串 30 变量名
ZHI 数(浮点) 值

WINCC动作,触发器按每小时的00:00触发。
Option Explicit
Function action

Dim gzd,RM_MASTER,tagstr,tag_name,table_name
Dim tag_N,tag_T,tag_U,i,tag_W
Dim Atag_N,Atag_T,Atag_U,max,Atag_W,idd,sql1,db_time

' On Error Resume Next
RM_MASTER=GetTag("@RM_MASTER")
'RM_MASTER=1
'If RM_MASTER=1 Then
table_name="UA#ZDGD"
db_open
sql="SELECT * FROM " & table_name & " ORDER BY ID DESC"
Set rs = CreateObject("ADODB.Recordset")
rs.Open sql, conn, 1, 1
If Not rs.eof And Not rs.bof Then
idd=rs(0)
db_time=rs("SJ")
Else
idd=0
db_time="00:00"
End If
If Hour(db_time)<>Hour(Now()) Then


sql="SELECT * FROM UA#gdblm ORDER BY ID"
Set rs = CreateObject("ADODB.Recordset")
rs.Open sql, conn, 1, 1
If Not rs.eof And Not rs.bof Then
rs.MoveFirst
i=0
Do While Not rs.Eof
tag_N=tag_N & ";" & rs(1)
tag_T=tag_T & ";" & rs(2)
tag_U=tag_U & ";" & rs(3)
i=i+1
rs.movenext
Loop
tag_N=Right(tag_N,Len(tag_N)-1)
tag_T=Right(tag_T,Len(tag_T)-1)
tag_U=Right(tag_U,Len(tag_U)-1)
Atag_N=Split(tag_N,";")
Atag_T=Split(tag_T,";")
Atag_U=Split(tag_U,";")
max= UBound(Atag_N)
For i=0 To max
idd=idd+1
tagstr=Atag_N(i)
tag_name=Atag_T(i)
'If RM_MASTER=1 Then
sql1=zdgd_sql1 (idd,tagstr,tag_name,table_name)
'MsgBox sql
conn.execute sql1
'End If
Next
'MsgBox sql
End If

End If
'End If





End Function

相关的项目函数:
Function zdgd_sql1(idd,tagstr,tag_name,table_name)
'2008-01-18 chenm 秦皇岛项目
Dim temp_str1,max,i,tagvalue,sql_str,aa,hh

aa=Hour(Now())
If Len(Trim(aa))=1 Then
aa="0" & aa
End If
aa=aa & ":00"
tagvalue=GetTag(tagstr)
sql_str="INSERT INTO [" & table_name & "] "
sql_str=sql_str& " (id,Tag_name, BM, ZHI, RQ, SJ) "
sql_str=sql_str & " VALUES (" & idd & ",N'" & tagstr &"',N'"& tag_name & "'," & tagvalue &

",N'"& longdatestr(Now())&"',N'" & aa & "')"
zdgd_sql1=sql_str
End Function
function longdatestr(str)
dim yyyy,mm,dd
if isdate(str) then
yyyy=year(str)
mm=month(str)
dd=day(str)
if len(trim(mm))=1 then
mm="0" & mm
end if
if len(trim(dd))=1 then
dd="0" & dd
end if
longdatestr=yyyy & "-" & mm & "-" & dd
else
longdatestr=str
end if
end function
快下班了晚上回家继续写
让学习成为一种习惯
虚心+学习
游侠

经验值:499
发帖数:110
精华帖:6
    2009-03-09 21:46:53
精华帖  主题:回复:技术专题探讨-WinCC实现报表的不同方法及其应用
刚赶回家,和几个志同道合的朋友喝了点小酒,头脑有点不清晰了。水晶报表是个好东西,特别是在做报表方面,为什么不不选用他,主要是:顺序输出的报表它还是可行的,但对于需要合计的月报、年报需要在VB内进行合计等,还需要用相当于变量填充单元格的方式,而且制作报表文件需要时间。
数据冗余其实我在上面的代码里已经有体现:就是这里:
RM_MASTER=GetTag("@RM_MASTER")

'RM_MASTER=1

'If RM_MASTER=1 Then

就是判断主机上位机为主机的时候方可写入数据库。

管理员注:本帖已被纳入此次探讨发帖整理之方案汇总,请点此详阅

让学习成为一种习惯
虚心+学习
游侠

经验值:499
发帖数:110
精华帖:6
    2009-03-09 21:52:55
精华帖  主题:回复:技术专题探讨-WinCC实现报表的不同方法及其应用
下面把日报、月报、年报的具体输出方式叙述一下:
日报:在wincc的图形编辑器里制作日报画面:画面中放置一日期的输入输出域,再放置一个按钮,按钮文本:“导出到EXCEL”按钮代码如下:
Sub OnClick(ByVal Item)
Dim objExcelApp
Dim i,n,tagstr
Dim writeRiQi,ksrq,jsrq,max
Dim baobiao,jls,tabname
Dim blm,sj,zhi

' Dim jcyl_a,cgyl_a,yw_a,dqyl_a,jcpjwd_a,cgpjwd_s_a,cgpjwd_x_a
' Dim jcyl_b,cgyl_b,yw_b,dqyl_b,jcpjwd_b,cgpjwd_s_b,cgpjwd_x_b
' Dim tank_A_kg,tank_A_Q,tank_B_kg,tank_B_Q'
Dim rb(17,23) '17表示18列数据 23表示24小时即24行
Dim TagNameSerial,TagNameArray

'欲显示在EXCEL中的变量名序列
TagNameSerial="AI_HY1_LGh;AI_HY2_LGh;AI_GF1_LGh;AI_GF2_LGh;AI_LF1_LGh;AI_LF2_LGh;AI_BY1_LGh;AI_GZ1_LGh;AI_RL1_LGh;AI_RL2_LGh;AI_SH1_LGh;AI_SH2_LGh;AI_SC1_LGh"
TagNameArray=Split(TagNameSerial,";")
max=UBound(TagNameArray)
' For i=0 To 17
' For n=0 To 23
' rb(i,n)="-"
' Next
' Next


ksrq=GetTag("ksrq")

If IsDate(ksrq)=False Then
'MsgBox "err ksrq =" & ksrq
ksrq=DateValue(Date)
SetTag "ksrq",ksrq
End If
jsrq=DateValue(ksrq)+1
'MsgBox jsrq
db_open


tabname="UA#ZDGD"

sql="SELECT * FROM " & tabname
'0点起显示
sql=sql & " WHERE (RQ = N'"&ksrq&"') "
'以每天9点为界显示
' sql=sql & " WHERE (RQ = N'"&ksrq&"') AND ({ fn HOUR(SJ) } >= 9) OR "
' sql=sql & " (RQ = N'"&jsrq&"') AND ({ fn HOUR(SJ) } < 9) "
sql=sql & " ORDER BY RQ DESC, SJ DESC"
'MsgBox sql
'writeRiQi="&ksrq="&ksrq&"&jsrq="&jsrq
Set rs=CreateObject("adodb.recordset")
rs.open sql,conn,1,1
if not rs.eof and not rs.bof then
rs.MoveFirst
Do While Not rs.EOF
'sj= Hour(rs("LastAccess") )
sj= Hour(rs("sj") )

blm=rs("Tag_name")
zhi=rs("ZHI")
'MsgBox sj & blm & zhi
i=0
for i=0 to max
If blm=TagNameArray(i) Then
rb(i,sj)=FormatNumber(zhi,2)
End If
Next
rs.movenext
loop
End If

Set objExcelApp = CreateObject("Excel.Application")
objExcelApp.Visible = True
objExcelApp.Workbooks.Open "F:\india\wincc\DayReport.xls"
'9点为界的赋值
' For i=0 To 17
' For n=9 To 23
' objExcelApp.Cells(n-4, 2+i).Value = rb(i,n)
' Next
' Next
' For i=0 To 17
' For n=0 To 8
' objExcelApp.Cells(n+20, 2+i).Value = rb(i,n)
' Next
' Next
'0点正常赋值
For i=0 To 17
For n=0 To 23
objExcelApp.Cells(n+5, 2+i).Value = rb(i,n)
Next
Next
'特殊单元格赋值
objExcelApp.Cells(1, 2).Value = ksrq
objExcelApp.Cells(1, 5).Value = WeekdayRturn(Weekday(ksrq))
' objExcelApp.Cells(32, 1).Value = tank_A_kg
' objExcelApp.Cells(32, 2).Value = tank_A_Q
' objExcelApp.Cells(32, 3).Value = tank_B_kg
' objExcelApp.Cells(32, 4).Value = tank_B_Q
' objExcelApp.ActiveWorkbook.Save
End Sub

管理员注:本帖已被纳入此次探讨发帖整理之方案汇总,请点此详阅
让学习成为一种习惯
虚心+学习
游侠

经验值:499
发帖数:110
精华帖:6
    2009-03-09 22:00:54
精华帖  主题:回复:技术专题探讨-WinCC实现报表的不同方法及其应用
月报的画面:
在画面中加入2个输入输出与分别填入年份和月份,再加入一个按钮,按钮文本:“导出到EXCEL”,代码如下:
Dim objExcelApp
Dim i,n,tagstr
Dim writeRiQi,ksrq,jsrq,max
Dim baobiao,jls,tabname
Dim blm,sj,zhi
Dim ReportYear,ReportMonth

Dim rb(17,31) '17表示18列数据 31表示31天即31行
Dim TagNameSerial,TagNameArray

'欲显示在EXCEL中的变量名序列
TagNameSerial="AI_HY1_LGh;AI_HY2_LGh;AI_GF1_LGh;AI_GF2_LGh;AI_LF1_LGh;AI_LF2_LGh;AI_BY1_LGh;AI_GZ1_LGh;AI_RL1_LGh;AI_RL2_LGh;AI_SH1_LGh;AI_SH2_LGh;AI_SC1_LGh"
TagNameArray=Split(TagNameSerial,";")
max=UBound(TagNameArray)
' For i=0 To 17
' For n=0 To 23
' rb(i,n)="-"
' Next
' Next

ReportYear=GetTag("ReportYear")
ReportMonth=GetTag("ReportMonth")

db_open


tabname="UA#ZDGD"

'23点即为当天保存的累计值,可以配合整点归档保存脚本,将保存时间调整到例如23:59:59
sql="SELECT ID, Tag_name, BM, ZHI, RQ, SJ, LastAccess, Fingerprint "
sql=sql & "FROM UA#ZDGD "
sql=sql & "WHERE (YEAR(RQ) = " & ReportYear & ") And (Month(RQ) = " & ReportMonth & ") And ({ fn Hour(SJ) } = 23) "
sql=sql & "ORDER BY ID "


Set rs=CreateObject("adodb.recordset")
rs.open sql,conn,1,1
if not rs.eof and not rs.bof then
rs.MoveFirst
Do While Not rs.EOF
'sj= Hour(rs("LastAccess") )
'sj= Hour(rs("sj") )
sj=Day(rs("RQ")) '取day值

blm=rs("Tag_name")
zhi=rs("ZHI")
i=0
for i=0 to max
If blm=TagNameArray(i) Then
rb(i,sj)=FormatNumber(zhi,2)
End If
Next
rs.movenext
loop
End If

Set objExcelApp = CreateObject("Excel.Application")
objExcelApp.Visible = True
objExcelApp.Workbooks.Open "F:\india\wincc\MonthReport.xls"

For i=0 To 17
For n=0 To 31
objExcelApp.Cells(n+4, 2+i).Value = rb(i,n)
Next
Next

'特殊单元格赋值
objExcelApp.Cells(1, 2).Value = ReportYear & "Year"
objExcelApp.Cells(1, 3).Value = ReportMonth & "Month"
objExcelApp.Cells(1, 13).Value = Now

'objExcelApp.Cells(1, 5).Value = WeekdayRturn(Weekday(ksrq))
' objExcelApp.Cells(32, 1).Value = tank_A_kg
' objExcelApp.Cells(32, 2).Value = tank_A_Q
' objExcelApp.Cells(32, 3).Value = tank_B_kg
' objExcelApp.Cells(32, 4).Value = tank_B_Q

' objExcelApp.ActiveWorkbook.Save

在这里需要说明一下,这个项目主要是做配料的流量累计,我的思路是每天的0点清除当日的累计量,所以报表是按照这个思路来做的,月报的累计量是取每天的23点的那个值。

让学习成为一种习惯
虚心+学习
游侠

经验值:499
发帖数:110
精华帖:6
    2009-03-09 22:12:04
精华帖  主题:回复:技术专题探讨-WinCC实现报表的不同方法及其应用
再说说年报,在图形编辑器里制作年报画面,插入一输入输出域:用以输入年份,再加入一个按钮,按钮文本:导出到EXCEL,按钮代码:
Dim objExcelApp
Dim i,n,tagstr
Dim writeRiQi,ksrq,jsrq,max
Dim baobiao,jls,tabname
Dim blm,sj,zhi
Dim ReportYear,ReportMonth

Dim rb(17,12) '17表示18列数据 12表示12月2
Dim TagNameSerial,TagNameArray

'欲显示在EXCEL中的变量名序列
TagNameSerial="AI_HY1_LGh;AI_HY2_LGh;AI_GF1_LGh;AI_GF2_LGh;AI_LF1_LGh;AI_LF2_LGh;AI_BY1_LGh;AI_GZ1_LGh;AI_RL1_LGh;AI_RL2_LGh;AI_SH1_LGh;AI_SH2_LGh;AI_SC1_LGh"
TagNameArray=Split(TagNameSerial,";")
max=UBound(TagNameArray)
' For i=0 To 17
' For n=0 To 23
' rb(i,n)="-"
' Next
' Next

ReportYear=GetTag("ReportYear")
' ReportMonth=GetTag("ReportMonth")

db_open


tabname="UA#ZDGD"

'23点即为当天保存的累计值,可以配合整点归档保存脚本,将保存时间调整到例如23:59:50

sql="SELECT SUM(ZHI) AS 累计值, Tag_name, MONTH(RQ) AS 月 "
sql=sql & "FROM UA#ZDGD "
sql=sql & "WHERE (YEAR(RQ) = " & ReportYear & ") AND ({ fn HOUR(SJ) } = 23) "
sql=sql & "GROUP BY Tag_name, MONTH(RQ) "
'结果集
'累计值 Tag_name 月
'30 AI_BY1_1 1
'5 AI_BY1_1 2
'0 AI_GF1_1 2
'0 AI_GF2_1 2
'0 AI_GZ1_1 2
'0 AI_HY1_1 2
'0 AI_HY2_1 2
'0 AI_LF1_1 2
'0 AI_LF2_1 2
'0 AI_RL1_1 2
'24 AI_RL2_1 2
'12 AI_SC1_1 2
'0 AI_SH1_1 2
'44 AI_SH2_1 2

Set rs=CreateObject("adodb.recordset")
rs.open sql,conn,1,1
if not rs.eof and not rs.bof then
rs.MoveFirst
Do While Not rs.EOF
'sj= Hour(rs("LastAccess") )
'sj= Hour(rs("sj") )
sj=rs(2) '取day值
blm=rs(1)
zhi=rs(0)
i=0
for i=0 to max
If blm=TagNameArray(i) Then
rb(i,sj)=FormatNumber(zhi,2)
End If
Next
rs.movenext
loop
End If

Set objExcelApp = CreateObject("Excel.Application")
objExcelApp.Visible = True
objExcelApp.Workbooks.Open "F:\india\wincc\YearReport.xls"

For i=0 To 17
For n=0 To 12
objExcelApp.Cells(n+4, 2+i).Value = rb(i,n)
Next
Next

'特殊单元格赋值
objExcelApp.Cells(1, 2).Value = ReportYear & "Year"
' objExcelApp.Cells(1, 3).Value = ReportMonth & "Month"
objExcelApp.Cells(1, 13).Value = Now

'objExcelApp.Cells(1, 5).Value = WeekdayRturn(Weekday(ksrq))
' objExcelApp.Cells(32, 1).Value = tank_A_kg
' objExcelApp.Cells(32, 2).Value = tank_A_Q
' objExcelApp.Cells(32, 3).Value = tank_B_kg
' objExcelApp.Cells(32, 4).Value = tank_B_Q

' objExcelApp.ActiveWorkbook.Save


这段代码的精髓在于那段SQL语句,是将每个月的合计输出到一个结果集中供报表使用。报表里的合计累计、判断无效数据等还需要EXCEL的配合,但这对经常使用EXCEL的人应该不算是困难。
论坛不然上传附件,否则可以将该项目的源文件上载以供大家斧正,在这里我只是提出一种报表的思路,且是切实可行的。

管理员注:本帖已被纳入此次探讨发帖整理之方案汇总,请点此详阅
让学习成为一种习惯
eaglesky
侠圣

经验值:2989
发帖数:660
精华帖:22
    2009-03-17 21:44:58
精华帖  主题:回复:技术专题探讨-WinCC实现报表的不同方法及其应用
这个专题是到3月18日结束? 还有这个专题的后续么?今天从头到尾又看了一遍,感触很多,可是又觉得没有很实质性的收获,不知道是不是我的理解能力较差导致。
从接触WINCC时就听说WINCC的报表不好用,所以我自己做的时候,几乎直接就将wincc的自带报表功能pass了,可从这个专题看,wincc自带报表还不是一奘谴Γ』赝芬一岷煤每纯戳恕N易约和暾淖龉?个项目的报表,主观上的分别采用了2种途径:1种是在wincc中写VBS脚本,生成EXCEL文件,1种是直接在EXCEL中写VBS脚本。但是这2种方法都有比较明显的缺陷。具体脚本内容就不写了,由于项目内容涉密,一时间也找不到项目文件,并且前面已经有这2种方法的例子帖出来了。简单说一下我感觉的这2种方法的缺陷吧:第一种,在wincc中写报表,由于操作人员会在操作过程中操作excel,所以为了避免干扰,每次写完EXCEL并保存后,我会用VBS关闭excel文件。但是会遇到一个问题:有时EXCEL文件虽然被关闭了,但是EXCEL进程会留在系统内并形成一个死掉的进程,操作越频繁,出现的概率越大!同时,这个方法不适合同时处理2个以上的EXCEL文件。 第二种方法,在EXCEL中写VBS,首先的问题就是EXCEL要始终处于运行状态,其次,这种方法很容易受到EXCEL文件本身的干扰,比如操作员打开其它的EXCEL文件,又或者操作员在本机上查看以前的报表文件等。最明显的现象,就是当前报表文件某个单元格处于被编辑状态时,VBS脚本无法执行!并且,从后一个现场的反馈情况,这种报表文件不间断24小时运行的话,很容易出现问题。
当然,某些现象是无法实际执行的,比如不允许操作员操作员操作EXCEL,不允许在本机查看报表等,这在实际中无法避免的。
过段时间就要调试下一个项目了,在这个专题中受到了一些启发,但是还有很多困惑,我还是偏向与先将数据存入数据库,然后提供给用户一个查询界面程序,这样我觉得更可靠些。至少数据已经正确的保存了,查询界面程序可以完善。先保证数据的存在才是基础。
希望这个专题还有后续,也希望我也可以借助这个专题,这次的项目调试,找到一个更好的方法。

管理员注:本帖已被纳入此次探讨发帖整理之理论探讨,请点此详阅
没有个性的签名就别签了。
您收到0封站内信:
×
×
信息提示
很抱歉!您所访问的页面不存在,或网址发生了变化,请稍后再试。