VFP 愛用者社區 首頁 VFP 愛用者社區
本討論區為 Visual Foxpro 愛用者經驗交流的地方, 請多多利用"搜尋"的功能, 先查看看有無前例可循, 如果還有不懂的再發問. 部份主題有附加檔案, 須先註冊成為社區居民才可以下載.
 
 常見問題常見問題   搜尋搜尋   會員列表會員列表   會員群組會員群組   會員註冊會員註冊 
 個人資料個人資料   登入檢查您的私人訊息登入檢查您的私人訊息   登入登入 

SPT指令集

 
發表新主題   回覆主題    VFP 愛用者社區 首頁 -> VFP 討論區
上一篇主題 :: 下一篇主題  
發表人 內容
Ruey



註冊時間: 2003-03-12
文章: 1698
來自: tunglo

第 1 樓

發表發表於: 星期六 四月 12, 2003 2:13 pm    文章主題: SPT指令集 引言回覆

一指令介紹
1.SQLCONNECT([DataSourceName,cUserID,cPassword|cConnectionName])
非同步建立與資料源的連接。

2.SQLSTRINGCONNECT
([cConnectString])
非同步通過連接字串建立與資料源的連接。

3.SQLDISCONNECT(nConnectHandle)
非同步斷開資料源連接。

4.SQLGETPROP(nConnectionHandle,cSetting)
非同步返回活動連接的當前設置或缺省設置參數值。

5.SQLSETPROP(nConnectionHandle,cSetting[,eExpression])
非同步設置活動連接的屬性參數值。

6.SQLPREPARE(nConnectionHandle,cSQLCommand[,CursorName])
非同步準備

7.SQLEXEC()
遠端執行的SQL語句。

8.SQLEXEC(nConnectionHandle[,cSQLCommand[,CursorName]])
同步,非同步將SQL語句發送到資料源進行處理。

9.SQLCANCEL(nConnectionHandle)
非同步請求取消正在執行的SQL語句。

10.SQLMORERESULTS(nConnectHandle)
同步,非同步如果有多個結果集,將另一個結果集複製到游標中。

11.SQLCOLUMNS(nConnectionHandl,Tablename[,"FOXPRO"|"NATIVE"]
[,CursorName])
同步,非同步將資料源指定表的列資訊存放到Visual FoxPro游標中。

12.SQLTABLES(nConnectionHandle[,cTableTypes][,cCursorName])
同步,非同步將資料源中表的資訊存放到Visual FoxPro游標中。

13.SQLCOMMIT(nConnectionHandle)
非同步提交一項事務。

14.SQLROLLBACK(nConnectionHandle)
非同步取消當前事務處理過程中所做全部處理。

15.SQLCONNECT([DataSourceName,cUserID,cPassword|cConnectionName])DataSourceName指定ODBC.ini檔中定義的資料源的名稱;
cUserID註冊到數據源的用戶名稱;
cPassword資料源用戶口令;
cConnectionName由CREATE CONNECTION創建的命名連接.
數值型正整數執行成功;
-1出現連接層錯誤;
-2出現環境層錯誤.

16.SQLSTRINGCONNECT([cConnectString])
cConnectStringODBC驅動器所要求的資料源連接串,
Visual FoxPro將連接串傳遞給ODBC驅動器.
數值型 正整數執行成功;
-1出現連接層錯誤;
-2出現環境層錯誤.

17.SQLDISCONNECT(nConnectHandle)
nConnectionHandle連接控制碼.
數值型 1執行成功;
-1出現連接層錯誤;
-2出現環境層錯誤.

18.SQLGETPROP(nConnectionHandle,cSetting)
nConnectionHandle連接控制碼;
cSetting連接屬性名稱. 數值型 1執行成功;
-1出現連接層錯誤;
-2出現環境層錯誤.

19.SQLSETPROP(nConnectionHandle,cSetting[,eExpression])
nConnectionHandle連接控制碼;cSetting連接屬性名稱;
eExpression連接屬性參數值.
數值型 1執行成功;
-1出現連接層錯誤;
-2出現環境層錯誤.

20.SQLPREPARE(nConnectionHandle,cSQLCommand[,CursorName])
nConnectionHandle連接控制碼;
cSQLCommand傳遞到資料源的SQL語句;
CursorName存放結果集的游標名稱,缺省游標名SQLRESULT.
數值型 1執行成功;
-1出現連接層錯誤;
-2出現環境層錯誤.

21.SQLEXEC(nConnectionHandle[,cSQLCommand[,CursorName]])
nConnectionHandle連接控制碼;
cSQLCommand傳遞到資料源的SQL語句;
CursorName存放結果集的游標名稱,缺省游標名SQLRESULT.
數值型 1執行成功;
-1出現連接層錯誤;
-2出現環境層錯誤.

22.SQLCANCEL(nConnectionHandle)
nConnectionHandle連接控制碼.
數值型 1執行成功;
-1出現連接層錯誤;
-2出現環境層錯誤.

23.SQLMORERESULTS(nConnectionHandle)
nConnectionHandle連接控制碼.
數值型 2已經沒有資料;
1執行成功;
-1出現連接層錯誤;
-2出現環境層錯誤.

24.SQLCOLUMNS(nConnectionHandl,Tablename[,"FOXPRO"|"NATIVE"]
[,CursorName])
nConnectionHandle連接控制碼;
TableName返回其列名的表的名稱;
FOXPRO|NATIVE列資訊的格式;
CursorName存放結果集的游標名稱,
缺省游標名SQLRESULT.
數值型 1執行成功;
-1出現連接層錯誤;
-2出現環境層錯誤.

