用vfp与sql server构建Client/Server应用程序(SPT)(2)2007-05-09把数据集设为可更新Visual FoxPro的光标类型光标的英文称呼是Cursor,在Visual FoxPro中习惯的提法是临时表(Temp Table),不过我想应该根据惯例叫它光标。因为Visual FoxPro的光标绝对强劲,如果称呼Temp Table恐造成误会,好像Visual FoxPro不支持光标一样。Visual FoxPro的光标有三种:只读光标、可读写光标、可更新光标。只读光标是那种不能被修改的光标,在Visual FoxPro中使用SQL-Select语句产生的光标就是典型的只读光标:SELECT * FROM ORDERS INTO CURSOR MYCURSOR对于结果集合MyCursor来说我们不能对它执行任何写操作,如:Replace、Delete、Update等。可读写光标是那种可以进行读写操作,但光标上的数据变更不被反映到数据源的光标:典型的可读写光标有三类,其一就是用SQLEXEC()得到的光标,我们可以对它进行各种操作(从了Zap、Pack这样的表压缩命令),但是任何数据的变动都不会反映到数据源。第二类可读写光标是Visual FoxPro 7 的新特性,我们在SQL-Select语句上加入关键字readwrite就可以得到这种光标。这是一个非常棒的特性,有了它在Visual FoxPro中操作中间结果就更自由了:SELECT * FROM ORDERS INTO CURSOR MYCURSOR READWRITE第三类可读写光标是“没有设置发送更新”的本地视图和远程视图。记得我在“远程视图”一章里反复强调:要想视图是可更新的就必须设定它的SendUpdate属性为.t.,如果没有设,试图就是可读写光标了,任何对视图数据的操作都不能反映到数据源里了。可更新光标是那种可以进行读写操作,并且任何数据变动都会反映到数据源的光标:典型的可更新光标就是可更新视图,对它的好处我就不多加议论了,因为详细的内容在“远程视图”一章里已经讨论过了。把SQLEXEC()得到的结果集设定为可更新光标的五大步骤在“远程视图”一章里我就反复强调,Visual FoxPro是怎么产生语句SQL描述,发送到SQL Server中去的。大家可以想象配置一条SQL-Update或是SQL-Insert或是SQL-Delete需要的要素,怎样把客户端变动转化为SQL语句需要的东西,就是我们要设定的东西:A.CURSORSETPROP("TABLES",数据源表名,可更新光标名)此步骤设定的是数据源里(SQL Server)待更新的表名,如果涉及多个表就这样写:CURSORSETPROP("TABLES","T1,T2","MyCursor")。B.CURSORSETPROP("KEYFIELDLIST",关键字段,可更新光标名)此步骤是设定关键字段的,这个关键字段是这可更新光标的字段,而不是数据源里字段。C.CURSORSETPROP("UPDATABLEFIELDLIST",可更新字段列表,可更新光标名)此步骤设定的是在可更新光标里哪些字段的变动要被反映到数据源,即哪些字段时可更新的。D.CURSORSETPROP("UPDATENAMELIST",前后段字段对应关系列表,可更新光标名)此步骤设定前后端字段的对应关系。E.CURSORSETPROP("SENDUPDATES",.T.,可更新光标名)这个步骤就不应多说了,最关键的一步,不做的话前面的努力都白搭。下面我用三个实例来说明问题:例一:cnn=SQLCONNECT("northwind")
SQLEXEC(cnn,"select categoryid as id ,categoryname,description from categories","mycursor")
SELECT mycursor
CURSORSETPROP("Tables","categories","mycursor")
CURSORSETPROP("KeyFieldList","id","mycursor")
CURSORSETPROP("UpdatableFieldList" ,"id,categoryname,description","mycursor")
CURSORSETPROP("UpdateNameList","id categories.categoryid,categoryname categories.categoryname,"+;
"description categories.description","mycursor")
CURSORSETPROP("SendUpdates" ,.t.,"mycursor")
- 数据源表是 NorthWind 数据库的Categories 表,可更新光表是mycursor
- CURSORSETPROP("Tables","categories","mycursor"),TABLES属性设定的是:被更新的数据源表Gategories
- CURSORSETPROP("KeyFieldList","id","mycursor"),关键字用可更新光标的字段名:ID,而不是数据源表的字段名:categoryid
- CURSORSETPROP("UpdatableFieldList" ,"id,categoryname,description","mycursor"),可更新字段列表都用可更新光标的字段名表示,而不是数据源表的字段名。
- CURSORSETPROP("UpdateNameList","id categories.categoryid,categoryname categories.categoryname,description categories.description","mycursor"),请注意这里的写法:每一组对应关系用逗号分开,前面写可更新光标的字段名,再放置一个空格,接着写数据源表的字段名(注意一定要加上数据源表名称)
例二cnn=SQLCONNECT("northwind")
SQLEXEC(cnn,"select a.productid,a.productname,a.unitprice,b.categoryid,b.categoryname,c.supplierid,"+;
"c.companyname as suppliername,c.contactname"+;
" from (products a inner join categories b on a.categoryid=b.categoryid)"+;
" inner join suppliers c on a.supplierid=c.supplierid","mycursor")
SELECT mycursor
CURSORSETPROP("Tables","products,categories,suppliers","mycursor")
CURSORSETPROP("KeyFieldList","productid,categoryid,supplierid","mycursor")
CURSORSETPROP("UpdatableFieldList",+;????????????????????? "productid,productname,unitprice,categoryid,categoryname,supplierid,suppliername,contactname","mycursor")
CURSORSETPROP("UpdateNameList","productid products.productid,productname ,"+;
"products.productname,unitprice products.unitprice,"+;
"categoryid categories.categoryid,categoryname categories.categoryname,"+;
"supplierid suppliers.supplierid,suppliername suppliers.companyname,contactname suppliers.contactname","mycursor")
CURSORSETPROP("SendUpdates" ,.t.,"mycursor")
- 这是一个三个表(Categories,Products,Suppliers)的连接结果集合,算是复杂了,我们的目标就是使所有的字段都能更新到相应的表中。
- 注意“Tables”属性的写法,涉及三个表就罗列三个表!
- 注意“KeyFieldList”属性的写法,三个表的关键字都要列上。如果你没有把supplierid了如的话,那么来自于suppliers表的字段就无法更新到suppliers表中了。
例三cnn=SQLCONNECT("northwind")
SQLEXEC(cnn,"select orderid,productid,unitprice,quantity,discount from [order details]","mycursor")
SELECT mycursor
CURSORSETPROP("Tables","[order details]","mycursor")
CURSORSETPROP("KeyFieldList","orderid,productid","mycursor")
CURSORSETPROP("UpdatableFieldList" ,"orderid,unitprice,quantity,discount","mycursor")
CURSORSETPROP("UpdateNameList","orderid [order details].orderid,unitprice [order details].unitprice,quantity [order details].quantity,discount [order details].discount","mycursor")
CURSORSETPROP("SendUpdates" ,.t.,"mycursor")
- 这个结果集来自于一个表:Order Details。
- 注意“Tables”属性的写法,在SQL Server中这种带空格的表名请用方口号分隔,Tables属性指定的是数据源表,所以必须用:[order details]填入。
- 注意“KeyFieldList”属性的写法,这个order details表的主关键字是一个复合关键字,有orderid与productid联合组成,所以这里就要将他们一起填入。
一个很重要的属性——WhereType当我们设定结果集为可更新光标后,还有一个重要的属性没有设定,就是WhereType。即,Where字句产生的依据,有四种情况:CURSORSETPROP("WhereType" ,1) &&根据关键字
CURSORSETPROP("WhereType" ,2) &&根据关键字+可更新字段
CURSORSETPROP("WhereType" ,3) &&根据关键字+已更新字段
CURSORSETPROP("WhereType" ,4) &&根据关键字+时间戳更详细的内容大家可以参看“远程视图”章节,在那里面我已经讲得很多了。