几乎每个完整应用都会需要个复合查询建立个功能强大复合查询首先必须要能够动态
生成查询条件其次应该能够对查询到数据进行修改最后这个复合查询最好能够对对多两个表建
立条件进行查询
在VFP里建立查询思路方法主要有这么几种:是使用VFP中自带SearchClass类; 2是建立个查询;
3是建立个视图其中包括参数化视图、宏替换Sql语句视图; 4是建立个Grid,将其数据源设置为
SQL语句或临时表
不管哪种思路方法其实质都是使用SQL语句
这几种思路方法各有各优点也都有缺点
建立查询思路方法最死板只能建立固定条件查询并且不能更新数据最不能满足要求
SearchClass类功能强大但是它只能对个表建立条件进行查询并且它源代码太复杂了几
乎难以进行修改定制;(初学者想必都有过用表单向导建立表单后试图修改txtbtn类、SearchClass类
经历吧!看到源代码后有几个没昏倒?)
用将Grid数据源设置为SQL语句或临时表思路方法无法修改/更新数据刷新数据也比较困难(这
方面问题在网易虚拟社区VFP版上有过许多讨论大家可以去看看)
建立视图思路方法中参数化视图也太简单不管是用表单Control控件值作参数还是用给参数两端加上引
号思路方法都只能对固定字段进行查询如果是复合查询难道要先建立几十个视图吗?
最有前途办法还是用宏替换SQL语句建立视图办法视图有着能够对数据进行修改/更新优点
如果能够动态生成查询条件那么就是最完美查询了
建立宏替换sql语句视图具体办法是先动态生成个Sql语句sqlstatement,然后用宏替换思路方法使
用Create Sql view viewname as &sqlstatement来动态建立视图最后将数据动态显示在个Grid控
件中
看到这里VFP大虾们怕会大喊:Stop!你当我是菜鸟啊!你办法从理论上虽然行通但实际做
起来就会碰到查询结果在表格上数据无法刷新难题俺早就试过不行了!你想骗稿费啊!
嘿嘿这个难题偏偏给我解决了!这就是我洋洋得意写这篇文章原因!
问题解决
几个月前(好可怜^0^.....),我参照VFPSample中Solution里Interactively Bulid a sql
statement举例建立了个复合查询,想将它集成到我自己中由于该举例是用browse窗口来显示
查询结果而我自己应用使用了顶层表单结果编译后运行才发现Browse窗口在顶层表单中无法
显示于是我建立了个有两个表单表单集用个表单makesql动态生成sql语句在另个表单
form1上用grid来显示查询结果数据,在给Grid设置数据源时候问题来了首先使用临时表来作为表
格数据源结果第次查询正确更改条件进行第 2次查询时碰到了众所周知\"不能更新临时表\"错
误;使用sql语句倒是可以可是在表格显示数据前会莫名其妙先出现个Browse窗口必须关闭它后
才会显示表格由于browse窗口在使用顶层表单中无法显示结果导致无法继续执行这个办
法也不行
最后只能使用Create sql view viewname as &sqlstatement办法了先随便建立个视图
tempview,把表格Recordsourcetype属性设置为1-别名Recordsource属性设置为视图别名tempview
在表单makesql上建立sql语句后代码中使用create sql view temp view as &sqlstatement建立视图
Tempview.
执行后发现第次查询正确更改查询条件后再次查询出现\"视图已存在要改写吗?\"情况
按下\"确定\"后出现表格中没有数据
避免出现对话框问题好解决在建立视图前先用rename view tempview to oldview,然后用
Delete view oldview将旧视图删除就可以了代码如下:
****************************************************************************
database to databasename &&databasename是你数据库名称
&&注意:即使你打开了数据库也必须写这个语句!否则会出现\"找不到数据库\"
used(\"tempview\")
rename view tempview to oldview
delete view oldview
end
Create sql view tempview as &sqlstatement
=requery
IF _TALLY = 0
#DEFINE MSG_LOC \"没有找到符合条件纪录!\"
#DEFINE TITLE_LOC \"没有找到纪录\"
=MESSAGEBOX(MSG_LOC,64+0+0,TITLE_LOC)
ELSE
thisform.hide
thisform.form1.show
End
*****************************************************************************
但是这样做了以后表格上没有数据问题仍然存在查找资料后发现用Create sql view语句编
程建立视图思路方法建立视图后要先保存视图定义再打开视图后视图中才有数据因此必须将Creat
sql view语句部分代码修改如下:
************************************************
Create sql view tempview as &sqlstatement
use
use tempview
************************************************
满以为这下问题解决了结果更惨出现表格上不但没有数据连表头、网格都不见了!这个问题
百思不得其解查找资料也没有结果最后不了了的直困扰了我几个月
就在昨晚我上床时候突然灵光现:既然表格无法动态加载数据源视图那么干脆连包含表格
表单也动态生成!只要表单动态生成那么表单上表格对象数据源不就完全重新加载了吗?也用不着
刷新什么了!而且用这个思路方法也用不着先建立个tempview视图完全在中动态生成就可以了
主意定马上下床动手将原来包含表格表单form1删除在上述代码中最后句
thisform.form1.show前插入以下代码:
*************************************************************
thisform.addobject(\"form1\",\"form\")
with thisform.form1
.caption=\"查询结果\"
.width=600
.height=400
.Autocenter=.t.
.controlbox=.f.
endwith
thisform.form1.addobject(\"cmdReturn1\",\"cmdReturn\")
with thisform.form1.cmdReturn1
.top=360
.left=270
endwith
thisform.form1.addobject(\"grid1\",\"gird\")
with thisform.form1.grid1
.Recordsourcetype=1
.Recordsource=\"tempview\"
.top=10
.left=20
.height=300
.width=560
endwith
**************************************************************
在最后加入:
*********************************************
Define cmdReturn as commandbutton
caption=\"返回\"
procdure click
thisform.release
endproc
end
*********************************************
这下总可以了吧?运行结果出现对话框\"在事件或思路方法中不能嵌套类定义!\"我@#$%&*....什
么嘛!教科书、帮助文件中举例prg都是这么写啊!
不过好在还有办法我手工建立个类总行了吧!
在类库mybut中新建个按钮类cmdReturn设置它cation属性为\"返回\"click事件代码为
thisform.release在上面代码前插入 Classlib to mybut additive(注意:如果不加additive参
数将关闭所有的前打开类库!)然后将最后类定义语句Define...EndDefine全部删除
运行新表单出现!且慢这个表单上如何什么东西都没有?:-((
打开调试器在\"局部\"窗口中察看发现明明有cmdReturn1、Grid1对象啊!如何回事?仔细察看他
们每个属性发现原来它们visible属性都为false!
原来我们平常看到帮助中举例都是prg文件在这些文件中用addobject思路方法向表单添加对
象在显示表单后都是可见而在表单scx文件中使用addobject思路方法建立任何东西其visible属
性都为false!
本质上用createobject、addobject思路方法建立对象其实只是在内存中建立了个对象变量
必须再用语句使它们例子化比如我们常用form.show语句就是如此没有使用show思路方法
form就只是内存中个变量而不是个表单不可见例子!反的,thisform.release语句则从根本
上释放了表单上所有对象变量,从而在内存中完全清除了表单.
而在prg文件中和scx文件中用addobject思路方法建立表单和Control控件顺序是不样在prg文件中是先
向表单添加Control控件再显示表单表单上Control控件继承了表单visible属性当表单例子化时Control控件也例子化;
而在scx文件使用addobject思路方法是先显示表单然后再向表单添加Control控件因此必须手工设置Control控件
visible属性为Ture
当然这样比较麻烦干脆在mybut类库中手工建立个Resultform表单类在该表单类上添加个命
令按钮cmdReturn和个Grid1,设置命令按钮cmdReturncaption属性为\"返回\"Click事件代码为
thisform.release,设置Grid1RecordSourceType属性为1-别名RecordSource属性为Tempview这样就
不用在代码中手工输入thisform.form1.cmdReturn1.visible=.t.语句省事多了
最终代码如下:
*******************************************************
database to databasename
used(\"tempview\")
rename view tempview to oldview
delete view oldview
end
Create sql view tempview as &sqlstatement
=requery
IF _TALLY = 0
#DEFINE MSG_LOC \"没有找到符合条件纪录!\"
#DEFINE TITLE_LOC \"没有找到纪录\"
=MESSAGEBOX(MSG_LOC,64+0+0,TITLE_LOC)
ELSE
Classlib to mybut additive
thisform.addobject(\"form1\",\"Resultform\")
thisform.hide
thisform.form1.show
End
********************************************************
运行切ok!终于实现了动态生成查询条件动态显示结果只要再用dbprop语句设置视
图为可更新就能对查询结果进行修改/更新了!这是个人所见到过最完美复合查询了!
就这么简单?没错就这么简单!个困扰数月问题研究时候峰回路转最终结果却是如此轻
松!这就是编程艺术吧!
这个问题解决虽然走了许多弯路但是也让我们了解了许多VFP原理难道不是很值得吗?!光
凭书本知识你永远也无法了解这些东西有人说:读 3年书还不如写个月不是吗?!
其他:
我在本文中省略了开头动态生成sql语句部分具体做法大家可以研究下VFP自带举例应用
solution中databases目录下view/queries目录中Interactively Bulid a sql statement举例
你甚至可以稍作修改就在你自己中使用该表单
我曾经就其原理写了篇文章交互式建立sql复合查询-vfp举例应用详解贴在网易虚拟社区
VFP版有兴趣朋友可以在精华区查到,读完该篇文章你应该可以自行修改该使的能够对对多数
据库进行查询了该文篇幅很长又比较枯燥就不在这儿解说了
要注意是:原举例用于生成sql语句查询要改为用于建立sql视图必须作些修改:
1、在sql查询中不必限定表别名和数据库名而建立sql视图却必须这样做因此需要修改makesql表单
自定义思路方法bldsql代码将源代码下面部分:
**************************************************************************
IF !EMPTY(lcOperand)
lcValue2 = THISFORM.ValidateType(THIS.cboField2.Value,lcValue2)
lcWHERE = lcOperand + \" \" + lcField2 + \" \" + ;
lcRelation2 + \" \" + lcValue2
ENDIF
** Create the first part of the WHERE condition
lcWHERE = \"WHERE \" + lcField1 + \" \" + lcRelation1 + \" \" + lcValue1 + \" \" + lcWHERE
** Create the full SQL command using the base table for the form
lcSQL = \"SELECT * FROM \" + lcAlias + \" \" + lcWHERE
****************************************************************************
修改为:
****************************************************************************
If !empty(lcOperand)
lcValue2 = thisform.ValidateType(this.cboField2.value,lcValue2)
lcWhere = lcOperand + \" \" + lcAlias + \".\" + lcField2 + \" \" +;
lcRelation2 + \" \" +lcValue2
End
lcWhere = \"Where \"+ lcAlias + \".\" + lcField1 + lcRelation1 + \" \";
+ lcValue1 + \" \" + lcWhere
lcSql = \"Select * From \" + \"DatabaseName!\" + lcAlias + \" \" + lcWhere
****************************************************************************
DatabaseName是你数据库名字以上修改实质是给要查询字段名限定其所在表别名给
select form表别名限定所属数据库
2、修改RunSql命令按钮Click事件代码将原代码:
*************************************************************************
cMacro = ALLTRIM(THISFORM.edtSQL.Value) + \"INTO CURSOR TEMPQUERY\"
*************************************************************************
中 (+ \"INTO CURSOR TEMPQUERY\")部分删除将cMacro改为sqlstatement.并将除了下面部分外全
部代码删除:
*************************
IF USED(lcOldAlias)
SELECT (lcOldAlias)
ENDIF
*************************
插入上面最终代码就可以了
ok!现在所有任务都完成了做完所有这切花不了十分钟你就建立了个强大复合查询!
最新评论