25.SQLTABLES(nConnectionHandle[,cTableTypes][,cCursorName])
nConnectionHandle連接控制碼;
cTableTypes指定一個或幾個表類型,
類型有'TABLE','VIEW','SYS TEM TABLE'或者資料源特定的合法的表類型識別字,必須大寫,
若多個類型,各類型間以逗號分隔;
CursorName存放結果集的游標名稱,
缺省游標名SQLRESULT.
數值型 1執行成功;
-1出現連接層錯誤;
-2出現環境層錯誤.

26.SQLCOMMIT(nConnectionHandle)
nConnectionHandle連接控制碼.
數值型 1執行成功;
-1出現連接層錯誤;
-2出現環境層錯誤.

27.SQLROLLBACK(nConnectionHandle)
nConnectionHandle連接控制碼.
數值型 1執行成功;
-1出現連接層錯誤;
-2出現環境層錯誤.


下面讓我們來認識一下連接屬性及連接屬性參數值:

屬性名稱 數值類型 缺省值 注釋
Asynchronous 邏輯型
可讀寫 .F. .F.同步返回結果集;
.T.同步返回結果集.
BatchMode 邏輯型
可讀寫 .T. .F.由SQLMORERESULTS()逐個返回結果集;
.T.由SQLEXEC()一次返回所有結果集.
ConnectBusy 邏輯型
唯讀 不定 .F.共用連接不忙;
.T.共用連接繁忙.
ConnectString 字元型
唯讀 不定 註冊連接串.
ConnectTimeOut 數值型
可讀寫 15 設置返回連接超時錯誤之前等待的時間(秒);
0無限期等待,並且不返回連接超時錯誤;
可以是0∼600.
DataSource 字元型
可讀寫 不定 ODBC.INI檔中定義的資料源名稱.
DispLogin 數值型
可讀寫 1 1或DB_PROMPTCOMPLETE(源於FOXPRO.H),僅當缺少必要資訊時才顯示ODBC註冊對話方塊;
2或DB_PROMPTALWAYS(源於FOXPRO.H),總顯示ODBC註冊對話方塊,允許在連接前更改設置;
3或DB_PROMPTNEVER(源於FOXPRO.H),從不顯示ODBC註冊對話方塊,如果缺少必要資訊,會產生錯誤.
DispWarnings 邏輯型
可讀寫 .F. .F.不顯示錯誤資訊;
.T.顯示錯誤資訊.
IdleTimeOut 數值型
可讀寫 0 空閒超時間隔(秒),時間問隔過後,廢止活動連接;0無限期等待.
ODBChdbc 數值型
唯讀 不定 外部庫檔(FLL檔)調用ODBC可使用的內部ODBC連接控制碼.
ODBChstmt 數值型
唯讀 不定 外部庫檔(FLL檔)調用ODBC可使用的內部ODBC語句控制碼.
PacketSize 數值型
可讀寫 4096 連接所使用的網路包大小,調整該值可以改善性能.
PassWord 字元型
唯讀 不定 連接口令.
QueryTimeOut 數值型
可讀寫 0 返回一般超時錯誤之前的等待時間(秒);
0無限期等待,不返回超時錯誤;
可以是0∼600.
Transactions 數值型
可讀寫 1 1或DB_TRANSAUTO(源於FOXPRO.H),自動進行遠端表事務處理;
2或者DB_TRANSMANUAL(源於FOXPRO.H),事務處理通過SQLCOMMIT()和SQLROLLBACK()函數人工進行.
UserId 數值型
唯讀 不定 用戶標識.
WaitTime 數值型
可讀寫 100 檢查SQL命令執行情況之前經過的時間(毫秒).

三.細說連接字串(或ConnectionString):

  在SQLSTRINGCONNECT([cConnectString])函數中變數cConnectString與ADO控制項物件的ConnectionString屬性具有相同一致的內容,為可讀寫String類型,提供資料提供者或服務提供者打開到資料源連接所需要的特定資訊,就Microsoft OLE DB Provider for ODBC

  提供者來講包括Provider、driver、Server、database、DSN、UID、PWD等,在以前發表的文章中已經談過,這埵A贅述一下。

  1.Provider:字串運算式,指定OLE DB資料或服務提供者的名稱。
  三種提供者:資料提供者、服務提供者和服務元件,分為兩類,提供資料的提供者和提供服務的提供者。資料提供者擁有其自己的資料並將資料以表的格式顯露給應用程式。服務提供者通過產生和消費資料將服務封裝,使ADO應用程式中的功能得以擴大。服務提供者也可以進一步定義為服務元件,服務元件必須連同其他服務提供者或元件一起工作。
  ①.資料提供者:
  由於每個提供者都是唯一的,所以應用程式與ADO交互作用的方式在不同的提供者之間略有差別,應用時需要注意它們之間的差別。不同資料提供者(Provider)其值歸結於以下:
內容 主題 字串值
ODBC資料庫 Microsoft OLE DB Provider for ODBC MSDASQL
Microsoft? Index Server Microsoft OLE DB Provider for Microsoft Index Server MSIDXS
Microsoft? Active Directory Service Microsoft OLE DB Provider for Microsoft Active Directory Service ADSDSOObject
Microsoft? Jet資料庫 OLE DB Provider for Microsoft Jet Microsoft.Jet.OLEDB.4.0
Microsoft? SQL Server Microsoft OLE DB Provider for SQL Server SQLOLEDB
Oracle資料庫 Microsoft OLE DB Provider for Oracle MSDAORA

  ②.服務提供者:

  要使用服務提供者,必須提供關鍵字。同時,也應當知道與每個服務提供者相關聯的、特定提供者的動態屬性。當前可從Microsoft獲得的每個服務提供者的特定提供者(Provider)其值資料如下:
主題 字串值
Microsoft Data Shaping Service for OLE DB MSDataShape
MicrosoftOLE DB Persistence Provider MSPersist
Microsoft OLE DB Remoting Provider MS Remote

  2.DRIVER:字串運算式,表示ODBC驅動程式的名稱。它並不是ODBC驅動程式動態連接庫(DLL)檔案名。對於其中的定義必須用{}括起來,名稱的選擇可以通過以下途徑:
  對於Windows 9x和Windows NT:
  "開始"→"設置" →"控制面板" →"資料源(ODBC)" →"ODBC資料源管理器" →"驅動程式"中
對於Windows 2000:
  "開始"→"設置" →"控制面板"→"管理工具" →"資料源(ODBC)" →"ODBC資料源管理器" →"驅動程式"中
  可以看到下列驅動程式名稱:
Driver da Microsoft para arquivos texto (*.txt;*.csv)
Driver do Microsoft Access (*.mdb)
Driver do Microsoft dBase (*.dbf)
Driver do Microsoft Excel (*.xls)
Driver do Microsoft Paradox (*.db )
Driver para o Microsoft Visual FoxPro
Microsoft Access Driver (*.mdb)
Microsoft Access-Treiber (*.mdb)
Microsoft dBase Driver (*.dbf)
Microsoft dBase VFP Driver (*.dbf)
Microsoft dBase-Treiber (*.dbf)
Microsoft Excel Driver (*.xls)
Microsoft Excel-Treiber (*.xls)
Microsoft FoxPro Driver (*.dbf)
Microsoft FoxPro VFP Driver (*.dbf)
Microsoft ODBC for Oracle
Microsoft Paradox Driver (*.db )
Microsoft Paradox-Treiber (*.db )
Microsoft Text Driver (*.txt;*.csv)
Microsoft Text-Treiber (*.txt;*.csv)
Microsoft Visual FoxPro Driver
Microsoft Visual FoxPro-Treiber
SQL Server
Sybase System 11

  從其中選擇自己所需要的驅動程式名稱,值得指出的是有些驅動程式是微軟公司的產品在安裝作業系統時就安裝了,而有些資料庫產品的驅動程式由開發資料庫產品的軟體公司隨資料庫產品一起提供,需在安裝資料庫時選擇安裝上,才可以使用。否則在此找不到驅動程式。例如:Sybase資料庫驅動程式。
  3.SERVER(SRVR):字串運算式,一些資料介紹為伺服器名稱,經筆者實踐認為確切地應為資料庫服務名稱,由於象SQL Server、Sybase等資料庫在安裝時自動把伺服器名稱缺省設置為資料庫服務名稱,但如果只在“我的電腦” →“屬性” →“網路標識” →“屬性”中更改電腦名,而不改變資料庫服務名稱,使之不相同,在程式中應以資料庫服務名稱為准。
  4.DATABASE(DB):字串運算式,指定要與其建立連接的資料庫名稱。需要特別指出的是即使DSN定義已經指定了資料庫,也可以在DSN之外指定DATABASE參數以便連接到不同的資料庫。這同時更改了DSN定義以包括指定的資料庫。使用DSN時始終包括DATABASE參數是一種好辦法。這樣將保證能連接到正確的資料庫,因為其他用戶可能會在上一次檢查DSN定義後更改默認的資料庫參數。
  5.DSN(Data Source):字串運算式,在此為空,無須指定連接的ODBC資料源的名稱
  6.UID(User ID):字串運算式,為ODBC資料源指定用戶標識(用戶帳號名),指定用戶必須有足夠的許可權。
  7.PWD(Password):字串運算式,為ODBC資料源指定用戶口令,必須有足夠的許可權。

四.非DSN連接字串的組成:

  除了ADO所定義的參數外,提供者不支援任何特定連接參數。但是,提供者將把任何非ADO連接參數傳遞給ODBC驅動程式管理器。

  由於可以省略Provider參數,因此使用與撰寫ODBC連接字串時用的相同參數名(DRIVER=、DATABASE=、DSN= 等等)、值和語法,可以撰寫與同一資料源的ODBC連接字串相同的ADO連接字串。

  1.對於SQL Server資料庫:
[Provider=MSDASQL;]
DRIVER={Driver Name};
SERVER=server;
DATABASE=database;
UID=user;
PWD=password"
例如:
cnna.ConnectionString = "Provider=MSDASQL;"_
+ "driver={SQL Server};"_
+ "server=servera; "_
+ "database=pubs; "_
+ "uid=sa; "_
+ "pwd=yyuui"

  2. 對於Sybase資料庫:
[PROVIDER=MSDASQL;]
DRIVER={Driver Name};
SRVR=server; 注:必須是SRVR,而不能是SERVER。
DB=database; 注:可以是DB,也可以DATABASE。
DSN=; 注:該項可以省略。
UID=user;
PWD=passwod
例如:
cnnb.ConnectionString = "Provider=MSDASQL;"_
+ "DRIVER={Sybase System 11};"_
+ "SRVR=serveru; "_
+ "DSN=;"_
+ "DB=dataa; "_
+ "UID=sa; "_
+ "PWD=dqwe"_

  3. 對於Oracle資料庫:

