2008-01-26

VFP和SQL SERVER搭配做C/S系統

1.CLIENT/SERVER 到底是什麼?

C/S屬於2-TIER系統,適合於中小型應用系統。大系統一般都用3-TIER了。
打個比方單機數據庫系統(比如VFP), 相當於前店後庫.店裡需要什麼東西,得自己去庫房找,庫房管理也是有你自己進行. 而C/S系統下,店和庫是相對獨立的,有一個專門的庫房管理(數據SERVER),店裡需要什麼,按照手續把單子給
庫房管理人員,由他們去操作.

因此可以看出C/S的優點: 支持多用戶; 更有效的數據管理,數據安全和可靠得多;遠程使用數據.
如果你是單機使用當然沒有太大必要使用C/S了.

如果用VFP本身做C/S系統, 效果不是很明顯,因為VFP的數據管理功能不是很強,比如加鎖解鎖都需要程序來操作. 我主要說的是VFP/SQL SERVER系統.

2. SQL SERVER

SQL SERVER是微軟發佈的RDBMS(關係數據庫管理系統), ORACLE, INFOMIX,POWERBUILD,也都是類似的系統. 他們就相當於倉庫的管理系統,但功能不僅僅是數據管理. 微軟的數據庫產品從功能和規模由小到大排列依次是: ACCESS, VFP, SQL SERVER.

稍微大一點的系統,SQL SERVER是需要專人管理的,這就是DBA (DATABASE ADMINISTRATOR)的位置.現在北美人才市場上, DBA的工作比程序員的工作好找些. 工資比普通程序員略高, 工作穩定性也強一些.

SQL SERVER是一套大的軟件系統,可以安裝在專門的NT數據SERVER上,也有個人版可以安裝在WIN95/98上, 主要是為了咱們這些程序員方便測試. 它的功能主要有這麼幾塊: 數據庫的管理和維護,用戶/安全管理, 數據的發布/轉換.

3. 用VFP/SQL SERVER做C/S系統

VFP和SQL SERVER的搭配應該是比較完美的, 但因為VB才是微軟的主流產品(VB一直是微軟的,FOXPRO是後來才買的,後娘生的), 所以微軟從來沒有大力推薦或者宣傳過VFP, 而是把VFP獨有的數據庫技術融合到自己的其它產品裡了: SQL SERVER, ODBC, OLE DB/ADO. 最近甚至把VFP從VISUAL STUDIO裡獨立出來了.

VFP和SQL SERVER的交流,可以通過3種方式進行:
A. 遠程視圖 B. ADO控件 C. SPT (SQL PASS THROUGH)

3種方式各有優缺點, 而我最偏好第3種. 遠程視圖和ADO都在VFP和SQL SERVER中間加了一個層次, 而這層次就相當於一個黑箱,你不清楚它們到底怎麼操作數據的,只需按照它們的規則進行設置,使用
相應的命令就可以. 反正我作為程序員,喜歡清楚地知道我的程序每一步都在幹什麼,所以我喜歡用SPT, 也從不用嚮導來建立表單報表一類的.

SPT技術是通過VFP的函數SQLCONNECT()來和SQL SERVER建立連接, 然後用SQLEXEC()函數把要執行的SQL命令 送到SQL SERVER上去執行,
所有對數據的操作都是通過這些SQL命令來進行的. 每一個細節都由自己的代碼來控制.

4. VFP數據的陞遷

VFP的數據庫,可以直接用VFP自帶的陞遷嚮導轉到SQL SERVER上,但必須把所有的表都放到數據庫裡,自由表不能直接陞遷, 而實際上陞遷上去的又只是表,數據庫本身不能轉到SQL SERVER裡. 感覺怪怪的. 也許是為了陞遷索引或者關係吧.

要把VFP數據陞遷到SQL SERVER上, 必須先在SQL SERVER裡建立相應的數據庫. SQL SERVER的管理是通過ENTERPRISE MANAGER (EM)來進行的. 通過它建立數據庫, 每個數據庫裡可以包含 數據表,用戶/用戶群,視圖,存儲過程等等.

至於改用SQL SERVER後,原來的VFP程序是肯定需要修改的, 而且是比較大的改動.

***************
談談VFP和SQL SERVER搭配做C/S系統 (二) --動態設置ODBC連接

1。設置ODBC數據源

VFP和SQL SERVER的連接是通過ODBC或者OLE DB(ADO)來進行的。可以打開控制面板的ODBC數據源進行設置。但很多情況下,我們希望能在程序裡動態設置數據源,一來可以不用去為每個用戶的機器手動設置, 二來為了數據的安全性,使用完後,希望把ODBC數據源刪掉。

下面的例子是用API函數來設置和刪除ODBC數據源。
函數名字是 SQLConfigDataSource,其中第二項參數是數字(1-增加 2-修改 3-刪除)

DECLARE INTEGER SQLConfigDataSource IN odbccp32 INTEGER, INTEGER, STRING, STRING

lnWindowHandle=0
lcODBCDriver='SQL Server' &&DRIVER類型
lcODBCName='SharedData' &&數據源名字
lcODBCDesc='Shared Data Source' &&數據源描述
lcODBCServer='DEVSQL' &&SQL SERVER名字
lcODBCDatabase='Shared' &&要連接的數據庫名字

**先試圖修改已有的ODBC,如果不存在,返回0。
lreturn=SQLConfigDataSource(lnWindowHandle, 2, lcODBCDriver, ;
'DSN=' + lcODBCName + CHR(0) ;
+ 'Description=' + lcODBCDesc + CHR(0) ;
+ 'Server=' + lcODBCServer + CHR(0) ;
+ 'Database=' + lcODBCDatabase + CHR(0))
IF lreturn=0 &&不存在

**添加新的ODBC
lreturn=SQLConfigDataSource(lnWindowHandle, 1, lcODBCDriver, ;
'DSN=' + lcODBCName + CHR(0) ;
+ 'Description=' + lcODBCDesc + CHR(0) ;
+ 'Server=' + lcODBCServer + CHR(0) ;
+ 'Database=' + lcODBCDatabase + CHR(0))
IF lreturn=0 &&失敗
MessageBox('添加ODBC數據源失敗',16,'BUFFER')
ENDIF
ENDIF

2。刪除ODBC數據源

**用完後,可以在表單DESTROY事件裡刪除ODBC。 如果不想重複設置參數,可以把這些參數加到表單作為屬性。

DECLARE INTEGER SQLConfigDataSource IN odbccp32 INTEGER, INTEGER, STRING, STRING

lnWindowHandle=0
lcODBCDriver='SQL Server'
lcODBCName='SharedData'
lcODBCDesc='Shared Data Source'
lcODBCServer='DEVSQL'
lcODBCDatabase='Shared'

