| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 4454 人关注过本帖, 1 人收藏
标题:分享:SQL2000 异步查询数据带进度条。
取消只看楼主 加入收藏
mywisdom88
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:191
帖 子:3147
专家分:8408
注 册:2015-3-25
结帖率:98.98%
收藏(1)
已结贴  问题点数:5 回复次数:4 
分享:SQL2000 异步查询数据带进度条。
*!* 斑竹aaaaaa提供代码,VFP9.0+SQL2000,外网数据库,8900条记录,测试11秒左右。

*!* 方法一:用 Wait window
*!* SQL Query 使用过程条,SQLExec 必须异步模式。
Local loTherm,lnRes ,lcQueryTB ,lcQueryYB

*!* Sql查询语句,同步查记录总数
TEXT TO lcQueryTB TEXTMERGE NOSHOW PRETEXT 4
SELECT COUNT(*) as SqlCount
 from wy_sdb
 where fyqj>='2015-10-01'
ENDTEXT

*!* Sql查询语句,异步查记录内容
TEXT TO lcQueryYB TEXTMERGE NOSHOW PRETEXT 4
SELECT bh,fyqj,df,sf,hj,sjh
 from wy_sdb
 where fyqj>='2015-10-01'
ENDTEXT

*!* Sql连接句柄
csql = [ driver=sql server;server=]+cServer+[;uid=]+cUid+[;pwd=]+cPwd+[;database=]+cdbs
sqlHandler = Sqlstringconnect(csql)
IF sqlHandler < 0
   MESSAGEBOX("连接数据库失败!",16,"连接错误")
ELSE
t1=SECONDS()  
*!* 首先使用同步方式获取总记录数(不要异步方式):
LOCAL lnFetchSize ,lnMaxWait ,lnSqlCount ,lcWait
SQLSetprop(sqlHandler, "Asynchronous", .F.) && 同步方式
lnRes=SQLExec(m.sqlHandler, lcQueryTB, "SqlQueryTB")
lnSqlCount = 0
lnFetchSize = 1
lnMaxWait = 20 && 满进度显示“■”的个数,可以自己设置,20个左右合适
IF lnRes < 0
   MESSAGEBOX("读取记录总数出错!",16,"读取错误")
   RETURN
ELSE
   lnSqlCount = IIF(ISNULL(SqlQueryTB.SqlCount),0,SqlQueryTB.SqlCount) && 合理设置 lnFetchSize
   IF lnSqlCount>lnMaxWait
      lnFetchSize=INT(lnSqlCount / lnMaxWait) && 自动计算异步查询步长,每个“■”代表的记录数
   ENDIF
   lcWait = Replicate("■", 1)+SPACE(lnMaxWait*2-1*2)
   Wait Window (lcWait) Nowait  && 刷新过程条
Endif

*!* 然后使用异步方式做查询:
SQLSetprop(sqlHandler, "Asynchronous", .T.) && 异步方式
CursorSetProp("FetchSize", lnFetchSize, 0)  && FetchSize 属性,设置每次异步查询返回的记录数 lnFetchSize
lnRes=SQLExec(sqlHandler, lcQueryYB,"SqlQueryYB")
If lnRes < 0
    MESSAGEBOX("读取记录进程出错!",16,"读取错误")
    WAIT CLEAR
    RETURN
Endif

*!* 更新过程条的显示,显示格式为:总共 lnMaxWait 个“■”
LOCAL lnCnt
Do While SQLExec(sqlHandler) = 0
   DoEvents
   lnCnt = CursorGetProp("RecordsFetched") && 当前返回的记录数
   lcWait = Replicate("■", INT(lnCnt/lnFetchSize))+SPACE(lnMaxWait*2-INT(lnCnt/lnFetchSize)*2)
   Wait Window (lcWait) Nowait  && 刷新过程条
Enddo

*!* 当总记录数少于lnMaxWait时,可能是出现不满过程条,补满过程条
lcWait = Replicate("■", lnMaxWait)
Wait Window (lcWait) Nowait  && 刷新过程条

?lnCnt,SECONDS()-t1

ENDIF

