VFP+SQL編程方法討論與經驗分享

VFP是一個簡單實用的編程工具,但數據庫一般用其本身的DBF數據庫,對於SQL可能每個人都用不同的看法,各位高手有什麼好的方法、經驗、建議全都拿出來,供大家分享,謝謝!  
   
  以下是我平時對SQL的使用點滴,歡迎各位指點!  
   
  **************************************************************  
  *--   vfpsql  
  *--   parameters   :tcDatabase,tcServer,tcUserId,tcPassword  
  *--   Sql   Connect  
  **************************************************************  
  FUNCTION   VFPSql()  
  PARAMETERS   tcDatabase,tcServer,tcUserId,tcPassword  
   
  SET   MULTILOCKS   ON    
   
  LOCAL   lcSqlConnectStr  
  PUBLIC   gcSqlConnectstr  
  IF   TYPE("gcSqlConnectstr")<>"C"  
  gcSqlConnectstr   =   ""  
  ENDIF    
  lcSqlConnectStr   =''  
   
  IF   TYPE("_gnSqlConnectHandle")   =   "N"   AND   _gnSqlConnectHandle   >   0  
  disVFPSql()  
  ENDIF    
  PUBLIC   _gnSqlConnectHandle  
  _gnSqlConnectHandle   =0  
  IF   PARAMETERS()>=3   AND   VARTYPE(tcDatabase)='C'   AND   VARTYPE(tcServer)='C'   AND   VARTYPE(tcUserId)='C'  
  IF   EMPTY(tcPassword)  
  tcPassword   =   ''  
  ENDIF    
  lcSqlConnectStr   ="driver={Sql   Server};Database=&tcDatabase;server=&tcServer;uid=&tcUserId;pwd=&tcPassword"  
  _gnSqlConnectHandle   =   SQLSTRINGCONNECT(lcSqlConnectStr)  
  ELSE  
  IF   gcSqlConnectstr   <>   ""  
  lcSqlConnectStr   =   gcSqlConnectstr  
  _gnSqlConnectHandle   =   SQLSTRINGCONNECT(lcSqlConnectStr)  
  ENDIF    
  ENDIF    
  gcSqlConnectstr   =   lcSqlConnectStr  
  LOCAL   iLoopCount  
  iLoopCount   =   1  
  DO   WHILE   _gnSqlConnectHandle   <=   0   AND   iLoopCount   <=3  
  DO   prgDataConnect  
  iLoopCount   =   iLoopCount   +   1  
  ENDDO    
  RETURN   _gnSqlConnectHandle>0  
  *-   VFPSQL   END  
   
  ************************************************  
  *--       disVFPSql()  
  *--       Sql   Disconnect  
  ************************************************  
   
  FUNCTION   disVFPSql()  
  IF   TYPE("_gnSqlConnectHandle")<>'N'   OR   _gnSqlConnectHandle<=0  
  Return  
  ENDIF  
  SQLDISCONNECT(_gnSqlConnectHandle)  
  RELEASE   _gnSqlConnectHandle  
  RETURN  
  *-   DisVFPSql   END  
   
  ***************************************  
  *--   SqlDo()  
  *--   PARAMETERS   tcSqlString:   查詢語句  
  *-- tcCurName   :   結果集存放表  
  *-   功能:   執行查詢  
  **************************************  
  FUNCTION   SqlDo  
  LPARAMETERS   tcSqlString,tcCurName  
  LOCAL   lnReturn  
   
  *--   檢查連接  
  IF   TYPE("_gnSqlConnectHandle")<>"N"   or   _gnSqlConnectHandle<=0  
  IF   !vfpsql()  
  *--   連接失敗,返回   0  
  RETURN   0  
  ENDIF    
  ENDIF  
  IF   TYPE('tcSqlString')<>'C'   OR   EMPTY(tcSqlString)  
  RETURN   0  
  ENDIF  
  IF   EMPTY(tcCurName)   OR   TYPE("tcCurName")   <>'C'  
  lnReturn   =   SQLEXEC(_gnSqlConnectHandle,tcSqlString)  
  ELSE  
  lnReturn   =   SQLEXEC(_gnSqlConnectHandle,tcSqlString,tcCurName)  
  ENDIF  
  RETURN   lnReturn  
  *-   SqlDo   END  
   
   
  *--   Opendb  
  ********************************************************  
  *--   OpenDB  
  *  
  *-   功能:打開table   Or   View  
  *  
  *-參數說明   tcCurName       :   臨時表名  
  *-                   tcSqlTblName:   Sql數據表名(默認tcCurName)  
  *       tcFldsList       :   字段列表(默認爲全部   *)  
  **********************************************************  
  FUNCTION   OpenDB  
  LPARAMETERS   tcCurName,tcSqlTblName,tcFldsList  
  IF   VARTYPE(tcCurName)<>"C"  
  MESSAGEBOX("參數錯誤,不能打開數據表或視圖!",48,"錯誤")  
  RETURN   .F.  
  ENDIF    
  IF   EMPTY(tcSqlTblName)  
  tcSqlTblName   =   tcCurName  
  ENDIF    
  IF   EMPTY(tcFldsList)  
  tcFldsList   =   "*"  
  ENDIF  
  *--   執行查詢  
  lnReturn   =   Sqldo("select   &tcFldsList   From   &tcSqlTblName   ","&tcCurName.")  
  *--   打開開放式表緩衝  
  IF   lnReturn   >   0  
  cursorsetprop("buffering",5,   "&tcCurName.")  
  ENDIF    
  RETURN   lnReturn>0  
  *--   OpenDB   END  
   
   
  ********************************************************  
  *--   CloseDB  
  *  
  *-   功能:關閉table   Or   View  
  *  
  *-參數說明   tcCurName       :   臨時表名  
  *-  
  **********************************************************  
  FUNCTION   CloseDB  
  LPARAMETERS   tcCurName  
  IF   VARTYPE(tcCurName)<>"C"  
  MESSAGEBOX("參數錯誤,非法數據表或視圖!",48,"錯誤")  
  RETURN   .F.  
  ENDIF    
   
  IF   SELECT(tcCurName)   >   0  
  USE   IN   &tcCurName  
  ENDIF  
  RETURN   .T.  
  *--   CloseDB   END  
   
   
   
  **********************************************************************  
  *-   SaveData  
  *--    
  *--   參數說明   tcCurName       :   臨時表名  
  *--                   tcSqlTblName:   Sql數據表名(默認tcCurName)  
  *--       tcKeyFld       :   關鍵字段名稱(一定要有,否則默認爲ID),  
  *--   程序要根據該字段來定位記錄,  
  *--   功能:從臨時表保存到   SQL數據庫中,注意,臨時表要啓用緩衝模式  
  **********************************************************************  
  FUNCTION   savedata  
  LPARAMETERS   tcCurName,tcSqlTblName,tcKeyFld  
  LOCAL   lcFldList,lcFldListTmp,lnNextModifyRec,lcFldValue,lnFldCnt  
  LOCAL   lcSqlString,lnSqlReturn  
  LOCAL   lcOldAlias,lcOldDele,lcOldSafe  
  LOCAL   laFlds(1)  
  LOCAL     i,llNeedAddDH  
   
  IF   TYPE("tcCurName")<>'C'   OR   ;  
  EMPTY(tcCurName)   OR   ;  
  SELECT(tcCurName)=0  
  MESSAGEBOX("表名錯誤!",48,"錯誤提示")  
  RETURN  
  ENDIF  
  lcOldDele   =   SET("Deleted")  
  lcOldSafe   =   SET("Safety")  
  SET   DELETED   OFF    
  SET   SAFETY   OFF    
  lcOldAlias   =   ALIAS()  
   
  SELECT   (tcCurName)  
  IF   cursorgetprop('buffering')=1  
  MESSAGEBOX("數據表沒有啓用緩衝模式,程序無法識別!",48,"錯誤提示")  
  RETURN   .F.  
  ENDIF  
  IF   EMPTY(tcSqlTblName)   OR   TYPE("tcSqlTblName")<>'C'  
  tcSqlTblName   =   tcCurName  
  ENDIF  
  IF   EMPTY(tcKeyFld)  
  tcKeyFld   =   'Id'  
  ENDIF    
   
  lnFldCnt   =   AFIELDS(laFlds)  
  lcFldList   =   ''  
  FOR   i   =   1   TO   lnFldCnt  
  IF   !EMPTY(lcFldList)  
  lcFldList   =   lcFldList   +','  
  ENDIF  
  lcFldList   =   lcFldList   +   laFlds(i,1)  
  ENDFOR  
  lnNextModifyRec   =   GETNEXTMODIFIED(0)  
  lnSqlReturn   =   SQLDO("BEGIN   TRANSACTION")  
  IF   lnSqlReturn   =-1  
  RETURN   .F.  
  ENDIF  
   
  DO   WHILE   lnNextModifyRec   <>0  
  GO   lnNextModifyRec  
  lcFldListtmp   =   ''  
  lcSqlString   =   ''  
  DO   case  
  CASE   DELETED() &&刪除  
  lcSqlString   =   "Delete   From   "+tcSqlTblName   +   IIF(TYPE(tcKeyFld)   $   "NI",;  
  "   Where   &tcKeyFld.   =   "+TRANSFORM(EVALUATE(tcCurName+".&tcKeyFld.")),;  
  "   Where   &tcKeyFld.   =   '"+TRANSFORM(EVALUATE(tcCurName+".&tcKeyFld."))+"'")  
   
  CASE   RECNO()<0     &&新增  
  lcSqlString   =   ""   &&"insert   into   "+tcSqlTblName   +"   ("+lcFldList+")   Values   ("  
  FOR   i   =   1   TO   lnFldCnt  
  lcFldValue   =   EVALUATE(tcCurName+'.'+laFlds(i,1))  
  IF   EMPTY(lcFldValue)  
  Loop  
  ENDIF  
  IF   !EMPTY(lcFldListtmp)  
  lcFldListtmp   =   lcFldListtmp   +','  
  ENDIF  
  lcFldListtmp   =   lcFldListtmp   +   laFlds(i,1)  
  DO   case  
  CASE   laFlds(i,2)$'NI'  
  lcFldValue   =   TRANSFORM(lcFldValue)  
  CASE   laFlds(i,2)='L'  
  IF   lcFldValue  
  lcfldValue   =   '1'  
  ELSE  
  lcfldValue   =   '0'  
  ENDIF  
   
  OTHERWISE  
  lcFldValue   ="'"+   TRANSFORM(lcFldValue)+"'"  
  ENDCASE  
  IF   !EMPTY(lcSqlString)  
  lcSqlString   =lcSqlString   +','  
  ENDIF  
  lcSqlString   =lcSqlString   +   lcFldValue  
  ENDFOR  
  lcSqlString   ="insert   into   "+tcSqlTblName   +"   ("+lcFldListtmp+")   Values   ("+lcSqlString   +')'  
  OTHERWISE  
  lcSqlString   =   "Update   "+tcSqlTblName   +"   set   "  
  llNeedAddDH   =   .F.  
  FOR   i   =   1   TO   lnFldCnt  
  IF   GETFLDSTATE(i)<>2  
  LOOP  
  ENDIF  
  DO   case  
  CASE   laFlds(i,2)$'NI'  
  lcFldValue   =   laflds(i,1)+'='+TRANSFORM(EVALUATE(tcCurName+'.'+laFlds(i,1)))  
  CASE   laFlds(i,2)='L'  
  IF   EVALUATE(tcCursorName+'.'+laFlds(i,1))  
  lcfldValue   =   laflds(i,1)+'=1'  
  ELSE  
  lcfldValue   =   laflds(i,1)+'=0'  
  ENDIF  
  OTHERWISE  
  lcFldValue   =laflds(i,1)+"   =   '"+   TRANSFORM( EVALUATE(tcCurName+'.'+laFlds(i,1)))+"'"  
  ENDCASE  
  IF   NOT   llNeedAddDH    
  llNeedAddDH   =   .T.  
  Else  
  lcSqlString   =lcSqlString   +','  
  ENDIF  
  lcSqlString   =lcSqlString   +   lcFldValue  
  ENDFOR  
  lcSqlString   =lcSqlString   +   IIF(TYPE(tcKeyFld)   $   "NI",;  
  "   Where   &tcKeyFld.   =   "+TRANSFORM(EVALUATE(tcCurName+".&tcKeyFld.")),;  
  "   Where   &tcKeyFld.   =   '"+TRANSFORM(EVALUATE(tcCurName+".&tcKeyFld."))+"'")  
  ENDCASE  
   
  lnSqlReturn   =   sqlDo(lcSqlString)  
  IF   lnSqlReturn=-1  
  SQLDO("Rollback")  
  MESSAGEBOX("保存失敗!"+CHR(13)+CHR(10)+lcSqlString)  
  _cliptext   =   lcSqlstring  
  TABLEREVERT(.T.)  
  RETURN   .F.  
  ENDIF  
  lnNextModifyRec   =   GETNEXTMODIFIED(lnNextModifyRec)  
  ENDDO  
  lnSqlReturn   =   SQLDO("   COMMIT   TRANSACTION   ")  
  TABLEUPDATE(.T.)  
  IF   !EMPTY(lcOldAlias)   AND   ALIAS()<>lcOldAlias  
  SELECT   (lcOldAlias)  
  ENDIF  
  IF   lcOldDele='ON'  
  SET   DELETED   on  
  ENDIF  
  IF   lcOldSafe   =   'ON'  
  SET   SAFETY   on  
  ENDIF  
  RETURN   .T.   
   *--   調用SQL設置  
  PROCEDURE   prgdataconnect  
  LOCAL   lcDataPath,lcTextString  
  LOCAL   loForm  
  _gnSqlConnectHandle   =   0  
  IF   _gnSqlConnectHandle   <=0  
  loFormCon   =   CREATEOBJECT("fmConnect")  
  loFormCon.Show(1)  
  ENDIF  
  **********************************************  
  *-   定義連接表單  
  *********************************************  
  DEFINE   CLASS   fmConnect   as   Form  
    &&-"driver={Sql   Server};Database=Hjasset;server=jianqy;uid=sa;pwd=")  
  Caption   =   'SQL服務器連接'  
  Width   =   300  
  Height   =   182  
  BorderStyle   =   2  
  maxbutton   =   .F.  
  minButton   =   .F.  
  ShowWindow   =   1  
  Autocenter   =   .T.  
  alwaysontop   =   .T.  
  desktop   =   .T.  
  windowType   =   1  
  Name   =   'fmConnect'  
  ADD   OBJECT   lblServer   as   label   WITH   Caption   =   '服務器:',;  
        left   =   15,;  
        Width   =   80,;  
        Top   =   20,;  
        Height=   22,;  
        Alignment   =   1,;  
        BackStyle   =   0,;  
        Visible   =   .T.  
         
  ADD   OBJECT   txtServer   as   textbox   WITH   left   =   95,;  
            Width   =   160,;  
            Top   =   17,;  
          Height=   25,;  
          Value   =   '(Local)',;  
        Visible   =   .T.  
  ADD   OBJECT   lblDatabase   as   label   WITH   Caption   =   '數據庫:',;  
        left   =   15,;  
        Width   =   80,;  
        Top   =   50,;  
        Height=   22,;  
        Alignment   =   1,;  
        BackStyle   =   0,;  
        Visible   =   .T.  
  ADD   OBJECT   txtDatabase   as   textbox   WITH   left   =   95,;  
            Width   =   160,;  
            Top   =   47,;  
          Height=   22,;  
          Value   =   'pubs' ,;  
        Visible   =   .T.  
         
  ADD   OBJECT   lblUid   as   label   WITH   Caption   =   '用戶名:',;  
        left   =   15,;  
        Width   =   80,;  
        Top   =   80,;  
        Height=   22,;  
        Alignment   =   1,;  
        BackStyle   =   0,;  
        Visible   =   .T.  
  ADD   OBJECT   txtUid   as   textbox   WITH   left   =   95,;  
        Width   =   160,;  
        Top   =   77,;  
        Height=   22,;  
        Value   =   'sa' ,;  
        Visible   =   .T.  
  ADD   OBJECT   lblPwd   as   label   WITH   Caption   =   '密   碼:',;  
        left   =   15,;  
        Width   =   80,;  
        Top   =   110,;  
        Height=   22,;  
        Alignment   =   1,;  
        BackStyle   =   0,;  
        Visible   =   .T.  
  ADD   OBJECT   txtPwd   as   textbox   WITH   left   =   95,;  
            Width   =   160,;  
            Top   =   107,;  
          Height=   22,;  
          passwordchar=   '*',;  
          Value   =   '' ,;  
        Visible   =   .T.  
  ADD   OBJECT   btnConnect   as   Commandbutton   WITH   left   =   35,;  
            Width   =   100,;  
            Top   =   150,;  
          Height=   22,;  
          Value   =   '' ,;  
        Visible   =   .T.,;  
        Caption   =   '連   接'  
  ADD   OBJECT   btnCancel   as   Commandbutton   WITH   left   =   165,;  
            Width   =   100,;  
            Top   =   150,;  
          Height=   22,;  
          Value   =   '' ,;  
        Visible   =   .T.,;  
        Caption   =   '取   消'  
  ADD   OBJECT   cntShp1   as   Container   WITH   left   =   0,;  
            Width   =   300,;  
            Top   =   142,;  
          Height=   1,;  
        Visible   =   .T.,;  
        SpecialEffect   =   1        
  PROCEDURE   destroy  
   
  PROCEDURE   load  
   
  PROCEDURE   init  
   
  PROCEDURE   txtPwd.Keypress  
  LPARAMETERS   nKeyCode,   nShiftAltCtrl  
  IF   nKeyCode   =   3   OR   nKeyCode   =   24  
  NODEFAULT  
  ENDIF    
  PROCEDURE   btnConnect.click  
  LOCAL   lcServer,lcDatabase,lcUid,lcPwd,lcSqlStrConnect  
  lcServer   =   ALLTRIM(thisform.txtServer.Value)  
  lcDatabase   =   ALLTRIM(thisform.txtDatabase.Value)  
  lcUid   =   ALLTRIM(thisform.txtUid.Value)  
  lcPwd   =   ALLTRIM(thisform.txtPwd.Value)  
  IF   EMPTY(lcServer)  
  MESSAGEBOX("請輸入SQL服務器的名稱!",48,"系統提示")  
  thisform.txtServer.setfocus  
  RETURN  
  ENDIF  
  lcSqlStrConnect="driver={Sql   Server};"+;  
  IIF(EMPTY(lcDatabase),'',"Database="+lcDatabase+";")+;  
  "server="+lcServer+";uid="+lcUid+";pwd="+lcPwd  
  _gnSqlConnectHandle   =   SQLSTRINGCONNECT(lcSqlStrConnect)  
  gcSqlConnectstr   =   lcSqlStrConnect  
  ON   ERROR    
  IF   _gnSqlConnectHandle   >   0  
  MESSAGEBOX("連接成功!",64,"SQL連接")  
  thisform.Release    
  ELSE  
  MESSAGEBOX("連接失敗!"+CHR(13)+CHR(10)+"請重新輸入連接項",64,"SQL連接")  
  thisform.txtServer.setfocus  
  ENDIF  
  PROCEDURE   btnCancel.click  
  thisform.Release    
  ENDDEFINE  