**先修改,或者其是否存在
lreturn=SQLConfigDataSource(lnWindowHandle, ;
2, lcODBCDriver, ;
'DSN=' + lcODBCName + CHR(0) ;
+ 'Description=' + lcODBCDesc + CHR(0) ;
+ 'Server=' + lcODBCServer + CHR(0) ;
+ 'Database=' + lcODBCDatabase + CHR(0))
IF lreturn=1 &&ODBC存在,刪除它
lreturn=SQLConfigDataSource(lnWindowHandle, ;
3, lcODBCDriver, ;
'DSN=' + lcODBCName + CHR(0) ;
+ 'Description=' + lcODBCDesc + CHR(0) ;
+ 'Server=' + lcODBCServer + CHR(0) ;
+ 'Database=' + lcODBCDatabase + CHR(0))
IF lreturn=0
MessageBox('刪除ODBC源失敗,16,'BUFFER')
ENDIF
ENDIF

**清除DLL
CLEAR DLLS

3. 從VFP連接到SQL SERVER

lnHandle=SQLConnect("SharedData","用戶名」,「密碼」)
If lnHandle>0 &&連接成功
**從庫裡獲得數據(比如從EMP表裡得到部門號為『01』的職工)
lnReturn=SQLExec(lnHandle,"Select * from Emp Where cDept='01'","CursorEmp")
If lnReturn>0 &&運行成功
Browse
Else &&失敗
&&出錯處理
EndIf
Else &&連接失敗
MessageBox("連接SQL SERVER失敗」,16,「BUFFER」)
EndIf

**用完連接後,最好馬上關閉,連接是很寶貴的資源,微軟是按連接數收費的,而且每個連接會增加SQL SERVER的管理負擔
=SQLDisconnect(lnHandle)

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

用SPT技術更新數據時,必須通過SQL命令進行,SQL命令必須符合ANSI或者T-SQL(微軟的TRANSACTION SQL),因為命令是通過VFP的SQLEXEC()函數送到SQL SERVER去執行的,語法必須遵守SQL SERVER的規則,而不是VFP的規則。不熟悉的人,最容易犯的錯誤就是把VFP的函數傳送到SQL SERVER上執行,結果總出錯。兩者大部分函數都是不一樣的。

比如ALLTRIM()是VFP的, SQL SERVER裡是LTRIM()和RTRIM()
VFP日期以{}分界,但SQL SERVER裡不認,必須用單引號.

如果SQL命令裡用到VFP程序裡的變量,變量前必須加問號「?」
比如,更新一個表的字段

lcLName="Zhang"
lcFName="San"
lnReturn=SQLEXEC(連接句柄,「Update Emp Set cLName=?lcName, cFName=?lcFName Where cEmpNo='733000'")

如果返回值lnReturn>0,就更新成功了

插入記錄,或者逐條修改記錄時,只能每次操作一條記錄。
比如要把臨時表TmpEmp裡的記錄加到SQL SERVER的EMP表裡,就得用循環

Select TmpEmp
Scan
lnReturn=SQLEXEC(連接句柄,"Insert Into Emp (cEmpNo,cLName,cFName) values (?TmpEmp.cEmpNo,?cTmpEmp.cLName,?cTmpEmp.cFName)"
EndScan

*** 要得到SQL SERVER上某個表的結構,有兩種辦法,一是運行SQL SERVER自帶的系統存儲過程。一是運行一個SELECT命令。

比如要從SQL SERVER得到EMP表的結構

lnReturn=SQLEXEC(連接句柄,"Select Top 0 * From Emp","TmpEmp")

返回的結果都是臨時表,是只讀的,要想變成可讀寫的,需要做點小變化:

Select 0
Use DBF("TmpEmp") Again Alias Emp
Use In TmpEmp

現在得到的EMP臨時表就是可讀寫的了。

*注 "Select Top 0 From Emp" 命令在VFP裡是錯誤命令,但SQL SERVER裡可以執行.

SPT和使用視圖相比,優點是每一步你都清楚自己在做什麼,知道為什麼命令會出錯。缺點是你需要多寫命令,多瞭解SQL SERVER的語法。

***************
談談VFP和SQL SERVER搭配做C/S系統 (五) --從VFP控制SQL SERVER事務處理和加鎖

**建立與SQL SERVER的連接
lnHandle=SQLConnect("ODBC數據源","用戶名","密碼")

If lnHandle>0

&& 設置成手工事務處理模式,由代碼來控制
= SQLSETPROP(lnSQL_Hand, 'Transactions', 2)

**下面的命令從EMPPAY裡選取記錄,並給該表加上獨佔鎖(TABLELOCKX),一直到該事務結束(HOLDLOCK)

ln1=SQLEXEC(lnHandle, "SELECT * FROM Emppay WITH (TABLOCKX, HOLDLOCK)","Emppay")

**執行其它命令,比如更新數據
ln2=SQLEXEC(lnHandle,"Update PayTotal Set ......")
...
...

**如果所有命令都正確執行了,則
=SQLCOMMIT(lnHandle)

***如果要放棄整個事務處理,用
=SQLROLLBACK(lnHandle)

***關閉連接,事務自動結束,鎖也解開
=SQLDISCONNECT(lnHandle)

Else
****連接失敗
EndIf

*** SQLSETPROP()函數
這個VFP函數是用來設置當前連接的屬性的。 比如上邊的手工事務處理。
還有一個比較常用的屬性是DISPLOGIN,該屬性控制是否顯示SQL SERVER的登錄表單

第3個參數: 1 - 顯示登錄表單,如果登錄信息(用戶名,密碼)不完全 2 - 總顯示登錄表單 3 - 不顯示登錄表單

例如:
=SQLSETPROP(lnHandle, "DISPLOGIN",1)

當使用SPT技術時,為節約連接數減少服務器負擔,需要經常連接和斷開SQL SERVER,有時候你並不希望每次連接都讓用戶登錄,當用戶首次登錄後,可以把名字和密碼存起來,以後的連接可以自動登錄了。

***************
談談VFP和SQL SERVER搭配做C/S系統 (六) -- SQL SERVER的索引

作為VFP程序員,我們深知索引對表的重要性,好的索引可以大大縮短程序讀取數據的時間。
索引對於SQL SERVER數據表來說,同樣是很重要的。你可以做個簡單的測試。

1. 索引測試

從SQL SERVER程序組裡或者ENTERPRISE MANAGER的TOOLS菜單上打開QUERY ANALYZER工具.
連接到你的SERVER後, 選擇QUERY菜單上的CURRENT CONNECTION OPTIONS(當前連接選項),
把SHOW STATS TIME 和SHOW STATS I/O兩個選項打勾,然後點OK. 這兩個選項將會告訴你命令的運行時間和讀寫次數.
如果你的SQL命令裡用到多個表,還可以選上QUERY菜單上的SHOW EXECUTION PLAN, 它會告訴你的命令在各各表上所花費的時間.

選一個沒有索引的大小適當的表,然後執行一條SELECT命令,你會看到運行時間.
比如我用了表CHQ,有將近40萬條記錄, 執行下面的命令,返回5000多個記錄

select * from Chq where date >='02/01/2001' and date<='02/28/2001'

顯示的時間和讀寫情況:
Table 'chq'. Scan count 1, logical reads 13145, physical reads 0, read-ahead reads 13152.
SQL Server Execution Times: CPU time = 5781 ms, elapsed time = 23526 ms.

然後我在CHQ表上對DATE字段建立索引,再運行相同的SELECT, 得到如下結果:
Table 'chq'. Scan count 1, logical reads 3965, physical reads 14, read-ahead reads 0.
SQL Server Execution Times: CPU time = 704 ms, elapsed time = 6432 ms.

比較兩個結果可以看出, 建立索引後,邏輯讀寫和預讀寫次數大大減少, 佔用CPU時間從5.781秒減少到了0.704秒, 總運行時間從23.526秒減少到6.432秒
如果運行更複雜的命令,效果會更加明顯.

2. 瞭解SQL SERVER的索引

SQL SERVER的數據文件和索引文件都是以頁為單位存放的,每頁是8K. 相當於把磁盤劃分成8K大小的塊,以塊為單位存放數據.
瞭解這一點是非常重要的, 它能幫助你理解下面的內容.

SQL SERVER的索引有2大類,
一類是CLUSTERED(物理索引),每個表只能有一個, 記錄在磁盤上存放時完全按照物理索引的順序.
另一類是NONCLUSTERED(邏輯索引), 記錄順序存放在索引表裡.

不管是哪類索引,只要能到達目的,索引表達式(包含的字段)越簡單越有效.

什麼字段作為物理索引最合適?

有兩個原則: 一是在根據範圍來選擇記錄時,哪個字段最有效, 二是在往磁盤上寫記錄是不會引起熱點(HOT SPOT).
熱點是指,大量讀寫發生在磁盤的同一區域,引起I/O瓶頸效應,降低運行速度.

我們用例子來看看這些原則怎麼用.
假如有個單據表, 包含這些字段: 單據號,單據日期,金額,銷售地點,已經其它數據.
哪個適合作為物理索引呢? 一般的想法是用沒有重複值的字段(相當於VFP裡的主鍵).

a. 用單據號, 其實這不是恰當的選擇. 因為很少有根據單據的範圍來選擇記錄的, 比如你很少用命令來查詢單據號大於或者小於某個值的記錄. 而且在輸入時,也比較容易產生熱點, 因為插入的記錄一般都加在表尾,當有大量用戶同時輸入時,會產生熱點. 單據號不符合上面的2條原則.

b. 用單據日期, 似乎是個比較適當的選擇. 因為經常需要用日期範圍來選擇記錄, 但同樣會因為大量用戶同時輸入最新單據而在磁盤上引起熱點.

c. 用銷售地點, 這應該是最恰當的物理索引人選了. 因為我們會經常根據地點來選擇記錄, 而在同一時刻插入的記錄也不太可能來自同一個銷售地點,避免了熱點.

當然,不同的環境下,你的選擇可能不同,比如你沒有成千上萬的用戶,就不太需要考慮熱點問題. 但要記住, 有唯一值的字段並不是物理索引的最佳選擇.

3. 選擇適當的FillFactor

在SQL-CREATE INDEX命令裡,有個FILLFACTOR選項, 這個選項對索引的效率是有很大作用的.
FILLFACTOR是指建立索引時, 每一頁存放數據的填滿程度, 比如100%,表示把索引文件每一頁都填滿,隱含值是0 (100%).

如果你的表經常需要插入記錄, 選擇適當的FILLFACTOR就很重要了. 如果總是用100%, 當你插入一個新記錄時, 由於每頁都是滿的, 就需要進行分頁操作(把當前頁分成2頁),頻繁的分頁操作會佔用服務器的資源和時間,也降低索引文件的效率. 而如果你的FILLFACTOR不是100%,比如設為80%, 在插入新記錄時,由於當前頁還有空間, 可以直接加入不需要分頁. 當然, FILLFACTOR太低也會降低效率,因為那樣的話,頁數就多了,搜索數據用的時間長,佔用空間也多.

如果是只讀表,或者插入記錄很少的表,用100% FILLFACTOR最好.

對於經常插入新記錄的表,需要定期重建索引, 因為索引文件隨著頁數的增加, 效率會越來越低. 因為索引都是樹狀結構, 當下面的頁加得沒有規律時, 連接就會變亂, 重建索引可以重新整理樹狀結構.

4. 索引分析工具

在QUERY ANALYZER的QUERY菜單裡,還有個選項PERFORM INDEX ANALYSIS.
在輸入你的命令後,選擇這一項, SQL SERVER會對你的命令進行分析,然後告訴你建立什麼樣的索引對當前命令最有利.
可以把你程序裡常用的命令放到這裡進行分析,找出最恰當的索引。

VFP常用函數

* VFP編程在SQL Server服務器上建立數據庫、數據表(在WinXp/SQL Server 2000/VFP6.0中調試通過)
* 用CREATE DATABASE、CREATE TABlE、INSERT語句

SET STEP ON
SET TALK ON
SET STAT ON

CLEAR
LOCAL nHandle,cSQLnResult

*cConnString="Driver=SQL Server;Server=SCBHWQ;UID=sa;PWD=67773240;Database=Master"
cConnString="Driver=SQL Server;Server=ZHANGZUO;UID=sa;PWD=;Database=Master"

nHandle=SQLSTRINGCONNECT(cConnString)

IF nHandle<=0
=MESSAGEBOX("無法建立連接",0+48,"提示")
RETURN
ENDIF

* 建立數據庫

cSQL="CREATE DATABASE SCXXGLXT "+;
"ON "+;
"( NAME=SCXXGLXT_dat,"+;
"FILENAME='C:\Program Files\Microsoft SQL Server\MSSQL\data\SCXXGLXTdat.mdf',"+;
"SIZE=10,"+;
"MAXSIZE=50,"+;
"FILEGROWTH=5 )"+;
"LOG ON "+;
"( NAME='SCXXGLXT_log',"+;
"FILENAME='C:\Program Files\Microsoft SQL Server\MSSQL\data\SCXXGLXTlog.ldf',"+;
"SIZE=5MB,"+;
"MAXSIZE=25MB,"+;
"FILEGROWTH=5MB )"
nResult=SQLEXEC(nHandle,cSQL)

IF nResult<0
=MESSAGEBOX("無法建立數據庫!")
ELSE
=MESSAGEBOX("建立數據庫成功")
ENDIF
=SQLDISCONNECT(nHandle) &&斷開連接


*cConnString="Driver=SQL Server;Server=SCBHWQ;UID=sa;PWD=67773240;Database=SCXXGLXT"
cConnString="Driver=SQL Server;Server=ZHANGZUO;UID=sa;PWD=;Database=SCXXGLXT"

nHandle=SQLSTRINGCONNECT(cConnString)

IF nHandle<=0
=MESSAGEBOX("無法建立連接",0+48,"提示")
RETURN
ENDIF

* 建立數據表

cSQL="CREATE TABlE 用戶表 "+;
"( 用戶編號 varchar(10) NOT NULL, "+;
"用戶名稱 varchar(40) NOT NULL, "+;
"用戶密碼 varchar(10) NULL, "+;
"顯示順序 varchar(10) NULL, "+;
"檔案建立時間 varchar(8) NULL "+;
") "+;
"CREATE TABlE 產品表 "+;
"( 產品編號 varchar(10) NOT NULL, "+;
"產品名稱 varchar(70) NULL, "+;
"產品型號 varchar(70) NULL, "+;
"產品基本型號 varchar(40) NULL, "+;
"產品類型 varchar(40) NULL, "+;
"產品功能 varchar(70) NULL, "+;
"顯示順序 varchar(10) NULL, "+;
"檔案建立時間 varchar(8) NULL "+;
") "+;
"CREATE TABlE 物料表 "+;
"( 物料編號 varchar(10) NOT NULL, "+;
"物料名稱 varchar(70) NULL, "+;
"物料型號 varchar(70) NULL, "+;
"物料類型 varchar(40) NULL, "+;
"計量單位 varchar(20) NULL, "+;
"單價 decimal(9,4) NULL, "+;
"不變價 decimal(9,4) NULL, "+;
"加工類型 varchar(30) NULL, "+;
"部門編號 varchar(10) NULL, "+;
"生產部門 varchar(40) NULL, "+;
"供貨商編號 varchar(10) NULL, "+;
"供貨商名稱 varchar(40) NULL, "+;
"供貨商物料編號 varchar(40) NULL, "+;
"供貨商物料名稱 varchar(70) NULL, "+;
"供貨商物料型號 varchar(70) NULL, "+;
"供貨商物料單價 decimal(9,4) NULL, "+;
"大小尺寸 varchar(40) NULL, "+;
"顏色 varchar(20) NULL, "+;
"單件重量 decimal(9,4) NULL, "+;
"原材料名稱 varchar(40) NULL, "+;
"原材料型號 varchar(70) NULL, "+;
"原材料單價 decimal(9,4) NULL, "+;
"原材料單件損耗重量 decimal(9,4) NULL, "+;
"舊物料編號 varchar(8) NOT NULL, "+;
"庫房編號 varchar(10) NULL, "+;
"庫房名稱 varchar(40) NULL, "+;
"顯示順序 varchar(10) NULL, "+;
"檔案建立時間 varchar(8) NULL "+;
") "+;
"INSERT 用戶表 "+;
"(用戶編號,用戶名稱,用戶密碼) VALUES('0000000001','Administrator','1234567890')"
nResult=SQLEXEC(nHandle,cSQL)

IF nResult<0
=MESSAGEBOX("無法建立數據表和增加記錄!")
ELSE
=MESSAGEBOX("建立數據表和增加記錄成功")
ENDIF

=SQLDISCONNECT(nHandle) &&斷開連接
RETURN

VFP編程在SQL Server服務器上建立數據庫、數據表

* VFP編程在SQL Server服務器上建立數據庫、數據表(在WinXp/SQL Server 2000/VFP6.0中調試通過)
* 用CREATE DATABASE、CREATE TABlE、INSERT語句

SET STEP ON
SET TALK ON
SET STAT ON

CLEAR
LOCAL nHandle,cSQLnResult

*cConnString="Driver=SQL Server;Server=SCBHWQ;UID=sa;PWD=67773240;Database=Master"
cConnString="Driver=SQL Server;Server=ZHANGZUO;UID=sa;PWD=;Database=Master"

nHandle=SQLSTRINGCONNECT(cConnString)

IF nHandle<=0
=MESSAGEBOX("無法建立連接",0+48,"提示")
RETURN
ENDIF

* 建立數據庫

cSQL="CREATE DATABASE SCXXGLXT "+;
"ON "+;
"( NAME=SCXXGLXT_dat,"+;
"FILENAME='C:\Program Files\Microsoft SQL Server\MSSQL\data\SCXXGLXTdat.mdf',"+;
"SIZE=10,"+;
"MAXSIZE=50,"+;
"FILEGROWTH=5 )"+;
"LOG ON "+;
"( NAME='SCXXGLXT_log',"+;
"FILENAME='C:\Program Files\Microsoft SQL Server\MSSQL\data\SCXXGLXTlog.ldf',"+;
"SIZE=5MB,"+;
"MAXSIZE=25MB,"+;
"FILEGROWTH=5MB )"
nResult=SQLEXEC(nHandle,cSQL)

IF nResult<0
=MESSAGEBOX("無法建立數據庫!")
ELSE
=MESSAGEBOX("建立數據庫成功")
ENDIF
=SQLDISCONNECT(nHandle) &&斷開連接


*cConnString="Driver=SQL Server;Server=SCBHWQ;UID=sa;PWD=67773240;Database=SCXXGLXT"
cConnString="Driver=SQL Server;Server=ZHANGZUO;UID=sa;PWD=;Database=SCXXGLXT"

nHandle=SQLSTRINGCONNECT(cConnString)

IF nHandle<=0
=MESSAGEBOX("無法建立連接",0+48,"提示")
RETURN
ENDIF

* 建立數據表

cSQL="CREATE TABlE 用戶表 "+;
"( 用戶編號 varchar(10) NOT NULL, "+;
"用戶名稱 varchar(40) NOT NULL, "+;
"用戶密碼 varchar(10) NULL, "+;
"顯示順序 varchar(10) NULL, "+;
"檔案建立時間 varchar(8) NULL "+;
") "+;
"CREATE TABlE 產品表 "+;
"( 產品編號 varchar(10) NOT NULL, "+;
"產品名稱 varchar(70) NULL, "+;
"產品型號 varchar(70) NULL, "+;
"產品基本型號 varchar(40) NULL, "+;
"產品類型 varchar(40) NULL, "+;
"產品功能 varchar(70) NULL, "+;
"顯示順序 varchar(10) NULL, "+;
"檔案建立時間 varchar(8) NULL "+;
") "+;
"CREATE TABlE 物料表 "+;
"( 物料編號 varchar(10) NOT NULL, "+;
"物料名稱 varchar(70) NULL, "+;
"物料型號 varchar(70) NULL, "+;
"物料類型 varchar(40) NULL, "+;
"計量單位 varchar(20) NULL, "+;
"單價 decimal(9,4) NULL, "+;
"不變價 decimal(9,4) NULL, "+;
"加工類型 varchar(30) NULL, "+;
"部門編號 varchar(10) NULL, "+;
"生產部門 varchar(40) NULL, "+;
"供貨商編號 varchar(10) NULL, "+;
"供貨商名稱 varchar(40) NULL, "+;
"供貨商物料編號 varchar(40) NULL, "+;
"供貨商物料名稱 varchar(70) NULL, "+;
"供貨商物料型號 varchar(70) NULL, "+;
"供貨商物料單價 decimal(9,4) NULL, "+;
"大小尺寸 varchar(40) NULL, "+;
"顏色 varchar(20) NULL, "+;
"單件重量 decimal(9,4) NULL, "+;
"原材料名稱 varchar(40) NULL, "+;
"原材料型號 varchar(70) NULL, "+;
"原材料單價 decimal(9,4) NULL, "+;
"原材料單件損耗重量 decimal(9,4) NULL, "+;
"舊物料編號 varchar(8) NOT NULL, "+;
"庫房編號 varchar(10) NULL, "+;
"庫房名稱 varchar(40) NULL, "+;
"顯示順序 varchar(10) NULL, "+;
"檔案建立時間 varchar(8) NULL "+;
") "+;
"INSERT 用戶表 "+;
"(用戶編號,用戶名稱,用戶密碼) VALUES('0000000001','Administrator','1234567890')"
nResult=SQLEXEC(nHandle,cSQL)

IF nResult<0
=MESSAGEBOX("無法建立數據表和增加記錄!")
ELSE
=MESSAGEBOX("建立數據表和增加記錄成功")
ENDIF

=SQLDISCONNECT(nHandle) &&斷開連接
RETURN

VFP遠程視圖使用面面觀

摘要:遠程視圖是Visual Foxpro 5.0 中開發Client/Server 應用系統的基礎,本文首先介紹了遠程視圖有關參數的放置技巧,然後介紹如何去設計、使用遠程視圖,最後討論了使用遠程視圖的四個實際問題。

關鍵詞:遠程視圖;遠程數據;連接;鎖定;緩衝。

一、緒論

VFP 是一種較好的客戶/ 服務器應用系統開發工具,用VFP 開發C/S 系統的關鍵是如何訪問遠程數據( 遠程服務器中的Table/View)。可以使用VFP 提供的SQL Pass-Through 函數訪問遠程數據,但最常用的方法是使用遠程視圖(Remote View) 去訪問遠程數據。本文結合本人的使用經驗對遠程視圖的使用技巧加以介紹。

二、遠程視圖的環境設置

在設計遠程視圖時,需要對遠程視圖的有關環境信息進行設置。使用Tools 菜單中的Options.... 選項來設置Remote Data 選項。其選項設置說明如下:

*Share Connection: 指出今後設計的遠程視圖是否使用共享連接。使用共享連接可大大減少數據庫服務器中客戶訪問許可數,但會影響客戶機的訪問速度。

*SQL Updates/Criteria: 指出對後台數據進行update 操作的條件。

它有四種可能:

①Key Field only ②Key and Updatable Fields

③Key and Modified Fields ④Key and Time Stamp。

一般選擇③較合適。

*SQL Updates/Method: 指出對後台數據的更新方法。

它有兩種選擇:①SQL Delete then Insert ②SQL update。

一般選擇②比較合適。

*Connection Defaults: 主要用於SQL Pass-Through 函數訪問遠程數據,對於遠程視圖則不需要放置。

三、遠程視圖的設計

有兩種方法設計遠程視圖,一是使用View Designer;二是使用SQL 語句。用View Designer 可設計較為簡單的視圖,而使用SQL 的Create Remote View 語句則可進行複雜視圖的設計。如果試圖去用View Designer 觀察或修改( 用Create 創建的視圖) 則極有可能被破壞它( 例如:若創建視圖的Select 語句中含有exists 子句, 則一定會被破壞!)

1. 用Create 命令設計

例如:假定連接名為WYFconnect,兩個遠程表為SealList 和ShipList. Create 命令可如下:

CREATE SQL VIEW ViewTest REMOTE CONNECTION WYFconnect AS SELECT SealList.* FROM SealList, ShipList WHERE SealList IS NOT NULL AND SealList AND 箱號NOT IN (SELECT 箱號FROM ShipList WHERE ShipList. 箱號IS NOT NULL AND ShipList. 船名=SealList. 船名

使用該方法可以在程序中動態地構造滿足不同條件的遠程視圖(View Designer 不能構造帶參數的遠程視圖)。例如:設m.ShipName 為一可變內存變量,其創建語句為:

CREATE SQL VIEW ViewTest REMOTE CONNECTION WYFconnect AS SELECT * FROM SealList WHERE 船名=m.ShipName.

2. 用View Designer 設計

啟動View Designer 選擇連接名後出現設計圖, 在其上部可以加入遠程服務器中的表或視圖,在其下部進行參數/ 條件設置:

*Select Criteria: 設置遠程數據值上的記錄必須滿足的條件,類似於下SQL Select 語句中的Where 子句。在這裡可以構造複雜條件,但條件中使用的函數和語法規則必須是後台數據庫支持的,例如:不能使用DTOC( 日期)=『90/01/01』,而必須使用Convert(char(10), 日期)=『90/01/01』, 因為後台數據庫不支持DTOC() 函數。

*Fields: 選擇結果集中的字段,在這裡要強調的是Function/Expression 的使用,使用它可構造出與源表字段不同的字段,如:T. 船名 『』 T. 中文AS 船舶。實踐證明Function/Expression 中不能使用雙引號,而只能使用單引號。

*Order by 和Group by: 對結果分組、分類。要求符合後台數據庫所支持的SQL 語法。

*Update Criteria: 設置視圖的有關替換參數, 具體如下:

①要選中Send SQL Update

②SQL where 一般選擇Key and Modify Fields

③Update Using 一般選擇SQL Update

④務請選擇關鍵字段和可更改字段( 在鑰匙符號下面和鉛筆符號下面加「√」),否則將無法正確完成Insert/update 功能。

四、遠程視圖的使用

1. 緩衝與鎖定設置

對於遠程視圖,建議使用緩衝機制來提高遠程視圖的工作效率和使用的方便性。首先在Option 菜單中設置Data 組件,需設置下列參數:

①選擇Open Exclusive 以讓庫共享打開,庫中的遠程視圖則可共享使用;

②Locking And Buffering 設置:選中Automatic File locking 和Multiple Record Locks,並將Buffering 設置成Fields Buffering,加鎖方式設置為「記錄級樂觀鎖定」。在具體設計Form 時,對數據環境中的每一個遠程視圖光標可重新根據需要來設置鎖定和緩衝機制。如果不重新設置,它取Form 的缺省設置。

2. 數據的寫入與前台刷新

對於採用了Buffering 技術的遠程視圖,當修改/ 刪除/ 增加了記錄時,需用TableUpdate(.T.,.T.) 函數來確保數據寫到後台數據庫中;若要取消對緩衝區中視圖數據的修改,需用TableRevert(.T.) 函數。例如:

Select View1

Append Blank

Begin Transaction

if TableUpdate(.T.,.T.)

EndTranseaction

else

RollBack

=TableRevert( T )

endif

如果該遠程視圖與別的表/ 遠程視圖發生級聯修改/ 刪除/ 增加關係,則需使用事務機制,以確保數據的完整性。

如果對應視圖的後台表/ 視圖數據發生變化時,使用下述方法讓前台客戶機中的數據與實際後台數據一致:

①Select 〈遠程視圖名〉

USE〈遠程視圖名〉&& 再次打開即可

②Select 〈遠程視圖名〉

=Requery() &&刷新緩衝區值

五、遠程視圖使用中碰到的若干問題

1. 如何在一個遠程視圖中多次使用同一遠程數據源?

依靠別名。例如:Select A. 船名,A. 航次,B. 姓名as 操作員,C. 姓名as 倉庫員from Shipname A, worker B, worker C where A. 操作員代碼=B.Code and A. 倉庫員代碼=C.Code

2. 設計遠程視圖時Select 語句的語法應符合VFP 或後台數據庫?

後台數據庫支持的SQL 語法。例如:Create SQL View AAA Remote Conection BB As Select A.* From Shipname A Where Convert(Char(10), 進港日期)=『1998/05/30』

3. 遠程視圖能否使用Pack 和Recall 語句?

不能使用pack 語句,例如:

use View1;

delete for 〈條件〉 &&加刪除標誌

pack &&錯誤,必須使用TableUpdate () 函數

對於Recall 命令,如果已執行了TableUpdate(),則執行無效; 若未發Tableupdate(), 則可用Recall 來取消刪除標記。

4. 本地視圖的數據源有遠程視圖,如何刷新本地視圖?

例如:有兩個遠程視圖Rview1 Rview2, 創建本地視圖的命令為:Create SQL view As Select A.* B.* from Rview1 A,R view2 B where A. 箱號=B. 箱號

刷新view 之前必須先刷新Rview1 和Rview2:

=requery (「Rview1」)

=Requery (「Rview2」)

=Refresh (「view」)

六、小結

遠程視圖是VFP 訪問遠程數據服務器中數據的有利武器,有了前面的介紹,就可得心應手地設計C/S 應用系統了。

參考文獻

[1 ]E.sander 等著visual FoxPro3.0 實用指南機械工業出版社1996

The Skills of Using Remote View in Visual Foxpro 5.0

Wuyefu and Yuanxiaoling

Dept. Computer, Wuhan Transaction University , WuHan430063

ABSTRACT: In the paper, it is introduced how to choice option parameters and to use remote view in Visual Foxpro 5.0. In the end, the solution to some problems is also discussed.

KEYWORDS: Remote view, Remote Data, Connection, Lock, buffering

常用VFP命令、函數及程序語句

一、主要命令:

二、常用函數

三、主要程序語句

常用VFP命令、函數及程序語句

一、主要命令:

二、常用函數

三、主要程序語句

一、主要命令:

1、CREATE

作用:建立一個新的表。

格式:CREATE [<文件>|?](注意,命令字符可取前面四個字符,後面可省略不寫,即CREA,下同;中括號表示其中的參數是可選的;|管道符號表示兩個參數隻能選擇一個,不能同時選擇,下同。)

說明:文件指建立以.dbf為擴展名的VFP數據庫文件,在命令後面加上一個問號表示系統會彈出

對話框,要求用戶輸入想要建立的表名。在命令中不加文件名或問號系統也會彈出對話框,要求用

戶輸入想要建立的表名。

2、MODIFY STRUCTURE

作用:顯示表文件結構,並允許修改此表的結構。

格式:MODIFY STRUCTURE

說明:只有在用USE命令打開表文件以後,才能顯示或修改表文件的結構。

3、APPEND

作用:在當前表的尾部(無論表中有無記錄)追加記錄(在當前表指當前正使用的表)。

格式:APPEND [BLANK]

說明:在APPEND命令後面加上BLANK參數表示在當前表的尾部添加一條空白記錄。無BLANK參數時,表示在當前表的尾部添加一條記錄並要求用戶輸入相應的字段內容。

4、INSERT

作用:在表文件中間插入一個新記錄。

格式:INSERT [BEFORE] [BLANK]

說明:INSERT 在當前記錄後插入一記錄;

INSERT BEFORE 在當前記錄前插入一記錄;

INSERT BEFORE BLANK 在當前記錄前插入一空記錄。

5、BROWSE

作用:主要用於打開瀏覽窗口,查閱表文件並同時進行修改。

格式:BROWSE

6、USE

作用:打開和關閉表文件。

格式:USE [<文件名>]

USE

說明:前一個命令用來打開<文件名>指定的表文件,該表如有備註型字段,則同時打開相應的

備註文件(.fpt文件);後一個命令關閉當前打開的表文件。

7、LIST和DISPLAY

作用:顯示表(.dbf)的內容、結構或狀態。

格式:LIST|DISPLAY [OFF] [<範圍>] [FIELDS] <表達式表> [WHILE <條件>] [FOR <條件>]

[TO PRINT|TO FILE <文件>]

LIST|DISPLAY STRUCTURE TO PRINT|TO FILE <文件>]

LIST|DISPLAY STATUS [TO PRINT|TO FILE <文件>]

說明:命令帶OFF參數表示不顯示記錄號,範圍指定對哪些記錄進行操作,範圍包括:RECORD n

第幾號記錄、NEXT n 當前記錄開始的幾個記錄、REST 自當前記錄開始至文件末尾的所有記錄、ALL

所有的記錄。不選範圍則隱含範圍為ALL;FIELDS後跟字段名,字段名與字段名之間用逗號分

隔。WHILE後跟條件,FOR後面也跟條件,區別是,WHILE後的條件如果滿足,便停止查找;FOR後的

條件查找所有滿足條件的記錄。TO PRINT和TO FILE <文件>分別表示將顯示結果在打印機上打印出

來和將顯示結果輸出到文件。DISPLAY命令在顯示記錄滿屏後,要求用戶按任意鍵繼續顯示,並且在

該命令中,如果省略範圍僅顯示當前記錄。格式中,下面兩個命令分別為顯示表結構(STRUCTURE)和工作狀態(STATUS)。

8、記錄的定位

作用:用記錄指針(POINTER)定位記錄。

格式:GO[TO] RECORD n|TOP|BOTTOM

n

SKIP [+|-]

說明:第一個命令又叫絕對定位,其中,RECORD n定位到n號記錄,TOP定位到第1個記錄,

BOTTOM定位到最後一個記錄。第二個命令定位到第n個記錄,n是一個數值。第三個命令又叫相對定

位,它以當前記錄為基準前移(-)或後移(+)n個記錄,不選任選項,則默認記錄指針後移一個記錄。

9、CHANGE和EDIT

作用:顯示要編輯或修改的字段。

格式:CHANGE|EDIT [<範圍>] [FIELDS <字段名表>] [WHILE <條件>] [FOR <條件>]

10、BROWSE

作用:打開一個"瀏覽"窗口,供用戶瀏覽或修改記錄。

格式:BROWSE [FIELDS <字段名表>]

11、REPLACE

作用:用表達式的值代替命令中與之相對應的字段的內容。

格式:REPLACE [<範圍>] <字段1> WITH <表達式1>[,<字段2> WITH <表達式2>] [FOR <條件>

] [WHILE<條件>]

12、DELETE、PACK、ZAP和RECALL

作用:分別是給要刪除的記錄作刪除標記、徹底刪除、刪除所有記錄和取消被選中的表記錄的

刪除標誌。

格式:DELETE [<範圍>] [WHILE<條件>] [FOR <條件>] (特例:DELETE FILE FILENAME.DBF,

該命令刪除指定的表文件)

PACK

ZAP

RECALL [<範圍>] [FOR <條件>] [WHILE<條件>]

13、SORT和INDEX

作用:分別是建立一個其記錄以新的物理順序排列的新表文件和對當前表根據關鍵字表達式的值

從小到大排列,並存入TO後指定的索引文件名的文件或復合索引文件的一個標識中。

格式:SORT TO <文件名> ON <字段名1> [/A] [/C] [/D][,<字段名2> [/A] [/C] [/D]]...

[ASCENDING|DESCENDING] [<範圍>] [FOR <條件>] [WHILE<條件>] [FIELDS<字段表>]

INDEX ON <關鍵字表達式> TO <文件名>

INDEX ON <關鍵字表達式> TAG <標識名> [OF <文件名>] [FOR <條件>]

說明:第1個命令中,/A按字段名升序排序,/D按字段名降序排序,/C忽略大小寫,針對字符型

關鍵字而言,ASCENDING和DESCENDING分別表示升序和降序。第1個命令建立.dbf表文件,第2個命令

建立.idx單一索引文件,第3個命令建立.cdx復合索引文件(Compound Index)。

14、USE <表文件名> INDEX <索引文件名表>、SET INDEX TO和SET ORDER TO

作用:分別是打開表文件的同時打開索引文件、打開索引文件和改變主索引。

格式:USE <表文件名> INDEX <索引文件名表>

SET INDEX TO [<索引文件名表>]

SET ORDER TO [<索引文件名>](特例:重新索引命令:REINDEX)

15、FIND、SEEK和LOCATE及CONTINUE

作用:前兩個命令FIND和SEEK是在一個已經建立了索引文件的表中,定位到關鍵字中的內容與命

令行中字符串相同的第一個記錄。後一個命令在用USE打開表文件以後,直接查詢表中字段內容。

格式:FIND <"字符串">|<字符串>

SEEK <表達式>

LOCATE [<範圍>] [FOR <條件>] [WHILE<條件>]

CONTINUE

說明:FIND命令與SEEK命令的區別是前者後跟字符串,而後者後跟表達式。在用LOCATE命令找到

一個匹配記錄後,可用CONTINUE命令搜索表的剩餘部分來尋找其他匹配的記錄。

16、COUNT

作用:統計當前表文件中符合條件的記錄數。

格式:COUNT [<範圍>] [FOR <條件>] [WHILE<條件>] [TO <內存變量名>]

說明:內存變量名可用除參數外的任意字符。

17、SUM

作用:對當前表中選中記錄的全部或指定的數值字段或由指定字段組成的數值表達式累加求和。

格式:SUM [<範圍>] [數值<表達式>] [TO <內存變量名表>] [FOR <條件>] [WHILE<條件>]

18、AVERAGE

作用:對當前表中選中記錄的全部或部分數值型字段及其組成的表達式求平均值並顯示。

格式:AVERAGE [<範圍>] [數值<表達式>] [TO <內存變量名表>] [FOR <條件>] [WHILE<條件>]

二、常用函數

1、數學函數

函數 用途

ABS(<數值表達式>) 絕對值,|x|

CEILING(<數值表達式>) >=自變量的最小整數

EXP(<數值表達式>) 對基E的冪,e=2.71828

FLOOR(<數值表達式>) <=自變量的最大整數

INT(<數值表達式>) 取整(舍尾)自變量

LOG(<數值表達式>) 自變量的自然對數,ln x

LOG10(<數值表達式>) 自變量的普通對數,lg x

MAX(<表達式1>,<表達式2>) 兩個值的最大值

MIN(<表達式1>,<表達式2>) 兩個值的最小值

MOD(<數值表達式1>,<數值表達式2>) 求餘數

RAND([<數值表達式1>]) 返回偽隨機數

ROUND(<數值表達式1>,<數值表達式2>) 四捨五入第一個自變量

SIGN(<數值表達式>) 自變量的符號

SQRT(<數值表達式>) 平方根(正根)

2、字符串操作函數

函數 用途

&<內存變量> 用於代替內存變量內容

LEN(<字符串表達式>) 返回字符串表達式的字符個數

SPACE(<數值表達式>) 生成空格

SUBSTR(<字符串表達式>,<數值表達式n>[,<數值表達式L>]) 求子字符串,從指定的字符串表達式第n個開始,總長為L的字符串

LOWER(<字符串表達式>) 將字符串字母轉換成小寫字母

UPPER(<字符串表達式>) 將字符串字母轉換成大寫字母

TRIM(<字符串表達式>) 刪除字符串尾空格

ASC(<字符串表達式>) 返回字符串表達式最左邊的第一個字符的ASCII碼

CHR(<數值表達式>) 將數值表達式轉換成字符

AT(<字符串表達式1>,<字符串表達式2>[,<數值表達式n>]) 確定字符串表達式1在字符串表達式2中的位置,n為字符串表達式第幾次出現

STR(<數值表達式>[,<數值表達式L>][,<數值表達式n>) 將數值轉換為字符串,L為數值表達式總長,n為小數位數

VAL(<字符串表達式>) 將數字字符串轉換為數字

TYPE(<表達式>) 檢測表達式值的數據類型

LTRIM(<字符串表達式>) 刪除字符串左部空格

RTRIM(<字符串表達式>) 刪除字符串右部空格

LEFT(<字符串表達式>,<數值表達式n>) 取字符串左邊部分字符,n為返回的字符個數

RIGHT(<字符串表達式>,<數值表達式n>) 取字符串右邊部分字符,n從右邊截取字符個數

3、表(.dbf)操作函數

函數 用途

BOF([<工作區號或別名>]) 查表文件開始函數

EOF([<工作區號或別名>]) 表文件結尾測試函數

RECNO([<工作區號或別名>]) 測試當前或指定工作區表的當前記錄號

DELETED([<工作區號或別名>]) 記錄刪除測試函數

FILE(<"字符串">) 測試文件是否存在函數

DBF([<工作區號或別名>]) 檢測表的文件名函數

4、日期、時間函數

函數 用途

DATE() 查系統當前日期函數

TIME([<數值表達式>]) 查系統當前時間函數

YEAR(<日期型表達式>|<日期時間型表達式>) 由日期查年函數

MONTH(<日期型表達式>|<日期時間型表達式>) 從日期查月份函數

CMONTH(<日期型表達式>|<日期時間型表達式>) 由日期查月份名函數

DAY(<日期型表達式>|<日期時間型表達式>) 從日期查當月的日函數

DOW(<日期型表達式>|<日期時間型表達式>[,<數值表達式>]) 由日期查星期函數

CDOW(<日期型表達式>|<日期時間型表達式>) 從日期查星期名函數

DTOC(<日期型表達式>|<日期時間型表達式>) 日期轉換為字符函數

CTOD(<字符串表達式>) 字符串轉換為日期函數

CTOT(<字符串表達式>) 返回日期時間值函數

TTOC(<日期時間型表達式>) 返回字符值

5、顯示、打印位置函數

函數 用途

ROW() 判斷光標行位置函數

COL() 判斷光標列位置函數

INKEY([<數值表達式>]) 檢測用戶所擊鍵對應的ASCII碼函數,數值表達式以秒為單位等待擊鍵的時間

6、其他函數

函數 用途

DISKSPACE() 返回默認磁盤驅動器中可用字節數函數

OS() 檢測操作系統名稱的函數

VERSION() 返回VFP版本號的函數

三、主要程序語句

1、條件判斷語句

格式:(1)IF <條件>

<命令語句組>

ENDIF

說明:如果條件為真,則執行命令語句組中的各語句,否則跳過這些命令語句不執行,

而執行ENDIF後的語句。

(2)IF <條件>

<命令語句組1>

ELSE

<命令語句組2>

ENDIF

說明:如果條件為真,執行命令語句組1,否則執行命令語句組2。

(3)IF <條件1>

IF <條件2>

<命令語句組1>

ELSE

<命令語句組2>

ENDIF

...

ELSE

<命令語句組N>

ENDIF

說明:進行多重條件的嵌套選擇。

(4)DO CASE

CASE <條件1>

<命令語句組1>

CASE <條件2>

<命令語句組2>

CASE <條件3>

<命令語句組3>

...

...

CASE <條件N>

<命令語句組N>

[OTHERWISE]

[<命令語句組N+1>]

ENDCASE

說明:依次判斷條件,轉入條件為真的命令語句組中執行。當所有條件都不成立時,若有

OTHERWISE項,則執行命令語句組N+1,否則執行ENDCASE後面的語句。

2、循環語句

格式:(1)DO WHILE <條件>

<命令語句組>

[LOOP]

<命令語句組>

[EXIT]

<命令語句組>

ENDDO

說明:判斷條件是否為真,如為真就重複執行循環體中的命令語句組,直到條件為假,結束循

環。

(2)SCAN

<命令語句組>

ENDSCAN

說明:在一個表中建立一個執行命令語句組的循環,並執行對每一條記錄的操作,直到表文件

記錄完為止。

VFP常用函數使用說明

1、數值運算函數

函數 操作 例 結果

SQRT(x) 求平方根 SQRT(9) 3

INT(x) 取整數 INT(3.14) 3

ROUND(x) 四捨五入 ROUND(3.14159,4) 3.1416

MOD(x,y) 求X除以Y的餘數 MOD(25,4) 1

MAX(x,y) 求X,Y中的最大值 MAX(7,8) 8

MIN(x,y) 求X,Y中的最小值 MIN(1,2,3) 1

2、字符中操作函數

函數名 操作 例 結果

UPPER(S) 小寫字母 UPPER(abc) ABC

LOWER(S) 大寫字母 LOWER(ACD) acd

LEN(S) 求字符串的長度 LEN("中國1號") 7

AT(S1,S2) 在字符串S2,找字符串S1 AT("H","CHINA") 2

SUBSTR(S,I,N) 在S字符串中的第I個字符起取N個字符 SUBSTR('TECHNOLO',3,3) CHN

LEFT(S,N) 從字符串S左邊取N個字符 LEFT("中國人",4) 中國

RIGHT(S,N) 從字符串S右邊取N個字符 S=『12345'

RIGHT(S,3) 345

SPACE(N) 生成N個空格 "合計"+SPACE(2)+"123" 合計123

TRIM(S) 消除字符串尾部空格 TRIM("姓名 ") 姓名

ALLTRI(S) 消除字符串中所有空格 ALLTRIM("李 麗") 李麗

STUFF(S1,N1,N2,S2) 用字符串S2替換S1中第N1個字符起的N2個字符 STUFF("NOW",2,1,"E") NEW

&宏替換 P="G2"

USE &P USE G2

3、日期和時間函數

函數名 操作 例 結果

DATE() 求當前日期 DATE() 2001/11/12

DATETIME() 求當前日期和時間 DATETIME() 2001/11/12/0:22:33am

YEAR(D) 求年份 YEAR(DATE()) 2001

MONTH(D) 求月份(數值) MONTH(DATETIME()) 11

CMONTH(D) 求月份(字符) MONTH(DATETIME()) Novenber

DAY(D) 求日期 DAY(DATE()) 12

DOW(D) 求星期幾(數值) DOW(DATE()) 1

CDOW(D) 求星期幾(英文) CDOW(DATE()) sunday

TIME(D) 求當前時間 TIME(DATE()) 10:20:38am

4、數據類型轉換函數

函數名 操作 例 結果

ASC(S) 求第一個字符串的ASCII碼 ASC("what") 87

CHR(N) 求ASCII碼的字符 CHR(87) w

STR(R,L,D) 數值轉換成字符,L為長度,D為小數位數 X=3.1415

STR(X,6,2) 3.14

VAL(S) 字符串轉換為數值 VAL("123") 123.00

CTOD(S) 字符串轉日期 CTOD('11/01/2002') 11/01/2002

DTOC(D) 日期轉換成字符串 DTOC(DATE()) 11/01/2002

DTOS(D) 把日期轉成年月日式的字符串 DTOS(DATE()) 20021101

CTOT(C) 字符串轉成日期時間型 CTOT(11/01/2002 10:30:50am) 11/01/2002 10:30:50am

DTOT(D) 日期型轉為日期時間型 DTOT(DATE()) 11/25/2001 00:00:01am

TTOC(T) 日期時間型轉為字符型 TTOC(DATETIME()) 11/25/2001 00:00:01am

TTOD(T) 日期時間型轉為日期型 TTOD(DATETIME()) 11/25/2001

IIF(LE,E1,E2) 邏輯判斷 IIF(A>0,"YES","NO") YES

5、檢測函數

函數名 操作 例 結果

RECNO() 檢測當前記錄號 RECNO() 1

RECCOUNT() 檢測當前記錄數 RECCOUNT() 12

BOF() 開始記錄 BOF() 1

EOF() 最後記錄 EOF() 12

FOUND() 返回查找結果 FOUND() .T.

ROW() 返回當前行坐標 ROW() 1

COL() 返回當前列坐標 COL() 1

SYS(N) 返回系統狀態 SYS(13)

vfp程式優化準則

vfp程式優化準則

◆ 內存的影響
為保證留更多的內存給程式使用以增進其效率,用戶自定義窗口、菜單、內存變量等組件,請在需要使用前才去定義、建立,並在使用後立刻將它們從內存中清除,而切勿在程式的開頭處一併定義、建立完畢。

◆ LockScreen屬性使用技巧
---以批次更新方式來加速表單的更新速度
  更改表單內控制項的一些影響其外觀的屬性前最好設定
thisform.lockscreen=.t.

  發出表單刷新命令thisform.refresh後應設定
thisform.lockscreen=.f.

◆ 加快VFP啟動速度
VFP在啟動時會搜尋下列文件:
Beaitify.app
Browse.app
Builder
Config.fpw
Convert.app
Coverage.app
Foxuser.dbf
Gallery.app
Genhtml.prg
Genmenu.prg
Dsdnv98.col
Runactd.prg
Scctext.prg
Spellchk.app
Transrort.prg
Vfp6stport.prg
Vfpxtab.prg
Wizard.app
假如你的應用程式並沒有使用到資原始檔案或幫助檔,請在config.fpw中進行下列設定來將它們關閉,以免VFP多花時間去尋找它們。
Resource=off
Help=off

至於其他VFP啟動時所必須搜尋的文件,則僅會在VFP所在的目錄下被搜尋。如果你將這些檔放在別的地方,請在config.fwp中加以指明。例如:

_genxtab=c:\crosstab\vfpxtab.prg
_convert=c:\convert\convert.app

又假如你不想使用其中的某些檔,,也請在config.fpw中指明以加快VFP的啟動速度,比方說,假設你不想使用 convert.app, 請在config.fpw 中加入下面一行敘述。
_convert=』』


◆ 文件的開啟

將那些經常要使用的表一直保持在開啟狀態。


◆ 以名稱運算式(Name Expression) 來取代宏替換。


◆ 以 evaluate() 來取代宏替換


◆ 計數循環
用for…endfor 取代 do while…enddo

◆ 表掃瞄循環
用scan…endscan 取代 do while…enddo
當需要進行條件過濾時,可直接在scan命令加入for 參數進行過濾處理

◆ 數組專用循環
使用for each…endfor


◆ 用gather 取代 replace

◆ 數據記錄的新增
速度最快者:使用SQL的insert into 命令新增數據記錄
速度較快者:先下達append blank 命令再執行 gather 命令寫入數據
速度最慢者:先下達append blank 命令再執行 replace…with 命令寫入數據。

如果你在網絡上要一次寫入數十筆、數百筆、甚至更大量的數據至一個共用表中,最快的作法是:
先將這些數據存放到一個數組中,最後再使用insert into… from array 命令一次寫入表,其速度上差異可達數百倍之巨。


◆ 暫存表(cursor)
如果你利用sql的select 命令所獲取的查詢結果是要存放在一個中繼(即中間結果表)處理用的暫存表中,請使用 into cursor 參數。


◆ 多重欄位處理
用 scatter to array 取代 scatter memvar


◆ 數據記錄的檢索
用 indexseek() 取代 seek命令與 seek()函數

◆ 善用lookup()函數進行數據的檢索處理

◆ 字串比較
假如你要進行字串或備註欄位中的字串檢索,想必下列各個字串檢索函數的速度比較對對你有所幫助:

$ > at() > atc() > inlist() > occurs() > ascan()
$ > rat() > ascan()

◆ 極多筆數據記錄的新增與索引
如果你需要將很多筆的數據記錄新增到一個已經建立了索引的表中,新增前請先關閉索引,而在新增完畢。再去重建索引(reindex).


◆ 復合索引檔與超大型表
如果在一個表很大,且其復合索引又多,可改用非結構化復合索引檔。

◆ DO命令的使用
儘量不使用DO 命令中的 IN programName 參數。


◆ 在任何一個目錄下的文件數不要超過255個。

◆ 假如使用 select…group by 與 select distinct 命令都能獲得相同的結果,建議採用前者。

◆ 以可能使用表單、報表的數據環境
因為VFP會使用底層引擎調用來打開表並設置索引與關係。
◆ 限制表單集(Formset)中的表單數量

只有當你同時需要多個表單且這些表單要共用一私有數據序列時,才有必要使用表單集。

◆ 動態載入分頁框(頁框架 PageFrame)中的控制項
作法是:除了一開始要顯示的頁面外,分別將每一個頁面中的所有控制項儲存成一個自定義類,然後當某一個頁面成為當前頁時,再將此自定義類加至頁中。

◆ 動態連接控制項與數據項
當你的表單中有很多控制項時,如果你能夠讓表單中的控制項在需要時才與其數據相連接,將可加速表單被載入的速度。
作法:在必須與數據相連的控制項的GotFocus事件中編程連接到數據的代碼,以便使控制項在成為作用控制項時才與數據相連接。比如,下列的程式將顯示框連接至表foxman的「職工姓名」欄位:
if this.rowsource=』』
this.rowsource=」foxman.職工姓名」
this.rowsourcetype=6
this.refresh
endif



◆ 反覆存取一個屬性時,如何最佳化其速度

nCount = thisform.ControlCount
for i = 1 to nCount
?thisform.Controls(i).Name
endfor
就比
for i = 1 to thisform.ControlCount
?thisform.Controls(i).Name
endfor
快很多


又例如,我想改變一個數組屬性所有元素的內容,就應該這樣做。

Local MediaArray[256]

For I = 1 to 256
MediaArray[i] = 「000」+ltrim(str(I))
Endfor
Acopy(MediaArray,thisform.aUsrId) && 將數組中的內容一次複製到數組屬性中
◆ 如何更快度存取同一個控制項的多個屬性

應該這樣:
with thisform.CurstFrame.Page3.WordContainer.AuthorEditBox
.value=『童心未泯』
.FontName=』宋體』
.FontSize=12
.FontBold=.T.
.ForeColor=255
endwith

或者

MyControl= thisform.CurstFrame.Page3.WordContainer.AuthorEditBox
MyControl.value=『童心未泯』
MyControl.FontName=』宋體』
MyControl.FontSize=12
MyControl.FontBold=.T.
MyControl.ForeColor=255

◆ 在常被引發或調用的事件與方法中的程式代碼應儘可能精簡
如Refresh方法與Paint事件經常被調用或觸發。

如果你想要加快表單的載入效率,也該儘可能將Init 事件程式的代碼移至較少被調用或觸發的事件程式中(例如Activate、Click與GotFocus),並利用某屬性(例如:Tag屬性或自定義屬性)來判斷控制項是否已執行僅需要執行一次的程式代碼。


◆ 慎重選擇數據類型
使用正確的數據類型也會加快執行的速度,比方說,如果欄位所要存儲的數值是介於-2147483647-217483647之間,則採用整數類型(Integer)就會比使用數值型(Numeric)來得有效率。

更重要的是,如果可能的話,儘可能以整數類型的欄位作為主鍵值與外鍵值。

◆ VarType()比Type()快

◆ NewObject() 比 CreateObject() 快

◆ NewObjec 方法 比 AddObject 方法快

◆ 加快 OLE 組件的使用效率

原則:
1) 事先啟動自動化服務器
2) 將組件插入通用欄位中
3) 儘可能使用圖片控制項(Image Control)
4) 儘可能使用人工連接方式

◆ 提升自動化的速度

要想提升自動化的速度,你就應該避免同時建立同一個自動化服務器的多個實例。建議應使用GetObject()而不要用CreateObjec()函數。

2008-01-18

VISTA business enterprise 啟動法

H7RPG-XDMJM-WTY9D-VYJ3C-CB3KJ
YFKBB-PQJJV-G996G-VWGXY-2V3X8
VKK3X-68KWM-X2YGT-QR4M6-4BWMV
以上企業版序號
■KMS服務器VBS.NET.CN■
-----KMS激活支持版本-------------------------------------
32位Business版(不區分語言)
64位Business版(不區分語言)
32位Enterprise版(不區分語言)
64位Enterprise版(不區分語言)
-----KMS激活使用方法---------------------------------------
序列號:YFKBB-PQJJV-G996G-VWGXY-2V3X8
第一步:使用序列號並選擇安裝Business版本! Enterprise版跳過這步。
第二步:安裝完後, 所有程序/附件/命令提示符,右鍵選擇以[以管理員身份運行]
第三步:輸入命令激活系統
cscript c:\windows\system32\slmgr.vbs -skms vbs.net.cn
[回車]
cscript c:\windows\system32\slmgr.vbs -ato
[回車]
------KMS激活錯誤解答---------------------------------------
1.錯誤:0x80070005
解答:提升你的權限為超級用戶。
2.錯誤:0xC004F039
解答:無法連接服務器,服務器關閉中。
3.錯誤:0x800706BA
解答:是由於你沒有輸入序列號造成的,可以更改序列號為 YFKBB-PQJJV-G996G-VWGXY-2V3X8
4.錯誤:0xC004F042
解答:您的Windows Vista版本號必須是6000,不可以是5840或其他。
-----歡迎加入QQ群-------------------------------------------
群號:21247398(VistaFanS)
(2007年12月9日VBS.NET.CN一週年)
(2007年11月25日原來的網通服務器已更換成電信服務器)



HTTP://VBS.NET.CN 版權所有.QQ.686838.pIAoRou

VBS.NET.CN旗下站點
http://www.zyqqkj.cn
http://www.qqapi.com

2008-01-07

如何讓Linux帳號搬家

如何讓Linux帳號搬家

  有時需要讓Linux帳號搬家,其方法如下:

  1.保證將要加入系統的新帳號放在新的位置上,這通過修改/etc/default/useradd文件中的HOME 值來實現。

  如:HOME=/home2 使新增帳號的主目錄建在/home2下。

  2.將已有帳號移至新的位置。這可按如下步驟實實施:

  首先,將已有帳號的主目錄連帶目錄屬性拷至新位置,可用下面命令:

  cp -a /home /home2

  或

  cp -rpd /home /home2

  然後,修改/etc/passwd文件中相應記錄的home_directory域為/home2/username。

  這樣兩步已將舊帳號移至新位置。確保無誤後,可刪去舊帳號的舊主目錄,以騰出原文件系統的空間。