*!* 斑竹aaaaaa提供代码,VFP9.0+SQL2000,外网数据库,8900条记录,测试11秒左右。

*!* 方法二:用类 _Therm.Vcx
*!* SQL Query 使用过程条,SQLExec 必须异步模式。
*!* 下面是一个使用 VFP FFC _Therm.Vcx 过程条例子:
Local loTherm,lnRes ,lcQueryTB ,lcQueryYB

*!* 使用 VFP FFC 自带的 _Therm.Vcx 过程条:
loTherm = Newobject("_thermometer", Home() + "ffc/_therm", "", "正在查询数据,请稍候...")
loTherm.Show
loTherm.Update(0, "正在查询...")
DoEvents Force

*!* Sql查询语句,同步查记录总数
TEXT TO lcQueryTB TEXTMERGE NOSHOW PRETEXT 4
SELECT COUNT(*) as SqlCount
 from wy_sdb
 where fyqj>='2015-10-01'
ENDTEXT

*!* Sql查询语句,异步查记录内容
TEXT TO lcQueryYB TEXTMERGE NOSHOW PRETEXT 4
SELECT bh,fyqj,df,sf,hj,sjh
 from wy_sdb
 where fyqj>='2015-10-01'
ENDTEXT

*!* Sql连接句柄
csql = [ driver=sql server;server=]+cServer+[;uid=]+cUid+[;pwd=]+cPwd+[;database=]+cdbs
sqlHandler = Sqlstringconnect(csql)

IF sqlHandler < 0
   MESSAGEBOX("连接数据库失败!",16,"连接错误")
   Release loTherm
ELSE
t1=SECONDS()

*!* 首先使用同步方式获取总记录数(不要异步方式):
LOCAL lnFetchSize ,lnSqlCount
SQLSetprop(sqlHandler, "Asynchronous", .F.) && 同步方式
lnRes=SQLExec(m.sqlHandler, lcQueryTB, "SqlQueryTB")
lnSqlCount=0
lnFetchSize=1
IF lnRes < 0
   MESSAGEBOX("读取记录总数出错!",16,"读取错误")
   Release loTherm
   RETURN
ELSE
   lnSqlCount = IIF(ISNULL(SqlQueryTB.SqlCount),0,SqlQueryTB.SqlCount) && 合理设置 lnFetchSize
   IF lnSqlCount>100
      lnFetchSize=INT(lnSqlCount / 100) && 自动计算异步查询步长
   ENDIF
   lotherm.iBasis = SqlQueryTB.SqlCount  && SqlCount 游标中的总记录数
Endif

*!* 然后使用异步方式做查询:
SQLSetprop(sqlHandler, "Asynchronous", .T.) && 异步方式
CursorSetProp("FetchSize", lnFetchSize, 0)  && FetchSize 属性,设置每次异步查询返回的记录数 lnFetchSize
lnRes=SQLExec(sqlHandler, lcQueryYB,"SqlQueryYB")
If lnRes < 0
    MESSAGEBOX("读取记录进程出错!",16,"读取错误")
    Release loTherm   
    RETURN
Endif

*!* 更新过程条的显示,显示格式为:当前记录数 N / 总记录数 M:
LOCAL lnCnt
Do While SQLExec(sqlHandler) = 0
   DoEvents
   lnCnt = CursorGetProp("RecordsFetched")
   loTherm.Update(m.lnCnt, Transform(m.lnCnt) + "/" + Transform(loTherm.iBasis))
Enddo
Release loTherm

?lnCnt,SECONDS()-t1
ENDIF

** 多个表共用1个进度条的方法,已经解决,在第10楼

[此贴子已经被作者于2016-4-9 20:09编辑过]

搜索更多相关主题的帖子: aaaaaa window 数据库 where 记录 
2016-04-03 21:02
mywisdom88
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:191
帖 子:3147
专家分:8408
注 册:2015-3-25
收藏
得分:0 
以下是引用aaaaaa在2016-4-3 21:20:12的发言:

其实我一直在考虑使用 DBF 也可以采用异步方程。好像没有方向。
假如采用调用多线程的方法也没招,取不回中途已下载的记录数。
假如 DBF 也用 ODBC 的连接,则 SQL Query 的查询速度会很慢。
在内网,应该不怎么慢吧。。
我以前外网SQL2000,只用 Wait window nowait "正在查询数据中..."
感觉不怎么好,一直在网上查,怎么搞个进度条,今天终于有了。
感觉同步查询和异步查询,时间差不多。不怎么打折。不知道在内网,速度会不会打折
2016-04-03 21:31
mywisdom88
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:191
帖 子:3147
专家分:8408
注 册:2015-3-25
收藏
得分:0 
回复 5楼 aaaaaa
CLEAR
CLOSE DATABASES
*!* 方法一:用 Wait window
*!* SQL Query 使用过程条,SQLExec 必须异步模式。
Local loTherm,lnRes ,lcQueryTB ,lcQueryYB

*!* Sql查询语句,同步查记录总数
TEXT TO lcQueryTB TEXTMERGE NOSHOW PRETEXT 4
SELECT COUNT(*) as SqlCount
 from wy_sdb
 where fyqj>='2015-10-01'
ENDTEXT

*!* Sql查询语句,异步查记录内容
TEXT TO lcQueryYB TEXTMERGE NOSHOW PRETEXT 4
SELECT bh,fyqj,df,sf,hj,sjh
 from wy_sdb
 where fyqj>='2015-10-01'
ENDTEXT

*!* Sql查询语句,同步查记录总数
TEXT TO lcQueryTB1 TEXTMERGE NOSHOW PRETEXT 4
SELECT COUNT(*) as SqlCount
 from wy_zlb
ENDTEXT

*!* Sql查询语句,异步查记录内容
TEXT TO lcQueryYB1 TEXTMERGE NOSHOW PRETEXT 4
SELECT *
 from wy_zlb
ENDTEXT


*!* Sql连接句柄
csql = [ driver=sql server;server=]+cServer+[;uid=]+cUid+[;pwd=]+cPwd+[;database=]+cdbs
sqlHandler = Sqlstringconnect(csql)
IF sqlHandler < 0
   MESSAGEBOX("连接数据库失败!",16,"连接错误")
ELSE

*!* 首先使用同步方式获取总记录数(不要异步方式):
public lnFetchSize ,lnMaxWait ,lnSqlCount ,lcWait
SQLSetprop(sqlHandler, "Asynchronous", .F.) && 同步方式

lnSqlCount = 0
lnFetchSize = 1
lnMaxWait = 20 && 满进度显示“■”的个数,可以自己设置,20个左右合适

lnRes=SQLExec(m.sqlHandler, lcQueryTB, "SqlQueryTB")
IF lnRes < 0
   MESSAGEBOX("读取记录总数出错!",16,"读取错误")
   RETURN
ELSE
   lnSqlCount = lnSqlCount + IIF(ISNULL(SqlQueryTB.SqlCount),0,SqlQueryTB.SqlCount) && 合理设置 lnFetchSize
ENDIF

lnRes1=SQLExec(m.sqlHandler, lcQueryTB1, "SqlQueryTB1")
IF lnRes1 < 0
   MESSAGEBOX("读取记录总数出错!",16,"读取错误")
   RETURN
ELSE
   lnSqlCount = lnSqlCount + IIF(ISNULL(SqlQueryTB1.SqlCount),0,SqlQueryTB1.SqlCount) && 合理设置 lnFetchSize
ENDIF

IF lnSqlCount>lnMaxWait
   lnFetchSize=INT(lnSqlCount / lnMaxWait)  && 自动计算异步查询步长,每个“■”代表的记录数
ENDIF

lcWait = Replicate("■", 1)+SPACE((lnMaxWait - 1) * 2)
Wait Window (lcWait) Nowait  && 刷新过程条

*!* 然后使用异步方式做查询:
public lnCnt ,lnBarNum ,lnCntAll ,lnCnt1
STORE 0 TO lnCnt ,lnBarNum ,lnCntAll,lnCnt1