*--   以pubs   爲例  
  &&連接SQL  
  vfpsql()  
  &&打開authors  
  opendb("authors")  
  &&修改  
  repl   au_lname   with   'dfjkdjfkdj'   for   au_id   =   '722-51-5454'  
  &&保存到SQL  
  savedata("authors","authors","au_id")  

****************************************************************

9 樓westbulls(westbulls)回覆於 2005-07-07 10:37:06 得分 30

一、採用ado方式,可能代碼會很多,但是會很靈活,而且可以讓前臺沒有dbc文件了,如果採用遠程視圖方式,就不會寫這麼多代碼了,但是必須要定義DBC(數據庫)用於保存遠程視圖及連接等,前一種方式,樓主已經寫的比較通俗簡明瞭,我對後一種簡單補充一下。  
  1.建立數據庫,然後建立與後臺數據庫的連接(當然可以用INI文件等先保存定義,然後動態設定)  
  2.建立遠程視圖表  
  3.打開表同時設置表的緩衝級別,一般爲行緩衝和表緩衝  
  4.修改後如果保存=tableupdate(.t.),放棄=tablerevert(.t.)  
  5.可以通過捕獲返回的錯誤信息,顯示給用戶.如  
  IF   TABLEUPDATE(.T.)  
  =MESSAGEBOX("更新完畢!",48,"系統信息")  
  ELSE  
  =AERROR(ERR)  
  IF   !EMPTY(ERR(2))  
  =SHOWWARN("錯誤信息:"+ALLTRIM(SUBSTR(UPPER(ERR(2)),AT('[SQL   SERVER]',UPPER(ERR(2)),1)+12)))  
  ENDIF  
  XX=SHOWCHOICE("是否取消此次操作?")  
  IF   XX=1  
  =TABLEREVERT(.T.)  
  ELSE  
  RETURN  
  ENDIF  
  ENDIF  
  =REQUERY()  
  二、當然了,現在最好使用的還是CursorAdapter方式,它即有了ado方式的靈活,又有了遠程視圖的簡易,還有了後臺升級方便等優點。具體使用請參考網上的一些說明,在些從簡了。  

