SPT指令介绍

来源:互联网 发布:只有我知免费观看全集 编辑:程序博客网 时间:2024/05/20 18:01

一指令介绍 
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等,在以前发表的文章中已经谈过,这里再赘述一下。 

  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 ( 姓名 
birthday nchar ( 生日 
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 里我们可以使用远程视图 (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 ",它的作用是返回指定客户关于产品的消费数量合计。据我所知,这里有两种书写格式供大家选择: 
使用 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 ,这里我们演示"怎样取得数据库服务器的时间": 
?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的字段,而不是数据源里的字段。 
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.,如果没有设,试图就是可擦写光标了,任何对视图数据的操作都不能反映到数据源里了。 
可更新光标是那种可以进行读写操作,并且任何数据变动都会反映到数据源的光标: 
典型的可更新光标就是可更新视图,对它的好处我就不多加议论了,因为详细的内容在“远程视图”一章里已经讨论过了。 
把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") 
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"),请注意这里的写法:每一组对应关系用逗号分开,前面写可更新光标的字段名,再放置一个空格,接着写数据源表的字段名(注意一定要加上数据源表名称) 
例二 
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联合组成,所以这里就要将他们一起填入。 
一个很重要的属性——WhereType 
当我们设定结果集为可更新光标后,还有一个重要的属性没有设定,就是WhereType。即,Where字句产生的依据,有四种情况: 
CURSORSETPROP("WhereType" ,1) &&根据关键词 
CURSORSETPROP("WhereType" ,2) &&根据关键词+可更新字段 
CURSORSETPROP("WhereType" ,3) &&根据关键词+已更新字段 
CURSORSETPROP("WhereType" ,4) &&根据关键词+时间戳

原创粉丝点击