SQLSetprop(sqlHandler, "Asynchronous", .T.) && 异步方式
CursorSetProp("FetchSize", lnFetchSize, 0)  && FetchSize 属性,设置每次异步查询返回的记录数 lnFetchSize
lnRes=SQLExec(sqlHandler, lcQueryYB,"SqlQueryYB")
If lnRes < 0
    MESSAGEBOX("读取记录进程出错!",16,"读取错误")
    WAIT CLEAR
    RETURN
Endif

*!* 更新过程条的显示,显示格式为:总共 lnMaxWait 个“■”
DO While SQLExec(sqlHandler) = 0
   DoEvents
   lnCnt = CursorGetProp("RecordsFetched") && 当前返回的记录数
   lnBarNum=INT((lnCnt + lnCntAll) / lnFetchSize)
   lcWait = Replicate("■", lnBarNum)+SPACE((lnMaxWait - lnBarNum) * 2)
   Wait Window (lcWait) Nowait  && 刷新过程条
ENDDO
?lnCnt, lnSqlCount,RECCOUNT()
lnCnt = CursorGetProp("RecordsFetched") && 当前返回的记录数
?lnCnt, lnSqlCount,RECCOUNT()
lnCnt = CursorGetProp("RecordsFetched") && 当前返回的记录数
?lnCnt, lnSqlCount,RECCOUNT() &&8907,10421,8907

MESSAGEBOX(TRANSFORM(lnCnt)+"="+TRANSFORM(RECCOUNT())) && 此时,lnCnt=RECCOUNT()了,表示,这个表的数据完成了
lnCntAll=lnCntAll+lnCnt
?lnCnt, lnSqlCount,lnCntAll &&8907,10421,8907

SQLSetprop(sqlHandler, "Asynchronous", .t.) && 异步方式
CursorSetProp("FetchSize", lnFetchSize, 0)  && FetchSize 属性,设置每次异步查询返回的记录数 lnFetchSize

lnRes1=SQLExec(sqlHandler, lcQueryYB1,"SqlQueryYB1")
If lnRes1 < 0
    MESSAGEBOX("读取记录进程出错!",16,"读取错误")
    WAIT CLEAR
    RETURN
Endif

*!* 更新过程条的显示,显示格式为:总共 lnMaxWait 个“■”
*LOCAL lnCnt ,lnBarNum
lnCnt1 = CursorGetProp("RecordsFetched") && 当前返回的记录数
DO While SQLExec(sqlHandler) = 0
   DoEvents
   lnCnt1 = CursorGetProp("RecordsFetched") && 当前返回的记录数
*  lnBarNum=INT((lnCnt1 + lnCntAll) / lnFetchSize)
   ?lnCnt1 && 应该这个是从新开始的,但最少有20次循环,这个值为=8907,然后才是新表的值521,1042,共1514,问题在这里。

   lnBarNum=INT((lnCnt1) / lnFetchSize)
   lcWait = Replicate("■", lnBarNum)+SPACE((lnMaxWait - lnBarNum) * 2)
   Wait Window (lcWait) Nowait  && 刷新过程条
ENDDO
?lnCnt1, lnSqlCount,RECCOUNT()
lnCnt1 = CursorGetProp("RecordsFetched") && 当前返回的记录数
?lnCnt1, lnSqlCount,RECCOUNT()
lnCnt1 = CursorGetProp("RecordsFetched") && 当前返回的记录数
?lnCnt1, lnSqlCount,RECCOUNT()

*lnCntAll=lnCntAll+lnCnt1

*!* 当总记录数少于lnMaxWait时,可能是出现不满过程条,补满过程条
lcWait = Replicate("■", lnMaxWait)
Wait Window (lcWait) Nowait  && 刷新过程条

ENDIF


2016-04-04 22:51
mywisdom88
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:191
帖 子:3147
专家分:8408
注 册:2015-3-25
收藏
得分:0 
以下是引用hu9jj在2016-4-5 11:02:02的发言:

用字符来显示进度还不如用矩形控件来显示进度,动态改变矩形控件的宽度,可以达到很好的效果。