13 樓cxmcxm(小陳)回覆於 2005-07-09 23:00:39 得分 10

用遠視圖.或vfp中提供的odbc方法,  
  如果用ado,最好用CursorAdapter.  
  不用直接用createobject創建ado對象,因爲vfp不能直接支持ado的recordset,只能自增麻煩.  
   
  就我的體驗,遠程視圖,cursoradapter中,odbc或ado的遊標已被轉爲vfp的臨時表,我們在vfp操作  
  轉化來臨時表,用vfp提供的命令對臨時表更新時,vfp內部再更新相應的odbc或ado遊標.因爲多了一層,所以有自增列的表添加記錄時,自增列的值在vfp中看不到,需requery後才能看到.  
回覆人:   westbulls(westbulls)   (   )   信譽:100     2005-07-17   21:29:00     得分:   0      
     
     
        TO   Hewiit(糊塗):  
  我的SQL的數據庫的記錄數有好幾百萬,在VFP中查詢都經常超時,有沒有什麼好的法子?  
   
  其實表結構的設計是否合理是最主要的關鍵,還有索引的運用及查詢條件的設置,都會加快運行速度,總之,要具體問題具體分析纔可以.  
   
  另外,發現使用9.0中的VARCHAR時,控件的MAXLENGTH就不可用了,而且如果你第一次存儲的數據長度定了後,第二次錄入到第一次長度後,光標會自動跳走,所以我暫時不打算用VARCHAR了.  
    -----------------------------------------------  
  非常感謝!!!!!!!!!!    
29 樓trainee(春泥)回覆於 2005-07-23 10:25:15 得分 25

CURSORADAPTER(故名思義:叫CURSOR的裝配器)  
  CURSORADAPTER和SPT生成的CURSOR是一樣的,  
  SPT生成的CURSOR也可通過CURSORSETPROP語句變成可更新的CURSOR  
  SPT生成的CURSOR可以通過CURSORADAPTER中的CURSORATTACH方法裝配到CURSORADAPTER中  
  CURSORADAPTER中生成的CURSOR也可以通過的CURSORDETACH方法遊離出來。  
  CURSORADAPTER技術比SPT擴展了,能處理AOD和XML,並增加了些事件,並可以自行改寫在TABLEUPDATE時由系統自動生成的SQL語句。  
  直到VFP9.0,兩者才增加了SQLROWCOUNT功能,即能返回UPDATE或DELETE語句所影響的行數。

32 樓trainee(春泥)回覆於 2005-07-25 10:49:42 得分 5

TO   Hewiit(糊塗):  
  ---------------------------------------------------------------------  
  爲知道sql中怎麼去鎖定一條記錄或者一個表,像lock(),rlock()這些命令?  
  ---------------------------------------------------------------------  
  在服務器型數據庫裏是沒有以上命令的,各種數據庫都有相應的鎖的SQL語句  
  爲了保證併發性,儘可能減少從加瑣到解鎖之間的時間,中間不能有任何交互型的語句。  
  一般採取緩衝比較技術  
  比如修改表中的某一記錄,以下的流程  
  SELECT   *   FROM   MYTABLE   WHERE   KEY=SOME  
    ---   進行交互型修改,中間你可以上廁所、吃飯等  
  開始提交時:  
  1。先加鎖  
      BEGIN   TRANSACTION  
      LOCK   TABLE   MYTABLE  
  2、比較是否被更改  
      A、SELECT   *   FROM   MYTABLE   WHERE   KEY=SOME  
            IF   EOF()   OR   被修改的字段<>OLDVALUE(被修改的字段)  
                  原記錄被他人修改了或刪掉了  
                  ROLLBACK  
                  RETURN   -1  
              ENDIF  
          UPDATE   MYTABLE   SET       被修改的字段=新值   WHERE   KEY=SOME  
      B、或者直接用一條語句,VFP9.0以上  
          UPDATE   MYTABLE   SET       被修改的字段=新值   WHERE   KEY=SOME   AND   被修改的字段=OLDVALUE(被修改的字段)  
          IF   SQLROWCOUNT=0           原記錄被他人修改了或不存在了  
                ROLLBACK  
                RETURN   -1  
          ENDIF  
  3、COMMITTop