[PROVIDER=MSDASQL;]
DRIVER={Driver Name};
SERVER=server;
databasename=database;
databasefile=path;
DSN=;
UID=user;
PWD=password;
例如:
cnnc.ConnectionString = "Provider=MSDASQL;"_
+ "DRIVER={Microsoft ODBC for Oracle};"_
+ "SERVER=Webserver; "_
+ "DSN=;"_
+ "databasename=dataall; "_
+ "databasefile=d:\data\;"_
+ "UID=dba; "_
+ "PWD=zxcv"

  4. 對於Informix資料庫:
[Provider=MSDASQL;]
Driver={Driver Name};
Host=IP Adress;
Database=database;
UID=user;
PWD=password;
FetchBufferSize=integer;
NoLoginBox=Yes;
Options=;
Protocol=TCP/IP;
ReadOnly=No;
ServerOptions=;
ServerType=Informix Version
例如:
cnnd.ConnectionString = "Provider=MSDASQL;" _
+ "Driver={OpenLink Generic 32 Bit Driver};" _
+ "Host=11.66.17.151;" _
+ "Database=pubs;" _
+ "UID=sa;" _
+ "PWD=asdf;" _
+ "FetchBufferSize=30;" _
+ "NoLoginBox=Yes;" _
+ "Options=;" _
+ "Protocol=TCP/IP;" _
+ "ReadOnly=No;" _
+ "ServerOptions=;" _
+ "ServerType=Informix 7.2"

  注:[]中的內容可以省略。

五.實例一瞥:

  伺服器安裝windows 2000 Server作業系統,以Sybase 11.9.2資料庫作為伺服器端資料庫管理資料;用戶端安裝Windows 98,Sybase用戶端程式Open Client,以Visual FoxPro 6.0資料庫作為用戶端開發工具。揚長避短,相得益彰,充分發揮Sybase資料庫安全性、可靠性高,管理資料量大;Visual FoxPrp 6.0資料庫開發人員熟悉,開發速度快,程式體積小,運行速度快,佔用資源少的特點。

  以Sybase 11.9.2為例,編制一個實用的學籍管理程式,以期達到抛磚引玉的效果;資料庫名稱為Studentdb,只包括一個表(Student),其結構如下:
欄位名稱 寬度 注釋
code nchar (22) 代號
name char (Cool 姓名
birthday nchar (Cool 生日
grade int 年級
class int 班
tuition numeric (7,2) 學費
maths numeric (5,2) 數學
chinese numeric (5,2) 語文
physicsnumeric (5,2) 物理
chemistrynumeric (5,2) 化學
history numeric (5,2) 歷史
geobiology numeric (5,2) 地理
biology numeric (5,2) 生物
gym numeric (5,2) 體育
           
  調試程式時需要注意以下問題:
  ①.伺服器端Sybase資料庫服務必須處於啟動狀態;
  ②.用戶端安裝必須選中“√”ODBC Driver元件;
  ③.用戶端通過Open Client程式組中的Dsedit元件配置連接,具體連接操作過程如下:“Dsedit”→“Add Server Object”→輸入服務名稱(Server Name)→“OK” →“單擊”選擇所輸入服務名稱→“單擊”“Server Address” →“右鍵”→“Modify Attributes”→“Add”→選擇“TCP”協議→“Network Address”在此輸入IP位址和埠號,例:10.23.12.120,5000→“Ping Server”測試是否連通,否則檢查機器連接或重複上述過程。
  ④.注意兩種資料庫資料類型的對應關係如下表:

Visual FoxPro 6.0資料庫資料類型 Sybase資料庫資料類型
字元型(C) Char
nchar
nvarchar
varchar
貨幣型(Y) money
smallmoney
數值型(N) decimal
numeric
浮動型(F) 無
日期型(D) 無
日期時間型(T) datetime
Smalldatetime
雙精度型(B) float
Real
整型(I) Int
smallint
tinyint
邏輯型(L) Bit
備註型(M) Text
通用型(G) image
字元型(二進位)(C) 無
備註型(二進位)(M) binary
varbinary

  關鍵程式段:

  *連接遠端資料源
PROCEDURE Activate
wait window at 12,20 nowait "請稍後!正在連接遠端資料源 ......"
VarDriver=THISFORM.Text1.Value
VarServer=THISFORM.Text2.Value
VarDatabase=THISFORM.Text3.Value
VarUser=THISFORM.Text4.Value
VarPassword=THISFORM.Text5.Value
Store sqlstringconnect("Provider=MSDASQL;DRIVER={"+alltrim(VarDriver)+"};
DSN=;SRVR="+alltrim(VarServer)+";DB="+alltrim(VarDatabase)+";UID="+alltrim(VarUser)+";
PWD="+alltrim(VarPassword)) to ConnHandle &&ConnHandle為連接控制碼
if ConnHandle<0
=messagebox(space(4)+" 連接遠端資料源失敗!原因如下:"+chr(10);
+"1.“SYBASE資訊”參數配置不正確;"+chr(10);
+"2.SYBASE服務("+alltrim(upper(VarServer))+")未啟動。",16,"錯誤提示:")
wait clear
close all
return
else
wait clear
……
=sqldisconnect(ConnHandle)
endif
ENDPROC
……
PROCEDURE Release
=sqldisconnect(ConnHandle)
close all
ENDPROC

  *查詢
&&結果存入自定義游標MathsCursor
=sqlsetprop(ConnHandle,'batchmode',.T.) &&設置一次返回所有結果集
=sqlprepare(ConnHandle,"select code,name,grade,class,maths from student where grade='"+Vargrade+"' and class='"+Varclass+"'","mathscursor")
=sqlexec(ConnHandle)
……
*表單中加入頁框控制項,表格控制項
THISFORM.Pageframe1.Page1.Grid1.RecordSource="mathscursor"
THISFORM.Pageframe1.Page1.Grid1.RecordSourceType=1 &&別名
THISFORM.Pageframe1.Page1.Grid1.Column1.ControlSource="mathscursor.code"
THISFORM.Pageframe1.Page1.Grid1.Column2.ControlSource="mathscursor.name"
THISFORM.Pageframe1.Page1.Grid1.Column3.ControlSource="mathscursor.grade"
THISFORM.Pageframe1.Page1.Grid1.Column4.ControlSource="mathscursor.class"
THISFORM.Pageframe1.Page1.Grid1.Column5.ControlSource="mathscursor.maths"
……

  *修改
=sqlsetprop(ConnHandle,'transactions',2) &&設置人工事務處理
=sqlprepare(ConnHandle, "update student set grade=grade+1") &&新年升級處理
=sqlexec(ConnHandle)
if messagebox("確定修改所輸入資料資訊嗎?",4+32,"運行提示:")=6
=sqlcommit(ConnHandle)
else
=sqlrollback(ConnHandle)
THISFORM.text1.setfocus
endif
……

  *刪除


Vargrade=THISFORM.Text1.Value
=sqlsetprop(ConnHandle,'transactions',2) &&設置人工事務處理
=sqlprepare(ConnHandle,"delete from student where grade='"+Vargrade+"'")
=sqlexec(ConnHandle)
if messagebox("確定刪除所輸入資料資訊嗎?",4+32,"運行提示:")=6
=sqlcommit(ConnHandle)
else
=sqlrollback(ConnHandle)
THISFORM.text1.setfocus
endif
……

  *增加
Varcode=THISFORM.Text1.Value
Varname=THISFORM.Text1.Value
……
=sqlsetprop(ConnHandle,'transactions',2) &&設置人工事務處理
=sqlprepare(ConnHandle,"INSERT INTO student(code,name,birthday,grade,class,tuition,maths,chinese,physics,
chemistry,history,geobiology,biology,gym);
VALUES('"+Varcode+"','"+Varname+"','"+Varbirthday+"',"+Vargrade+","+Varclass+",
"+Vartuition+","+Varmaths+","+Varchinese+","+Varphysics+","+Varchemistry+",
"+Varhistory+","+Vargeobiology+","+Varbiology+","+Vargym+")")
=sqlexec(ConnHandle)
if messagebox("確定增加所輸入資料資訊嗎?",4+32,"運行提示:")=6
=sqlcommit(ConnHandle)
else
=sqlrollback(ConnHandle)
THISFORM.text1.setfocus
endif
……




說在前面
熟悉 Fox 的朋友都知道,在 VFP 塈畯怚i以使用遠端視圖 (Remote View) 和 SPT(SQL Pass Through) 技術控制遠端異構資料庫。這些技術其實是 VFP 對 ODBC 的 API 的封裝,所以對於用戶來說訪問遠端資料庫就像操作傳統的DBF一樣簡單。關於這兩種技術的使用,完全可以洋洋灑灑地寫下一本書,鑒於本文主題及篇幅,這媔枚舉 SPT 技術訪問遠端資料的應用。
SPT與遠程視圖
很多人搞不懂有了遠端視圖這樣直觀、簡單的工具,為什麼還需要 SPT 呢?確實 SPT 較遠端視圖難以掌握,但細細體會你會發現:遠端視圖其實是對 SPT 的視覺化工具!SPT 較遠端視圖更具威力,遠端視圖提供的功能只是 SPT 的一個子集。仔細探索兩者優劣,我們發現:
SPT 的優勢:
1. 一次得到多個Cursor
2. 執行除 Select 以外的其他 SQL 語句,如 Insert、Update、Delete等
3. 執行遠端資料庫的存儲過程
4. 執行遠端資料庫的特殊函數、命令
5. 事務管理
SPT 的劣勢:
1. 沒有圖形用戶介面
2. 必須人工維護連接
3. 得到的Cursor默認是"可讀寫"Cursor,要使它成為"可更新"Cursor必須經過設定
下面就順著我們對 SPT 的認識,來流覽一下這種偉大的工具吧!(注意:本文所有常式均使用 SQL Server的NorthWind 資料庫演示)
 
管理連接:
建立連接:
(注意:本文所有示例代碼若用到連接的,默認採用"建立連接"代碼中產生的連接控制碼"con")
WAIT ' 連接到 SQL Server 上去 ' NOWAIT NOCLEAR WINDOW
SQLSETPROP(0,"DispLogin" ,3) && 設置環境為:"從不顯示 ODBC 登陸對話方塊"
con=SQLSTRINGCONNECT("driver=SQL Server;Server=BOE;Uid=sa;pwd=;database=northwind")
*假定 SQL Server 伺服器名為 BOE, 用戶 ID 是sa, 口令是空串
*如果你的 SQL Server 的伺服器名, 用戶 ID, 口令與上不同,請修改以上代碼中的相關部分以符合你系統中的設置
WAIT clear
IF con<=0
MESSAGEBOX(' 連接失敗 ',64,' 連接到 SQL Server 上去 ')
ELSE
MESSAGEBOX(' 連接成功 ',64,' 連接到 SQL Server 上去 ')
ENDIF
斷開連接:
SQLDISCONNECT(con)
一次得到多個Cursor
我們可以用一次 SPT 傳回多個Cursor,如下:
cSQL="SELECT * FROM EMPLOYEES"+CHR(10)+"SELECT * FROM CUSTOMERS"+CHR(10)+"SELECT * FROM PRODUCTS"
?SQLEXEC(con,cSQL,"TEMP")
SQLEXEC( ) 的返回值表示Cursor的數量,這堛藀^ 3 。這三個Cursor分別以: TEMP,TEMP1,TEMP2 命名。
執行除 SQL-Select 以外的 SQL 語句
cSQL="IF EXISTS(SELECT * FROM CUSTOMERS WHERE CUSTOMERID='TEST')"
cSQL=cSQL+" DELETE FROM CUSTOMERS WHERE CUSTOMERID='TEST'"
cSQL=cSQL+" ELSE INSERT CUSTOMERS(CUSTOMERID,COMPANYNAME) VALUES('TEST',' 這是一個測試! ')"
IF SQLEXEC(CON,cSQL)<=0
MESSAGEBOX(' 執行失敗 ',64,' 發送語句到 SQL Server 上去 ')
ELSE
MESSAGEBOX(' 執行成功 ',64,' 發送語句到 SQL Server 上去 ')
ENDIF
行文至此,也許有朋友會問:如果 SQL 語句中 CUSTOMERID 是一個變數怎麼辦呢?有兩個常用的解決方案:
拼接字串
CUSTID='TEST'
cSQL="IF EXISTS(SELECT * FROM CUSTOMERS WHERE CUSTOMERID='"+CUSTID+"')"
cSQL=cSQL+" DELETE FROM CUSTOMERS WHERE CUSTOMERID='"+CUSTID+"'"
cSQL=cSQL+" ELSE INSERT CUSTOMERS(CUSTOMERID,COMPANYNAME) VALUES('"+CUSTID+"',' 這是一個測試! ')"
?SQLEXEC(CON,cSQL)
SPT 標準變數傳遞法
CUSTID='TEST'
cSQL="IF EXISTS(SELECT * FROM CUSTOMERS WHERE CUSTOMERID=?CUSTID)"
cSQL=cSQL+" DELETE FROM CUSTOMERS WHERE CUSTOMERID=?CUSTID"
cSQL=cSQL+" ELSE INSERT CUSTOMERS(CUSTOMERID,COMPANYNAME) VALUES(?CUSTID,' 這是一個測試! ')"
?SQLEXEC(CON,cSQL)
執行遠端資料庫的存儲過程
存儲過程的好處自是不必多言,下面就讓我們看看怎樣用 SPT 調用遠端資料庫的存儲過程。下面我們演示的是 NorthWind 資料庫中的存儲過程" CustOrderHist ",它的作用是返回指定客戶關於產品的消費數量合計。據我所知,這埵釣熇堮捊g格式供大家選擇:
使用 T-SQL 的寫法:
CUSTID='VINET'
?SQLEXEC(CON,'EXEC CustOrderHist ?CUSTID','TEMP1')
使用 ODBC 的寫法:
CUSTID='VINET'
?SQLEXEC(CON,'{CALL CustOrderHist(?CUSTID)}','TEMP2')
存儲過程常常會需要返回一些變數,通用的方法就是使用輸出參數。在演示之前,我們先用 SPT 在 SQL Server 建立一個包含輸入、輸出參數的存儲過程。
cSQL="IF EXISTS(select * from sysobjects where id=object_id('MY_PROC') and OBJECTPROPERTY(id,'IsProcedure')=1)"
cSQL=cSQL+" drop procedure MY_PROC " &&如果存儲過程My_proc已經存在,就刪除它
?SQLEXEC(con,cSQL)
cSQL="CREATE PROCEDURE MY_PROC @EmployeeID int,@Desc varchar(100) output as /* 只支援尋找直接下屬 */"+chr(10)
cSQL=cSQL+" DECLARE @ROW INT"+chr(10)
cSQL=cSQL+" SELECT * FROM EMPLOYEES WHERE REPORTSTO=@EMPLOYEEID"+chr(10)
cSQL=cSQL+" SELECT @ROW=@@ROWCOUNT"+chr(10)
cSQL=cSQL+" IF @ROW>0"+chr(10)
cSQL=cSQL+" SELECT @Desc=' 找到了 '+CAST(@ROW AS VARCHAR(4)) +' 位下屬 '"+chr(10)
cSQL=cSQL+" ELSE SELECT @Desc=' 這是一位普通員工 '"
?SQLEXEC(con,cSQL)
使用 T-SQL 的寫法:
EMPID=2
DESCRIPTION=""
?SQLEXEC(CON,'EXEC MY_PROC ?EMPID,?@DESCRIPTION','TEMP1')
?DESCRIPTION
使用 ODBC 的寫法:
EMPID=2
DESCRIPTION=""
?SQLEXEC(CON,'{CALL MY_PROC(?EMPID,?@DESCRIPTION)}','TEMP2')
?DESCRIPTION
執行遠端資料庫的特殊函數、命令
如果在 SQL Server 中你有足夠的許可權,通過 SPT 你可以完全控制 SQL Server ,這塈畯抮t示"怎樣取得資料庫伺服器的時間":
?SQLEXEC(con,"select getdate() as serverdatetime","temp1")
?temp1.serverdatetime
USE IN ("temp1")
事務管理
在一些複雜的應用中,往往會有一項操作影響好幾個表的情況。就用戶端來說,發送到遠端資料庫的資料變動可能來源很多:表緩衝的多行記錄的變動,行緩衝的單行記錄變化,以及前文我們演示的直接用 SQL 語句傳遞的資料維護,林林總總……怎樣把這些更新行為控制在一個事務中要麼--一起成功,要麼一起回滾。
cSQL="DELETE FROM CUSTOMERS WHERE CUSTOMERID='BLAUS'"+CHR(10)
cSQL=cSQL+"INSERT CUSTOMERS(CUSTOMERID,COMPANYNAME) VALUES('TEST1',' 這是一個測試! ')"
SQLSETPROP(CON,"Transactions" ,2)&& 開始一個事務
IRETURN=SQLEXEC(CON,cSQL)
IF IRETURN=1
SQLCOMMIT(CON)&& 事務交付
ELSE
SQLROLLBACK(CON)&& 事務回滾
ENDIF
SQLSETPROP(CON,"Transactions" ,1)&& 重新回到自動事務處理狀態
&&就本例而言,"DELETE FROM CUSTOMERS WHERE CUSTOMERID='BLAUS'"總是不能執行的,SQL Server會返回錯誤:
&&DELETE statement conflicted with COLUMN REFERENCE constraint 'FK_Orders_Customers'.
&&The conflict occurred in database 'Northwind', table 'Orders', column 'CustomerID'.
&&所以這筆事務總是被回滾的!!
從常式中我們看到,我們開啟的事務其實是針對"連接"的,也就是說通過該"連接"的所有資料更新都包含於事務中,直到事務被回滾或交付。
SQLSETPROP(CON,"Transactions" ,2 ), 其實是開啟了人工事務處理,也就是說必須由用戶明確的給出交付或者回滾指令,事務才會結束。所以筆者以為:完成一筆事務以後,應執行 SQLSETPROP(CON,"Transactions" ,1 ) 將"連接"的事務模式設為默認的"自動",這樣可以防止用戶陷入未知的事務中去。
設為可更新
到目前為止,我們已經演示了 6 個 SPT 專題了,除了第一個"連接管理"在遠端視圖中能夠實現之外,其餘的遠端視圖都無法實現。下面我們要討論一下怎樣把 SPT 傳回的結果集合設為"可更新",總的來說遠端視圖提供的就是這個功能。
在默認狀況下, SPT 從遠端資料庫得到的Cursor是"可讀寫"的,即:可以對它進行" Select 、 Update 、 Insert 、 Delete "的操作,但資料的變化不會反映到資料源。"可更新"Cursor的特色就是可以直接將用戶端的資料變動,自動生成一系列 SQL 描述更新遠端資料庫。
實現"可讀寫"Cursor到"可更新"Cursor必須經歷以下五步的設置:
1. CURSORSETPROP("TABLES", 資料源表名 , 可更新Cursor名 )
此步驟設定的是資料源(SQL Server)待更新的表名,如果涉及多個表就這樣寫: CURSORSETPROP("TABLES","T1,T2","MyCursor") 。
2. CURSORSETPROP("KEYFIELDLIST", 關鍵字段 , 可更新Cursor名 )
此步驟是設定關鍵字段的,這個關鍵字段是可更新Cursor的欄位,而不是資料源堛瘧璁魽C
3. CURSORSETPROP("UPDATABLEFIELDLIST", 可更新欄位列表 , 可更新Cursor名 )
此步驟設定的是在可更新Cursor堶些欄位的變動要被反映到資料源,即哪些欄位時可更新的。
4. CURSORSETPROP("UPDATENAMELIST", 前後段欄位對應關系列表 , 可更新Cursor名 )
此步驟設定資料源欄位與可更新Cursor欄位的對應關係。
5. CURSORSETPROP("SENDUPDATES",.T., 可更新Cursor名 )
這個步驟是打開 SQL 發送開關,最關鍵的一步。
為便於大家理解,現將以上五步實例化:
例一:
SQLEXEC(con,"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")
例二:
SQLEXEC(con,"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")
行筆匆匆,終於把我認識的 SPT 基本操作寫完了,掌握這些,已能編寫不錯的 C/S 程式。雖然,本文是用 SQL Server 作為遠端資料庫,但是如果你使用 DB2 、 Oracle ,在 VFP 中也是一樣處理。








把資料集設為可更新
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.,如果沒有設,試圖就是可讀寫游標了,任何對視圖資料的操作都不能反映到資料源堣F。
可更新游標是那種可以進行讀寫操作,並且任何資料變動都會反映到資料源的游標:
典型的可更新游標就是可更新視圖,對它的好處我就不多加議論了,因為詳細的內容在“遠端視圖”一章堣w經討論過了。
把SQLEXEC()得到的結果集設定為可更新游標的五大步驟
在“遠程視圖”一章塈痟N反復強調,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
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")
1. 資料源表是 NorthWind 資料庫的Categories 表,可更新光表是mycursor
2. CURSORSETPROP("Tables","categories","mycursor"),TABLES屬性設定的是:被更新的資料源表Gategories
3. CURSORSETPROP("KeyFieldList","id","mycursor"),關鍵字用可更新游標的欄位名:ID,而不是資料源表的欄位名:categoryid
4. CURSORSETPROP("UpdatableFieldList" ,"id,categoryname,description","mycursor"),可更新欄位列表都用可更新游標的欄位名表示,而不是資料源表的欄位名。
5. CURSORSETPROP("UpdateNameList","id categories.categoryid,categoryname categories.categoryname,description categories.description","mycursor"),請注意這堛獐g法:每一組對應關係用逗號分開,前面寫可更新游標的欄位名,再放置一個空格,接著寫資料源表的欄位名(注意一定要加上資料源表名稱)
例二
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")
1. 這是一個三個表(Categories,Products,Suppliers)的連接結果集合,算是複雜了,我們的目標就是使所有的欄位都能更新到相應的表中。
2. 注意“Tables”屬性的寫法,涉及三個表就羅列三個表!
3. 注意“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")
1. 這個結果集來自於一個表:Order Details。
2. 注意“Tables”屬性的寫法,在SQL Server中這種帶空格的表名請用方口號分隔,Tables屬性指定的是資料源表,所以必須用:[order details]填入。
3. 注意“KeyFieldList”屬性的寫法,這個order details表的主關鍵字是一個複合關鍵字,有orderid與productid聯合組成,所以這奡N要將他們一起填入。
一個很重要的屬性——WhereType
當我們設定結果集為可更新游標後,還有一個重要的屬性沒有設定,就是WhereType。即,Where字句產生的依據,有四種情況:
CURSORSETPROP("WhereType" ,1) &&根據關鍵字
CURSORSETPROP("WhereType" ,2) &&根據關鍵字+可更新欄位
CURSORSETPROP("WhereType" ,3) &&根據關鍵字+已更新欄位
CURSORSETPROP("WhereType" ,4) &&根據關鍵字+時間戳
更詳細的內容大家可以參看“遠端視圖”章節,在那堶惕琱w經講得很多了。
回頂端
檢視會員個人資料 發送私人訊息
yls



註冊時間: 2006-11-10
文章: 3
來自: taiwan tainan

第 2 樓

發表發表於: 星期三 三月 26, 2008 10:16 am    文章主題: 引言回覆

再次感謝分享..........!!
回頂端
檢視會員個人資料 發送私人訊息
syntech



註冊時間: 2003-05-16
文章: 3819
來自: Taipei,Taiwan

第 3 樓

發表發表於: 星期三 三月 26, 2008 10:20 am    文章主題: 引言回覆

鞭屍文........

明明 help 也說的很清楚,
也有中文版 (vfp6 及 vfp9 ),
基本上欠缺的是經驗談.

不過我想更多人的理由是懶的找資料.

_________________
如果公司有下列困擾:
1. 找不到便宜,快速,簡易的 生產排程軟體
2. 不知道如何快速排定 採購計劃
3. 成本抓不準,自己算比軟體算有用
4. 想學習系統規劃,想找系統架構的顧問

請聯絡我們,也許我們幫得上忙
回頂端
檢視會員個人資料 發送私人訊息 發送電子郵件 AIM Address
impotence



註冊時間: 2005-02-21
文章: 135
來自: Hong Kong

第 4 樓

發表發表於: 星期三 三月 26, 2008 11:46 am    文章主題: 引言回覆

syntech 寫到:
鞭屍文........

明明 help 也說的很清楚,
也有中文版 (vfp6 及 vfp9 ),
基本上欠缺的是經驗談.

不過我想更多人的理由是懶的找資料.


什麼是 "鞭屍文" ?

_________________
一個常常忘記 Command 的人 !
回頂端
檢視會員個人資料 發送私人訊息
syntech



註冊時間: 2003-05-16
文章: 3819
來自: Taipei,Taiwan

第 5 樓

發表發表於: 星期三 三月 26, 2008 11:55 am    文章主題: 引言回覆

這篇是 2003/4/12 發的,
有人在 2008/3/26 從墳墓中挖出來"感謝分享",
這種行為就和 從慈湖把老蔣拉出來修理一番(或把秦檜從墓中挖出來修理),"鞭屍" 一樣,
故網路習慣上稱為 "鞭屍文"

_________________
如果公司有下列困擾:
1. 找不到便宜,快速,簡易的 生產排程軟體
2. 不知道如何快速排定 採購計劃
3. 成本抓不準,自己算比軟體算有用
4. 想學習系統規劃,想找系統架構的顧問

請聯絡我們,也許我們幫得上忙
回頂端
檢視會員個人資料 發送私人訊息 發送電子郵件 AIM Address
sken



註冊時間: 2004-02-17
文章: 59


第 6 樓

發表發表於: 星期五 三月 28, 2008 9:44 am    文章主題: 引言回覆

小弟也來抽一下~痛嗎?
回頂端
檢視會員個人資料 發送私人訊息
從之前的文章開始顯示:   
發表新主題   回覆主題    VFP 愛用者社區 首頁 -> VFP 討論區 所有的時間均為 台北時間 (GMT + 8 小時)
1頁(共1頁)

 
前往:  
無法 在這個版面發表文章
無法 在這個版面回覆文章
無法 在這個版面編輯文章
無法 在這個版面刪除文章
無法 在這個版面進行投票
無法 在這個版面附加檔案
無法 在這個版面下載檔案


Powered by phpBB © 2001, 2005 phpBB Group
正體中文語系由 phpbb-tw 維護製作