都可以,但问题不在显示这里
上面的,如果是只读取1个表的数据,没问题。
但如果我想读取2个表的数据,在一个进度中显示,就有问题。
问题在红字那里
第1个表的数据完全下载回来后,
lnCnt = CursorGetProp("RecordsFetched") && 当前返回的记录数
第2个表的这个值,
lnCnt = CursorGetProp("RecordsFetched") && 当前返回的记录数
有很长时间都是上次第1个表的最后数据
2016-04-05 12:01
mywisdom88
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:191
帖 子:3147
专家分:8408
注 册:2015-3-25
收藏
得分:0 
以下是引用aaaaaa在2016-4-5 15:27:50的发言:

不管是同步还是异步方式,如果只有一个表的 Select-SQL 语句,用过程条还是比较正确的。
但如果是父子多表连接的,或者一表自连接的,总的记录数(多表合计记录数)不好取,已下载的记录数更不好取。
 
所以用过程条用在复杂的查询语句,有很大的局限性。
* 搞定了。。
* 发现  lnCnt = CursorGetProp("RecordsFetched"),当前没打开表时,会报错,我们就可以用DBF(),同时,2个表一起显示进度时,对比前后的DBF()的值,就可以知道,* 第2个表,是不是开始下载数据
* 红字是本次修改后的代码,WIN7 + VFP9.0 +SQL2000 通过测试
CLEAR
RELEASE ALL
CLOSE DATABASES &&就是这句话,让我发现,启发本次修改完成,实现多个表共1个进度条
*!* 方法一:用 Wait window
*!* SQL Query 使用过程条,SQLExec 必须异步模式。
Local loTherm,lnRes ,lcQueryTB ,lcQueryYB

*!* Sql查询语句,同步查记录总数,第1个表
TEXT TO lcQueryTB TEXTMERGE NOSHOW PRETEXT 4
SELECT COUNT(*) as SqlCount
 from wy_sdb
 where fyqj>='2015-10-01'
ENDTEXT

*!* Sql查询语句,异步查记录内容,第1个表
TEXT TO lcQueryYB TEXTMERGE NOSHOW PRETEXT 4
SELECT bh,fyqj,df,sf,hj,sjh
 from wy_sdb
 where fyqj>='2015-10-01'
ENDTEXT

*!* Sql查询语句,同步查记录总数,第2个表
TEXT TO lcQueryTB1 TEXTMERGE NOSHOW PRETEXT 4
SELECT COUNT(*) as SqlCount
 from wy_zlb
ENDTEXT

*!* Sql查询语句,异步查记录内容,第2个表
TEXT TO lcQueryYB1 TEXTMERGE NOSHOW PRETEXT 4
SELECT *
 from wy_zlb
ENDTEXT

*!* Sql连接句柄
csql = [ driver=sql server;server=]+cServer+[;uid=]+cUid+[;pwd=]+cPwd+[;database=]+cdbs
sqlHandler = Sqlstringconnect(csql)
IF sqlHandler < 0
   MESSAGEBOX("连接数据库失败!",16,"连接错误")
ELSE

*!* 首先使用同步方式获取总记录数(不要异步方式):
LOCAL lnFetchSize ,lnMaxWait ,lnSqlCount ,lcWait
lnSqlCount = 0
lnFetchSize = 1
lnMaxWait = 20 && 满进度显示“■”的个数,可以自己设置,20个左右合适

SQLSetprop(sqlHandler, "Asynchronous", .F.) && 同步方式

lnRes=SQLExec(m.sqlHandler, lcQueryTB, "SqlQueryTB")
IF lnRes < 0
   MESSAGEBOX("读取记录总数出错!",16,"读取错误")
   RETURN
ELSE
   lnSqlCount = lnSqlCount + IIF(ISNULL(SqlQueryTB.SqlCount),0,SqlQueryTB.SqlCount)
   USE IN SqlQueryTB
ENDIF

lnRes1=SQLExec(m.sqlHandler, lcQueryTB1, "SqlQueryTB1")
IF lnRes1 < 0
   MESSAGEBOX("读取记录总数出错!",16,"读取错误")
   RETURN
ELSE
   lnSqlCount = lnSqlCount + IIF(ISNULL(SqlQueryTB1.SqlCount),0,SqlQueryTB1.SqlCount)
   USE IN SqlQueryTB1