33 樓trainee(春泥)回覆於 2005-07-25 11:36:06 得分 5

其實SPT和遠程試圖、CURSORADAPTAR中的TABLEUPDATE單條記錄,用的就是以上技術,他封裝的是B方法,即  
  UPDATE   MYTABLE   SET       被修改的字段=新值   WHERE   KEY=SOME   AND   被修改的字段=OLDVALUE(被修改的字段)  
  只是前後不會加上BEGIN、LOCK、COMMIT,由客戶自行決定,其實若是更新一條記錄,服務器若處於AUTOCOMMIT模式,一條SQL語句前後也不必加。  
  若TABLEUPDATE多條記錄,與單條一樣,一條條生成。  
  在SPT中,你可以用CURSETPROP("WhereType")來控制自動生成的UPDATE語句中的WHERE子句  
  1、值爲1(DB_KEY   )或者TABLEUPDATE(0,   FORCE),只生成   WHERE   KEY=SOME,表示無條件更新  
  2、值爲2(DB_KEYANDUPDATABLE   ),生成   WHERE   KEY=SOME   AND   可更新的字段=OLDVALUE(可更新的字段)   AND   。。。。表示只要有一可更新字段被別人更改,就無法更新  
   
  3、值爲3(DB_KEYANDMODIFIED   )   默認,生成   WHERE   KEY=SOME   AND   被修改的字段=OLDVALUE(被修改的字段)   AND   。。。   表示只要有一被改字段被別人更改,就無法更新  
   
  4、值爲4(DB_KEYANDTIMESTAMP   )   生成   WHERE   KEY=SOME   AND   TIMESTAMP字段=OLDVALUE(TIMESTAMP),適應於某些特定的數據庫,根據時間戳對比。  
   

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章