ENDIF

&&根据总记录数与■数,计算出步长
IF lnSqlCount>lnMaxWait
   lnFetchSize=INT(lnSqlCount / lnMaxWait) +1 && 自动计算异步查询步长,每个“■”代表的记录数,要+1,要不会出错。还没查到什么原因
ENDIF

lcWait = Replicate("■", 1)+SPACE((lnMaxWait - 1) * 2)
Wait Window (lcWait) Nowait  && 刷新过程条

*!* 然后使用异步方式做查询:
LOCAL lnCnt ,lnBarNum ,lnCntAll ,lnCnt1 ,lcDbf ,lcDbf1 ,lcDbf2
STORE 0 TO lnCnt ,lnBarNum ,lnCntAll,lnCnt1

SQLSetprop(sqlHandler, "Asynchronous", .T.) && 异步方式
CursorSetProp("FetchSize", lnFetchSize, 0)  && FetchSize 属性,设置每次异步查询返回的记录数 lnFetchSize

lcDbf=DBF() &&这步非常重要,判断开始下载的根据

lnRes=SQLExec(sqlHandler, lcQueryYB,"SqlQueryYB")
If lnRes < 0
    MESSAGEBOX("读取记录进程出错!",16,"读取错误")
    WAIT CLEAR
    RETURN
Endif

DO While SQLExec(sqlHandler) = 0
   DOEVENTS
   lcDbf1=DBF()
   && 当前打开的表名为空或者等于上次表名,表示数据还没开始下载,等待
   IF EMPTY(lcDbf1) OR lcDbf1=lcDbf
      ?lnCntAll
   ELSE
      lnCnt = CursorGetProp("RecordsFetched") && 当前返回的记录数
      lnBarNum=INT((lnCnt + lnCntAll) / lnFetchSize)
      lcWait = Replicate("■", lnBarNum)+SPACE((lnMaxWait - lnBarNum) * 2)
      Wait Window (lcWait) Nowait  && 刷新过程条
   ENDIF
ENDDO

&& 虽然 SQLExec(sqlHandler) = 0,但 lnCnt 却不是最最大值,继续取lnCnt
lnCnt1=lnCnt
DO WHILE lnCnt1=lnCnt
    lnCnt = CursorGetProp("RecordsFetched") && 当前返回的记录数
    lnBarNum=INT((lnCnt + lnCntAll) / lnFetchSize)
    lcWait = Replicate("■", lnBarNum)+SPACE((lnMaxWait - lnBarNum) * 2)
    Wait Window (lcWait) Nowait  && 刷新过程条
ENDDO
lnCntAll=lnCntAll+lnCnt

&& 第2个表开始
lcDbf=lcDbf1
lnRes1=SQLExec(sqlHandler, lcQueryYB1,"SqlQueryYB1")
If lnRes1 < 0
    MESSAGEBOX("读取记录进程出错!",16,"读取错误")
    WAIT CLEAR
    RETURN
Endif

DO While SQLExec(sqlHandler) = 0
   DOEVENTS
   lcDbf2=DBF()
   && 当前打开的表名为空或者等于上次表名,表示数据还没开始下载,等待
   IF EMPTY(lcDbf2) OR lcDbf2=lcDbf
      ?lnCntAll
   ELSE
      lnCnt = CursorGetProp("RecordsFetched") && 当前返回的记录数
      lnBarNum=INT((lnCnt + lnCntAll) / lnFetchSize)
      lcWait = Replicate("■", lnBarNum)+SPACE((lnMaxWait - lnBarNum) * 2)
      Wait Window (lcWait) Nowait  && 刷新过程条
   ENDIF
ENDDO

*!* 当总记录数少于lnMaxWait时,可能是出现不满过程条,补满过程条
lcWait = Replicate("■", lnMaxWait)
Wait Window (lcWait) Nowait  && 刷新过程条

ENDIF


[此贴子已经被作者于2016-4-9 21:12编辑过]

2016-04-09 20:07
快速回复:分享:SQL2000 异步查询数据带进度条。
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.019066 second(s), 11 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved