第一部分:记录集
记录集是从数据库中按一定查询条件读入到内存中的一批记录,以供快速的操作。
记录集recordset对象的属性,方法:
BOF:当记录集记录指针指到起始记录(第1条记录)再向前移(即超过第1条记录),这时返回true.常用来对付一些出错情况。注:在BOF或EOF时使用update方法会出错。
EOF:当记录指针指到最后一条记录之后(即超过了最后1条记录)时,该属性返回true.注:当一个记录集为空时,其BOF和EOF属性都为True,可据此检测一个记录集是否为空。
AbsolutePosition:返回当前记录指针,即当前记录是第几条记录,只读。
BookMark: 设置/返回当前记录指针的书签,为字符串。如:
在当前记录处设置书签:lxn=Adodc1.Recordset.BookMark
当指针移动后回到指定书签位置:Adodc1.Recordset.BookMark=lxn.
返回记录集中记录的总数:RecordCount属性。该属性对于表形式的记录集将返回精确数目,但对于仅向前型记录集(adOpenForwardOnly),返回-1。动态记录集(adOpenDynamic)则不一定,可能返回-1,与记录集的CursorLocation有关;而对于静态记录集(adOpenStatic),也总能返回精确数目。附:在DAO中,对动态集和快照集需要先用MoveFirst和Movelast方法,再用RecordCount取得记录精确数目。
Move方法:移动记录集指针。该方法有两个参数,第一个参数指定要向前或向后移动多少条记录,第二个参数指定一个相对书签位置,表明从当前记录还是从第1条或最后1条记录开始算,缺省为0从当前记录开始移,将指针从当前位置向前(负数)或向后(正数)移动指定条记录(第二个‘按书签移动’参数设为0-adBookMarkCurrent从当前记录开始,缺省)或将指针从第1条记录算起移动指定条记录(第二个参数设为1-adBookMarkFirst从首记录)。或将指针从最后1条记录算起移动指定条记录(第二个参数设为adBookMarkLast),如:Adodc1.Recordset.Move -12,将指针从当前位置向前移动12条记录,再如Adodc1.Recordset.Move 6 , 1表示指针从首记录开始后移6条记录,即使指针移到第7条记录。Move方法有几个引申的方法,如下:
movefirst,记录集指针移到第1条记录;
movelast,记录集指针移到最后1条记录;
moveprevious,记录集指针移到上一条记录;
movenext,记录集指针移到下一条记录。
Find方法:查找满足条件的记录。
find方法简略格式为:
adodc对象.recordset.find 查找表达式(为“字段 比较符号 值”)
其他参数采用缺省,find工作方式是:从当前记录指针位置开始(含当前记录)向后逐条检索记录,遇到满足条件的1条记录就停下来,指针指到此记录。
因此,若要实现“继续寻找下1个”的功能,只要将记录指针移到下1条记录(用movenext一下),再照原样使用find即可。 而重新查找必须先用movefirst将指针指到开头。
Adodc1.Recordset.find "姓名 = ’李长春’"
其中查找表达式的样子为“字段 比较符号 值”,比较符号不仅可以是等号,还可以是>,<,<=,>=,<>,like等。其中Like和 = 很相近,只不过like专用于字符串比较,不区分字母的大小写可用通配符,而 = 号会区分字母大小写不能用通配符。
一般情况下,查找表达式常采用变量表示,由用户来确定,如下:
Dim lxn As String
Static a As String
a = InputBox("请输入查找姓名","查找")
lxn = "NAME like ’" & a & "’"
.Find lxn
LockType属性:设置记录集中的记录锁定方式,是否可修改及修改方式:有1-adLockReadOnly(只读);2-adLockPessimistic(保守式修改),当修改记录后立即将更改保存到数据源,3-adLockOptimistic(开放式修改),当修改记录后只有调用Update方法才将更改保存到数据源;4-adLockBatchOptimistic(开放式批处理修改)。当修改记录后只有调用UpdateBatch方法才将更改保存到数据源。对于ADO对象而言,该属性的缺省值为1-adLockReadOnly只读,要编辑记录则必须加以改变。
Update方法:对记录集当前记录的更改进行保存到数据库。
UpdateBatch方法:成批保存更改的多条记录。只有当记录集使用锁定方式为adLockBatchOptimistic打开时该方法才有效。使用该方法,可以加快更新速度。因为一条一条更新的话,速度慢,而多条一起更新的话,其实等同于一个更新操作,因此更快。该方法有个可选参数AffectRecords提一下,它可设为:adAffectCurrent只更新当前记录;adAffectGroup只更新当前Filter属性满足的记录;adAffectAll(缺省)全部更新,包括被当前Filter属性隐藏的记录。
CancelUpdate方法:放弃保存对当前记录自上次Update后的更改,即不保存当前所作的修改。通常在WillChangeRecord事件中进行数据验证时用。当然一般是直接将事件提供的参数adStatus设为adStatusCancel即可取消保存。这里要注意,在WillChangeRecord事件中取消一个操作,将发生“操作已取消”的错误。照我的感觉,还不如直接在要Update的代码前面去验证输入的数据。
在记录集中添加新记录,用addnew方法先在缓存中添加一个新的空记录,这时它自动成为当前记录,通过修改,然后用update方法保存,data1.recordset.update,说明:如果用Movenext等方法将记录指针移开时记录集会自动保存缓存中的记录(等于调用Update方法)。
修改当前记录,只要直接给字段赋值就可以了,注意赋值后也要用Update方法将缓存中的数据保存,否则不会自动更新,除非用MoveNext等方法将指针移开让它自动调用。
删除当前记录用Delete方法就行了。有一点要注意,删除后,记录指针仍在被删除的记录上,因此要用MoveNext等方法将指针移开,或干脆Requery刷新一下。
Sort:指定用来对全部记录排序的参照字段。
Fields:包含记录集中各字段的集合。指定某个字段格式为:fields("字段名")。可省略。如有:m$=data1.recordset.fields("姓名").value为读当前记录(用value表示)的“姓名”字段值。还可用来在代码中修改(写)记录值(不是用绑定控件),如修改记录值为“李新能”:data1.recordset.fields("姓名").value="李新能"。也可写为data1.recordset("姓名").value,括号内写明字段名或“字段索引值”,第1个字段索引值从0开始。如data1.recordset(0).value.
关闭记录集用close方法,格式为“记录集.close”。
要读或写当前记录的某个字段值,只要用“记录集("字段名")”就可以了,Fields和Value都是缺省属性,但当值是一个记录集的除外,如数据环境中Command命令对象的子命令对象。
刷新记录集(即重新打开记录集):Requery方法。在记录集打开的情况下,迅速关闭又打开一次,以达到确保记录集始终处于激活状态。
返回/设置记录集当前编辑状态:EditMode属性。有以下三个可能返回值:adEditNone没有编辑;adEditInProgress正在编辑(即当前记录已修改但未保存);adEditAdd已经用AddNew方法添加新记录但还未存盘,在缓存中的是新记录。这个属性通常用来检测某些操作状态,比如可在窗体的Unload事件中防止修改了的记录未保存就卸载。
★ AbsolutePage属性:指定当前记录所在的页。其值的范围在1—PageCount值之间,所谓页,是把Recordset对象按PageSize为标准分为若干页面,每一页(除最后一页)记录数相等(等于PageSize)。有三个特殊值:adPosUnkown未知位置;adPosBOF在文件头;adPosEOF在文件尾。
★ ActiveCommand:属性:只读属性。返回关联的Command对象,如果记录集不是由Command对象创建的,则返回Null.
★ ActiveConnection属性:设置/返回记录集基于哪个Connection对象,如果没有Connection对象,则直接指定一个连接字符串。
★ Cancel: 取消执行异步 Execute(对Connection和Command对象而言) 或 异步Open 方法调用(即通过 adAsyncConnect、adAsyncExecute 或 adAsyncFetch 参数选项调用这些方法)。
★ CacheSize属性:本地内存缓存的大小。
★ CancelBatch方法: 取消批更新模式下记录集中所有还未执行的更新。
★ Clone方法:复制一个记录集。格式:Set 记录集变量=记录集.Clone [adLockReadOnly]当指定可选参数adLockReadOnly表示创建只读的记录集副本。使用 Clone 方法可创建多个 Recordset 对象副本,这对于希望在给定的记录组中保留多个当前记录十分有用。使用 Clone 方法比使用与初始定义相同的定义创建和打开新 Recordset 对象要有效得多。新创建副本的当前记录将设置为首记录。无论游标类型如何,对某个 Recordset 对象所作的修改在其所有副本中都是可见的。不过一旦在原始 Recordset 上执行了 Requery,副本将不再与原始 Recordset 同步。关闭原始 Recordset 时并不关闭它的副本,而关闭某个副本也将不关闭原始 Recordset 或任何其他副本。用户只允许复制支持书签的 Recordset 对象。书签值是可交换的,也就是说,来自一个 Recordset 对象的书签引用可引用其任何副本中的相同记录。
★ CompareBookmarks: 比较两个书签并返回它们相差值的说明。即谁先谁后。
★ CursorLocation: 设置或返回游标服务的位置。游标:可以简单理解为指向若干行的指针。有三种设置值:adUseNone 没有使用游标服务。(该常量已过时并且只为了向后兼容才出现,通常不用)。adUseClient 使用由本地游标库提供的客户端游标,通常使用这种游标。adUseServer 使用数据提供者的或驱动程序提供的游标。
该属性应在建立连接之前设置,更改 CursorLocation 属性不会影响现有的连接。
远程数据服务用法 当用于客户端 (ADOR) Recordset 或 Connection 对象时,只能将 CursorLocation 属性设置为 adUseClient。
★ CursorType: 指示在 Recordset 对象中使用的游标类型。AdOpenForwardOnly 仅向前游标,默认值。除了只能在记录中向前滚动外,与静态游标相同。当只需要在记录集中单向移动时,使用它可提高性能。
AdOpenKeyset 键集游标。尽管从您的记录集不能访问其他用户删除的记录,但除无法查看其他用户添加的记录外,键集游标与动态游标相似。仍然可以看见其他用户更改的数据。
AdOpenDynamic 动态游标。可以看见其他用户所作的添加、更改和删除。允许在记录集中进行所有类型的移动,但不包括提供者不支持的书签操作。
AdOpenStatic 静态游标。可以用来查找数据或生成报告的记录集合的静态副本。另外,对其他用户所作的添加、更改或删除不可见。
说明:使用 CursorType 属性可指定打开 Recordset 对象时应该使用的游标类型。Recordset 关闭时 CursorType 属性为读/写,而 Recordset 打开时该属性为只读。
如果将 CursorLocation 属性设置为 adUseClient 则只支持 adOpenStatic 的设置。
★ Filter属性:过滤器。对记录集进行筛选,返回记录集中满足条件的所有记录,该属性指定一个筛选字符串,为一个“字段-比较符号-值”的条件表达式,当该属性赋值后,记录集立即变成筛选后的方式,包括如 AbsolutePosition、AbsolutePage、RecordCount 和 PageCount等属性都将改变,“变”成了一个“新”记录子集,当前记录移动到记录子集的第一个记录。而当清除 Filter 属性后,记录集立即恢复,当前记录位置将移动到原Recordset 的第一个记录。
关于“字段-比较符号-值”的说明:“字段” 必须为 Recordset 中的有效字段名。如果字段名包含空格,必须用方括号将字段名括起来。
“比较符号”必须使用的操作符为:<、>、<=、>=、<>、= 或 LIKE。
“值” 是用于与字段值(如 ’Smith’、#8/24/95#、12.345 或 $50.00)进行比较的值。字符串使用单引号而日期使用井号 #(注:在SQL中不用#号),对于数字,可以使用小数点、货币符号和科学记数法。如果 “比较符号” 为 LIKE,“值” 则可使用通配符。ADO和SQL只允许使用下划线(_) 和百分号 (%) 通配符,而且必须为字符串的尾字符。DAO只允许使用问号(?)和星号(*)作通配符.“值” 不可为 Null。在 LIKE 子句中,可在样式的开头和结尾使用通配符(如 LastName Like ’*mit*’),或者只在结尾使用通配符(如,LastName Like ’Smit*’)
Filter属性还有几个特殊值可供选择:AdFilterNone 删除当前筛选条件并恢复查看所有记录。同空字符串””。 AdFilterPendingRecords 允许只查看已更改且尚未发送到服务器的记录。只能应用于批更新模式。 AdFilterAffectedRecords 允许只查看上一次 Delete、Resync、UpdateBatch 或 CancelBatch 调用所影响的记录。 AdFilterFetchedRecords 允许查看当前缓冲区中的记录,即上一次从数据库中检索记录的调用结果。 AdFilterConflictingRecords 允许查看在上一次批更新中失败的记录。
★ GetRows方法: 将Recordset的多个记录值复制到数组中,应当先定义一个变体变量,然后将GetRows的返回值赋给它,这个变量就成了一个二维数组,其第一维下标标识原所在的列(字段),第二维下标标识原所在的行(记录),每一个交叉点就是一个值了,如:
Dim VariData As Variant
VariData = DataEnvironment1.rsCommand1.GetRows
x = UBound(VariData, 1)
y = UBound(VariData, 2)
For m = 0 To x
For n = 0 To y
Print VariData(m, n); ‘用分号表示同一字段的数据打印在同一行。
Next n
Next m
该方法格式:变体变量=记录集.GetRows([rows],[start],[fields])有三个可选参数,第一个参数Rows限制返回的记录数量,即要复制几行记录,它决定的是变体数组的第二维长度,缺省情况下,将读取记录集中的所有记录。第二个参数Start指定从哪个记录位置开始向数组复制记录,可以是一个记录书签字符串,或以下三个常数之一:adBookMarkCurrent(当前记录)adBookMarkFirst(首记录录)adBookMarkLast(尾记录);第三个参数Fields限制返回的记录字段,即要复制哪几列,它决定的是变体数组的第一维长度,缺省情况下,将读取记录集中的所有字段,该参数可设置为单个字段名字符串,或多个字段名字符串组成的数组。
注意:使用该方法复制记录值时,记录指针将随之移动,每复制一行后,指针自动移动到下一行。
★ GetString: 将 Recordset 按字符串值的变体型 (BSTR) 返回。
★ MarshalOptions: 汇集选项。指示要被调度返回服务器的记录。可选设置值:AdMarshalAll 默认值。表明所有行将返回到服务器。 AdMarshalModifiedOnly 表明只有已修改的行返回到服务器。当使用客户端 (ADOR) Recordset 时,已在客户端被修改的记录将通过称作“调度”的技术写回中间层或 Web 服务器。
★ MaxRecords: 指示通过一次查询返回 Recordset 的记录的最大数目。使用 MaxRecords 属性可对从数据源返回的记录数加以限制。该属性的默认设置为零,表明提供者返回所有所需的记录。Recordset 关闭时,MaxRecords 属性为读/写,打开时为只读。
★ NextRecordset:清除当前Recordset对象,执行下一个命令返回新的Recordset对象。当一个命令语句是复合语句(即用分号隔开的多条命令)?时,用该方法依次执行下一条命令。格式:Set recordset2=recordset1.NextRecordset。例如:
Dim rst As ADODB.Recordset
Dim strCnn As String
Dim strCmd As String
strCnn = "Provider=Microsoft.Jet.OLEDB.3.51;Persist Security Info=False;Data Source=C:\工商所收费系统\MyDatabase.mdb"
strCmd = "SELECT * FROM unitrecord;SELECT * FROM invoice" ‘AccessSQL不支持。
Set rst = New ADODB.Recordset
rst.Open strCmd, strCnn, adOpenDynamic, adLockOptimistic, adCmdText
Print rst("Name")
Set rst = rst.NextRecordset
Print rst("Name")
rst.Close
★ Open:打开一个游标,即记录集。
★ PageCount:页面数。
★ PageSize:每页大小,缺省为10。
★ Properties:
★ Resync:
★ Save:
★ Seek方法:使用索引进行查询,比用Find方法速度更快,但只能用于以表形式打开的记录集,不能用于动态记录集或快照型记录集,不能在远程服务器表上使用Seek,因为远程数据源不能以表形式打开。而且这个表预先定义了索引字段,使用Seek方法前,要在代码中用Index属性指定当前要使用的索引,格式为:记录集对象.Index=索引名。索引名是在表的设计阶段定义好的。注意索引名不等于字段名,只不过是以某个字段为标准的。设置好要使用的索引后,使用Seek进行查找,格式:Recordset对象.Seek 值,这里的值参数指定按当前索引所属字段进行查找的值,若找到,则指针指到此记录,若没找到,则EOF为True.
一般情况下,在ADO中都不用Seek进行定位,而是用SQL查询生成动态记录集。只是在DAO中有一些使用,如:
Private Sub Command2_Click()
Data1.Recordset.Index = "indexName"
Data1.Recordset.Seek "=", "李春生"
Text1.Text = Data1.Recordset(2)
End Sub
其格式有一点不同,它的第一参数指定一个比较符号,第二个参数才是值,需要在属性窗口中将DATA1的RecordsetType属性设置为0-Table。
★ Sort:
★ Source:数据源。
★ State:对象的当前状态,有adStateClosed(关闭)或adStateOpen(打开)。
★ Status:批量操作或海量操作的状态。
★ StayInSync:
★ Supports方法:判断本记录集是否具有某个方面的功能。如:是否允许增添记录If rst.Supports(adAddnew)=True then rst.Addnew,如果具有某项功能则返回True,不具备则返回False,该方法的一个参数是指定哪个方面,如adDelete是否允许删除记录,adBookmark是否支持书签设置,adUpdate是否允许更新(即修改)数据源,adIndex是否可以使用index属性设置索引,adSeek是否可用Seek方法定位记录指针。再如判断是否支持索引:MsgBox DataEnvironment1.rsCommand1.Supports(adIndex)。
记录集有五种不同的类型:
Table:表示数据库中一张表,记录集与数据库中的数据同步,可通过记录集对数据库添加,删除等操作。
Dynaset:一张查询结果集,可由多个表中不同数据组成,可通过记录集对数据库进行添加、删除等操作。
Dynamic:与dynaset相似,但它有这样的功能:当其他用户修改记录集的基表(数据库表)时,会将修改反映到这个记录集中,主要用于多用户操作。
SnapShot:一张只读的查询结果集,可包含不同表中数据记录,不能对记录添加,修改等,可用于浏览数据库。
Forward-Only:一个没游标的SnapShot记录集,只能从头到尾顺序经过所有记录,不能任意移动。
第二部分:控件
什么是绑定控件?绑定控件指的是一个窗体上的”对象“,由于创建它的那个控件设置了显示数据库信息方面的功能,通过设置对象的datasource(数据源)属性和datafield(数据字段)属性,使这个对象“绑定”于一数据库。
数据对象DATA的几个重要属性:
一,connect属性:数据库类型,缺省为ACCESS。
二,databasename属性:选定一个路径下数据库文件,可在属性窗口设置,代码中例如:Data1.DatabaseName = "d:\vb6\Nwind.mdb"
三,recordsource属性:选定数据库中的一个表,如果不在属性窗口设置,代码中写也可以,例如:Data1.RecordSource = "个体户管理"
与DATA对象绑定的对象的相关属性:
四。绑定对象的datasource属性:在属性窗口中设置,确定“绑定”到哪个数据对象,如设置为Data1
五。将绑定对象的datafield属性设置为该表中的某个字段名,如: Text1.DataField = "姓名"
以上是几个最基本的属性。
DATA对象的readonly属性:选择是否以只读方式打开数据库。
Data对象的Exclusive属性:是否以独占方式打开数据库。
Data对象的UpdateRecord方法:在不触发Validate事件的情况下保存绑定控件中的值到数据库。
Data对象的UpdateControls方法:把数据库中的记录值写到绑定控件中。即忽略当前绑定控件的值,相当于取消更改。
Validate事件:当数据被增删,修改,添加等操作前引发。
Reposition事件:当记录指针移动到新位置时引发。
ADO是以后发展的趋势,将替代DAO和RDO,ADO可访问本地数据库,也可访问远程数据库。
基于ADO对象的数据控件:Adodc(使用方法和DATA差不多,但DATA是DAO的),与Adodc绑定的控件:DataGrid控件显示记录集并可修改;DataList控件;DataCombo控件,DataRepeater控件可同时显示几个绑定控件数据。Hierarchical FlexGrid网格控件,可排序、合并等,但不能修改。Adodc的主要属性如下:
BOFAction属性:返回或设置当其记录集BOF时的动作。
EOFAction属性:返回或设置当其记录集EOF时的动作。
CacheSize:返回或设置在cache中的行数;
CommandTimeout:等待命令返回的时间(单位为秒),超时将出错。
CommandType:指明形成记录集的命令的类型,为1-adCmdText表示形成记录集的是SQL命令,为2-adCmdTable表示记录集由表构成,为4-adCmdStoredProc由存储过程生成记录集,为8-adCmdUnknown未知命令类型。
ConnectionString:通过对话框来建立连接(返回字符串)。
ConnectionTimeout:等待连接成功的时间(秒)。超时将出错。
CursorLocation:光标位置。为2-adUseServer表示采用服务器端光标,为3-adUseClient表示采用客户机端光标。
CursorType:光标类型,为1-adOpenKeyset键集光标,为2-adOpenDynamic动态光标,为3-adOpenStatic静态光标。动态光标允许用户看到其他用户对记录的修改增删,可修改数据源;静态光标是记录集的拷贝与快照,用户看不到其他用户对记录集的修改,且只读,键集光标类似动态型光标,但用户不能看到其他用户添加的记录或已删除的记录。
MaxRecord:每次从数据库中取的最大记录数。
UserName:用户名。
password:口令。
Mode:数据库打开模式,0是未知;1是只读;2是写;3是读写;16是可共享读写;4是不可共享读;8是不可共享写;12是不共享。
RecordSet:记录集。
RecordSource:记录集的数据源,指定记录集数据产生的方法。
Adodc的主要事件:
EndofRecordSet: 当记录集EOF/BOF时触发;
willChangeField: 当一个字段将被修改前触发;其中的cfields参数:返回发生改变的字段数目,fields参数:返回发生改变的字段对象。
fieldChangeComplete: 当一个字段被修改后触发;
willChangeRecord: 当一个记录将被修改前触发;
recordChangeComplete: 当一个记录被修改后触发;
willChangeRecordset: 当一个记录集将被修改前触发;
recordsetChangeComplete: 当一个记录集被修改后触发;
willMove: 一个记录即将成为当前记录前触发;
MoveComplete: 一个记录成为当前记录后触发。
对以上事件的参数,以Willmove为例说明如下:
adReason返回产生该事件的原因,如返回AdRSNAddnew(值1)是“因添加新记录而触发”,返回AdRSNClose(9)是“因关闭触发”,adrsndelete(2)是“因删除记录触发”,返回AdRsnMove(10)是“因记录移动而触发”,返回AdRsnUpdate(3)是“因更新触发”等等。可到对象游览器中找那个枚举变量去。
adStatus参数设置/返回此事件或(引发事件的)此操作的状态。adStatusOK(1)为引发事件的操作完成,为2是发生错误,为3是“不能取消引发事件的操作”,为4即adStatusCancel是“取消引发事件的操作”,如在代码中设adStatus=4,那么就取消了(引发事件的)此操作,等于没有发生此操作。
pRecordSet参数返回(引发事件的)此操作所作用的记录集。
★如何完全在代码中使用ADO控件和绑定控件?包括设置ADO的ConnectionString属性和RecordSource属性;绑定控件的DataSource和DataField属性。举一例如下:
Private Sub Form_Load()
Adodc1.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\Program Files\VB98\Biblio.mdb;Persist Security Info=False"
Adodc1.RecordSource = "Titles"
Set Text1.DataSource = Adodc1
Text1.DataField = "Title"
End Sub
其中对于ADO控件,设置其ConnectionString和RecordSource属性都是字符串,重点要注意的就是绑定控件的DataSource属性,它的值是一个对象,一定要用Set赋值。而且有一点重要常识:绑定控件实质上是绑定到记录集上的,不要简单地理解为绑定到数据控件或数据环境的Command命令对象上,这是不准确的,你应当试试在代码中直接将DataSource赋值给一个记录集。(注:对于数据对象ADO是如此,但对于ADODC控件??却不是)
★对用户输入的数据进行验证:如用户输入的是无用的数据,则取消保存和更新,对于ADO控件,应在WillChangeRecord事件中进行验证。ADO对象则在用WithEvents声明的RecordSet对象WillChangeRecord事件中,一样的。要取消保存就将事件提供的参数adStatus设为adStatusCancel,或者用CancelUpdate方法。
DataGrid表格控件:DataGrid控件包含1个Columns字段列集合,对单元格,行,列等操作方便。在设计时,在DataGrid控件上单击鼠标右键,选“检索字段”,这时就会填充指定datasource中的全部字段,然后再单击鼠标右键,选“编辑”,这时就可随意调整每列的宽度了。通过设置datagrid控件中columns字段集合的count属性和recordset对象的recordcount属性,可以规定控件显示的列数和行数。当用户选中某个单元格时,控件的text和对应column字段对象的Value属性就指向这个单元格,通过修改这两个属性可以修改当前单元格的内容。 利用datagrid控件,还可在程序运行时对各控件进行数据的动态绑定。以及随时将不需要的列进行隐藏。
DataGrid控件的属性方法和事件:
属性:AllowAddnew,AllowDelete,AllowUpdate属性:是否允许在表中增添、删除、修改记录。如果设为false实际等于表只读,也可分别单独设置。
Col,Row属性:运行中当前光标所在的列(col)和行(row),最左上角单元格为0,0开始。如姓名“李海石”在第7行第0列。
Text属性:运行时当前单元格的文本内容。
ColumnHeaders属性:是否在表的最上1行显示字段标头。
HeadLines属性:字段标头的文本行数(宽度)。缺省为1行。
DataChanged属性:表中的数据是否改变,如果设为false表数据不可修改。
VisibleCols,VisibleRows属性:在表中(不使用滚动条)可见的列数和行数。
Columns字段集合:对每1字段对象的操作。如: DataGrid1.Columns("姓名").Visible = False.隐藏"姓名"字段。用Columns(索引或关健字)来标识每个字段,其实是columns.item(索引或关健字)的缺省形式,索引值从最小0开始。Columns集合本身有count(字段列数),item(当前字段),add(在表中添加字段),remove(删除表中字段)四个属性方法。如x=Datagrid1.Columns.Count.x返回6表示有六个字段。索引为0—5。每个字段对象有其自身的属性,Alignment——记录中文本的对齐方式(如左、右、居中);Button——是否在当前记录单元格右边显示下拉箭头;Caption——字段标题;AllowSizing——是否允许用户调整本字段列宽度;Locked——字段只读;DataChanged——是否有记录被修改(本字段);DataField——捆绑字段(只读?);Text和Value——当前记录的本字段值。
BeforeUpdate,BeforeInsert,BeforeDelete,BeforeColUpdate,BeforeColEdit事件:在表中修改,插入,删除记录等之前触发,如果要取消修改或删除等,只要将事件中的参数cancel设为true即可。在修改,添加,删除等操作之后则触发AfterUpdate,AfterInsert…等事件。
RowResize,ColResize事件:在运行时改变表的行,列宽时引发。
注意:在使用数据绑定控件时,必须把绑定控件和数据控件放在同一窗体上。
Datacombo对象RowSource和listfield属性,指定下拉表框显示的某adodc的某字段,仅仅是显示而已。datasource,datafield属性,绑定某adodc控件中某字段,注:须认清一点,在绑定后,在datacombo对象文本框内的的改动会自动更新到当前记录的对应绑定字段中。也就是说它和文本框一样“用来接受数据输入”。
MSChart控件的功能:将数据以图表的形式显示。
数据库中的“关系”:是建立在两个表“之间”的链接。有一对一,一对多,多对多三种关系。
[问题:在数据库中删除一个记录时,并不真正将其删除,而只是打上个标记而已,如何真正删除这些记录呢?对一个打上删除标记的记录,如何恢复为原样,能显示出来呢?]
数据绑定控件的DataFormat属性:自定义数据的不同显示格式(自选)。
datachanged属性:绑定控件的内容是否发生变化。如果设为False,表示本控件中绑定数据不可修改。(?)
ADODC控件的connectionstring属性用来连接一个数据库,除用“连接字符串”建立连接外,还可选“使用data link文件(链接文件)”的方式建立连接,先随便在VB外创建(如桌面)一个后缀为udl的文件(只要单击鼠标右键“新建”选“Microsoft数据链接”即可),然后双击,从“提供者”卡开始完成对话框即可。有了这样一个链接文件,就可在adodc的connectionstring属性中指定这个Data link文件。使用数据链接文件的好处是:多个不同程序的ADODC可同用一个这样的链接文件,还有利于简化用ADO对象编程时代码中写的connectionstring字符串。
★ 使用数据环境DataEnvironment。
数据环境用于连接数据库,比数据控件更方便有用,在实际的数据库编程中,不少方案用了数据环境!
添加数据环境:从工程菜单中“更多ActiveX设计器”“Data Environment”就可添加一个数据环境,最好干脆在新建工程对话框中选择数据工程,还可在工具栏上打开“数据视图”窗口,其包含的工具栏上有“添加数据环境到当前工程”按纽。
使用数据环境:可将一个数据环境看成一个数据控件如Adodc,但又有ADO对象的特征,
第一步:从工程窗口双击DataEnvironment1打开它,在其中有一个缺省的Connection1对象,右键单击它,在弹出菜单中选择“属性”,即可设置要连接到的数据源,其实就是它的ConnectionString。设置好后,单击工具栏上的“添加命令”按纽,给这个Connection1对象添加一个Command1命令对象。右键选中Command1,选择“属性”,在对话框中设置从数据源中取得数据的方式(即RecordSource),如选中数据库对象,在其中选“表”,然后选择一个表名称即可。
第二步:为这个DataEnvironment1添加绑定控件:很简单,只要在DataEnvironment1中展开设置好RecordSource的Command1命令对象,会出现可用的全部字段,按住鼠标拖动字段到窗体上即可自动生成绑定控件(一个标答和一个文本框)。可同时向不同的窗体上拖放字段,都与这个数据环境绑定,可见,DataEnvironment确实比数据控件好,它在整个工程中都可见。当然也可自行添加绑定控件,需要设置好DataSource,
DataField以及DataMember属性,这里多出一个DataMember属性是要绑定到数据环境中的哪个Command命令对象(因为一个数据环境中经常包含多个命令对象)。
第三步:添加代码控制DataEnvironment.其实它就象是Adodc控件,不过在使用之前要初始化,否则会出现“对象关闭”的错误提示,初始化的方法是用语句:” DataEnvironment1.命令对象名”,如DataEnvironment1.Command1,这样就可以把Command1打开了,注意如果在代码中重复使用这句,会出现“对象已打开”的错误提示,所以应当只使用一次。其他实际的操作,和数据控件类似,比如要使记录的指针向上移动。可用DataEnvironment1.RecordSets(0).MovePrevious,也是有它的记录集(集合)的。当然需要指出,因为一个数据环境可有多个连接和命令对象,当在数据环境中添加多个命令对象时,会有多个记录集,每个命令对象有一个记录集,命名约定是”rs+命令对象名”,比如有一个命令对象Command3,那么要操作它所产生的记录集:
DataEnvironment1.rsCommand3.MoveNext
rsCommand3就是对应于Command3对象的记录集,可用于代码中进行控制。
技巧:一个数据环境可添加多个连接Connection和多个Command对象,当你选中一个对象时,在属性窗口中会显示出它的属性列表,真的和控件一样哦。
特别说明:缺省情况下,创建的连接对象和命令对象是只读的,不能修改源数据库。需要在命令对象的属性页“高级”选项卡上将锁定类型设为“3-开放式”,或直接在属性窗口中将命令对象的LockType属性设置为“3- adLockOptimistic开放式”。注意:实际上不是命令对象的LockType属性,而是它形成的记录集的LockType属性,一并放到命令对象的属性页中设置。这点与ADO对象一样,因为ADO只在RecordSet对象中有一个LockType设置。
★使用数据环境操作关联表:
大多数数据库都在多表间存在关联。关联有一对一,一对多,多对多三种。最常用的是一对多的关系。
一、关联:
首先要理解关联:关联就是能够使一个表中的记录与另一个表中的记录链接或关联的两表间连接。对于一个表中的一条记录,在另一个表中有一条或多条记录与之对应,比如我在“个体户档案”表中有一条“吴莲秀”的记录:
姓名 地址 执照号码 营业额 行业 备注
吴莲秀 吉富 1386671215 2000 零售贸易
在“发票”表中有“吴莲秀”交纳的多张管理费发票:
发票号码日期 姓名 收费起点 收费终点 金额 备注
0188035 4/1 吴莲秀 1/1/2002 1/31/2002 40
0188047 4/1 吴莲秀 2/1/2002 2/28/2002 40
0188073 4/1 吴莲秀 3/1/2002 3/31/2002 40
0188098 4/1 吴莲秀 4/1/2002 4/30/2002 40
在这种情况下,我们就可把这两个表关联起来,把“个体户档案”作源表,其“姓名”字段作为主关健字,把“发票”作目的表,其“姓名”字段作为外来关健字,创建一个一对多的关系,要注意:一个表只能有一个主关健字,可以有多个外来关健字。主关健字必须具有唯一性,即每个记录要有不同的值,这样才能正确无误地标识每条源记录,否则关联将崩溃,有一个办法就是将主关健字设为主索引,如先把“个体户档案”的“姓名”字段设为主索引,当你试图增加另一个叫吴莲秀的记录时就会出错。且最好使用数值型字段,能“自动增加字段”更好,这里使用的是字符串,不好意思。
如何创建关联?——通过在一个表中包含一个主关健字字段并在另一个表中提供一个外来关健字段,将一个引用存储到连接的记录上。主关健字是唯一标识表中每个记录的ID字段,在“可视化数据库管理器”中,以建立索引的同时选中复选框的 “主要的”来设定即可。(?)外来关健字用于存储另一个表中的主关健字以创建连接。外来关健字不用特别设定,至多改一下字段名使其与主关健字相同就可以了。
另一方面,实际上,上面两个表原是一个表,即每张发票上的应填内容为发票号码,日期,姓名,地址,执照号码,行业,营业额,起点,终点,金额,备注等,但因每个个体户的地址,执照号,行业等对同一户来说都是一样,每张发票上都有这些字段,就会造成数据的重复。把这样的信息分解到另外的表中,利用关联来实现同样的目的,可节省不少资源。这种分解数据到多个关联表中以简化结构的过程叫“规范化”(也叫标准化)。这是设计数据库时一个很重要的步骤。数据库规范化是分解表使信息重复最小化的过程。
对于两个表中有关联的字段,应使用相同的字段名,如都为“姓名”。
在ACCESS软件中,单击“关系”按纽可显示出各表间的关系,它在有关系的不同表字段间连起一条线,在源表的主关健字处,上面标有数字1,表示一条记录,到达目的表的对应外来关健字处,上面标有无穷大符号∞,表示可对应无穷多记录,这是一对多关系,象VB提供的范例Nwind.mdb数据库中就全部是这样的关系。
一对一关系就是一个表中的一条记录被连接到另一个表的一条记录上。有一点要注意:不能把一对多关系反过来看成好象一对一,比如上面每张发票记录只对应一个个体户档案记录,认为是一对一,不对!发票记录的“姓名”不能是主关健字!不唯一,必须是从主关健字的源表引出一条记录对应另一个目的表的一条记录。如下图一对一:在目的表端有一个十字线,标明了源表主关健字和目的表外来关健字。另外象上面个体户的一对多:
目的端有一个分叉,象这种图叫做气泡图,在建立表关联时事先画好作为草图很有用。
多对多在联较为复杂,第一个表中的多条记录被链接到第二个表的多条记录,反过来也是这样。
二、在数据环境中使用关联:
主要就是建立分级的命令对象,即先建立一个指向源表的Command对象,再为这个命令对象建立一个子命令对象,使它指向目的表,然后在该子命令属性页“关联”卡上,可以看到选中了“与父命令关联”复选框,而且还可看到父命令对象是指向源表的那个对象(本来就是在它下面建立的子对象嘛),在“关联定义”中定义好主关健字(父字段)和外来关健字(子字段),“添加”即可。这样,与源表(父命令)记录集当前记录关联的目的表(子命令)所有记录就存储在子命令的记录集中。再说一遍,也就是:先为源表和目的表在同一Connection连接对象下各建立一个Command对象(只建立一个指向源表的也可以),再在连接到源表的那个Command对象上建立子命令对象,使它指向目的表,然后接着在子命令属性页的“关联”选项卡上,选中“与父命令关联”复选框,将父命令选定源表,在“关联定义”中选择主关健字和外来关健字,单击添加按纽即可。这时,当指向源表的父命令对象移动记录时,指向目的表的子命令对象将与之关联的记录都生成到子对象的记录集中。现举一例:
双击工程窗口中的DataEnvironment1,在Connection1上单击右键打开属性页,选择上面提到的个体户档案的数据库。建立连接。然后在Connection1下建立两个并列的Command对象(只建一个对象指向源表也可以),在属性页“通用”卡上设置,使之分别指向源表个体户档案和目的表发票。这时,再在指向源表的那个Command命令下建立子命令对象(选中源表命令单击“添加子命令”按纽),选中新添的子命令,先在其属性页“通用”卡上设置使其指向目的表发票,然后单击“关联”选项卡,选中与父命令对象关联,并在父命令下拉框中选定指向源表的那个命令对象,然后在关联定义框架中将父对象字段(主关健字)和子对象字段(外来关健字)都选择“姓名”,单击“添加”按纽,即可。
最后是在窗体上显示源表记录和目的表中的关联记录,对于源表记录,随便怎样都可以,如直接从数据环境中拖放字段到窗体上,对于关联的目的表,因为可能同时有多条关联记录(一对多),因此最好用MSHFlexGrid全部列表显示,只要在属性窗口设置HflexGrid的DataSource和DataMember就可以了,直接将DataMember指定为那个子对象,如果在代码中设置绑定,可按如下方式写代码:
Set MSHFlexGrid1.DataSource = DataEnvironment1.rsCmdUnitRecord.Fields("CmdSubInvoice").Value
其中rsCmdUnitRecord是源表为个体户档案的对象的记录集,而子对象CmdSubInvoice确实如数据环境表中显示的那样,成了它的“字段”,只不过其Value值变成记录集,赋予MSHFlexGrid了(经验:绑定控件的DataSource不仅可指定数据控件或环境,还可直接指定记录集来绑定)。当然也可老方法绑定:Set MSHFlexGrid1.DataSource = DataEnvironment1 : MSHFlexGrid1.DataMember = "CmdSubInvoice"一样的。
设置好绑定(特别是子对象的绑定)后,当源表对象每移动当前记录时,目的表子对象的记录集就会更新,记录集中存储的都是与源表当前记录关联的记录,因此绑定到记录集的MSHFlexGrid会不断更新数据。
★在数据环境中使用记录分组和参数查询:
这两项工作都是在Command对象的属性页中设置。
将记录按某个字段分组:先设置好Connection1连接和Command1的数据源,然后在Command1的属性页“分组”选项卡上选中“分组命令对象”复选框,然后从左边选择一个字段添加到右边框中,确定即可。这样生成的记录集便具有了层次性,和GROUP BY的效果是一样的,可以用MSHflexgrid或报表Data Report来绑定。
使用带单个参数的SQL查询:在Command1的属性页“通用”卡上选中使用“SQL语句”生成记录集,然后输入在WHERE子句中带?问号的查询:SELECT [name],[money] FROM [invoice] WHERE [name] LIKE ?。这个问号就是一个参数,可以在代码中赋值,生成不同记录集。当然,仅这样参数的设置还没完成,在“参数”选项卡上为这个‘问号’设置属性,如参数名,输入/输出参数,数据类型等。
代码中赋予具体的参数值,很简单,在初始化命令对象的语句(DataEnvironment1.Command1)后面附上参数值就可以了,如:
Private Sub Form_Load()
DataEnvironment1.Command2 "符章秀"
Set MSHFlexGrid1.DataSource = DataEnvironment1.rsCommand2
End Sub
不过只能包含一个参数。而且有一点问题本人还没解决:就是如何动态地改变参数值,因为会出现“对象已打开”的错误。
★数据报表DataReport:
新建工程时选择数据工程,或直接从“工程”菜单中添加Data Report,这时就会在工程窗口中显示出DataReport1对象,它就象一个Form窗体一样,只不过界面为白色,网格点变成了稀疏的格线,而且多了几条“页标头”“页注脚”“细节”的横杠,下面就解释一下:
这几根横杠是“带-Band”,它表示了报表的结构,也是报表中在需要时可多次重复的区域。主要有:1,报表页眉/页脚,它在整个报表的头尾处出现,可让它们单独占据一页,只要将ForcePageBreak属性设为1-rptPageBreakAfter即可;当然首先要在报表中单击鼠桔右键”显示报表页眉/注脚”显示它;2,页面页眉/页脚(在界面中写为页标头和页注脚),它在报表中每页的头尾处出现,就象WORD的页眉页脚一样;3,组页眉/页脚,显示分级的查询结果时会出现这些带区,例如在关联表中,组页眉显示主表信息,其下的细节带则显示更详细的多条关联信息;组页眉/页脚包围在每个细节带的头尾外出现;4,细节Detail带,它是报表中最重要的带,位于最中心位置,显示最详细的那部分数据信息,并在一个页面内自动重复多次直到整页全部占满为止。
使用一个数据报表时,先要将它绑定到数据源上,设置其DataSource属性为数据环境,设置其DataMember为一个命令对象,然后在报表窗体上单击鼠标右键,选择“检索字段”,这时就会按绑定的命令对象来初始化报表结构,比如分级的具有子命令的命令,结构中会包含进“分组标头/注脚”带区等,经过检索字段初始化后,可在报表上添加控件以显示数据,可添加六种特定的控件RptLabel、RptTextBox等,和普通的标签文本框没什么两样,只不过专用于报表上而已。其中有一点要注意:在这六个控件中,标签,图片框、直线、形状控件都不能绑定,只有文本框和函数控件可以进行绑定,因此要显示记录集中不同记录时都要使用文本框(即在细节带区中都要使用文本框)来进行,设置其DataMember属性和DataField属性。注意:报表中的绑定与普通窗体上的绑定有点不同,它会自动枚举记录集中每条记录依次显示于报表中。另外,将控件添加到哪个带区,按具体情况而定,总之是:页标头/注脚带区在每页头尾处重复;细节带区在每页中都不断重复(其实是枚举记录集记录);分组标头/注脚包围在每次细节带区重复的外面头尾重复。看你的需要摆放和对齐控件位置。
★ 数据报表DataReport是一个对象,可以在代码中对其进行操作,如显示报表的Show方法:
Private Sub Command1_Click()
DataReport1.Show
End Sub
★ 再如将报表内容导出为HTML文档或文本文档:ExportReport方法。
Private Sub Command1_Click()
DataReport1.ExportReport rptKeyHTML, "c:\a.htm"
End Sub
其中第一个参数指定导出为HTML文档还是文本文档,rptKeyHTML为导出HTML文档,rptKeyText为导出文本文档,rptKeyUnicodeText为导出Unicode文本文档。RptKeyUnicodeHTML_UTF8为导出HTML Unicode文档,第二个参数指定导出文件的路径和名字,该方法还有其他可选参数,第三个OverWrite参数指定当文件存在时是否覆盖原文件,第四个ShowDialog参数为是否显示Export导出对话框,第五个参数Range为是否导出所有页,缺省为rptRangeAllPages所有页,可选值为rptRangeFromTo设定导出范围。第六个参数PageFrom和第七个参数PageTo只在前面参数设定为导出范围时需要设置,分别为范围起始页和终止页。如:
DataReport1.ExportReport rptKeyHTML, "c:\abc.htm", True, True, rptRangeFromTo, 2, 3
★ 再如不经预览直接打印报表:PrintReport方法,如:DataReport1.PrintReport,其参数都是可选参数,第一个ShowDialog意为是否显示打印对话框,缺省为False,只打印不显示。第二个参数Range意为是否打印所有页,缺省为rptRangeAllPages所有页,可选值为rptRangeFromTo打印指定范围,如果是这个值,则需要在第三个和第四个参数中指定打印范围的起始页及终止页,第三个参数PageFrom和第四个参数PageTo意为打印范围的起始页和终止页,这两个参数只在第二个参数为rptRangeFromTo指定一个打印范围时需要设置。例如:
DataReport1.PrintReport False, rptRangeFromTo, 1, 4
★ 报表中的动态变量:也就是程序运行时在报表中会自动代入具体值的类似符号的内置变量。%t:短格式当前时间;%d:短格式当前日期;%p:当前页码;%P:总页数;%i:报表标题;%D:当前日期;%T:当前时间。这些动态变量会自动随具体情况不同而调整,比如在属性窗口中,将一个标签rptLabel的Caption属性设为“第%p页,共%P页。”当报表运行时,显示的就是具体的数字如“第2页,共9页。”。
★在报表上显示字段的统计信息:RptFunction控件。可以显示指定字段值的总和,平均值,最大值,最小值等。注意:此控件只能放在分组注脚或报表注脚中。
控件的使用方法很简单,先向分组注脚(或报表注脚)中添加该控件,然后在属性窗口中设置其DataMember和DataField属性指到要绑定(统计)的那个字段,然后设置FunctionType为要统计的方面,有以下可选项:0-rptFuncSum字段值总和;1-rptFuncAve字段平均值;2-rptFuncMin字段最小值;3-rptFuncMax字段最大值;4-rptFuncRCnt字段的行数;5-rptFuncVCnt字段中非空值的行数;6-rptFuncSDEV字段标准偏差;7-rptFuncSERR字段标准错误。这也就决定了该控件所能进行的所有统计功能。
简单地设置好以上三个属性,就完成了所有的工作,可以打印了。
使用水晶报表Crystal Reports:
★ 使用Crystal Reports水晶报表:首先要从VB6光盘中安装,路径在Common/Tools/
VB/CrysRept/CrysTL32.exe,然后在“外接程序”中打开“报表设计器”。报表是一个单独的.rpt文件存在的。要在VB中使用,应当添加一个控件:Crystal Report Control 4.6,设置好相关属性即可。最简单只要设置ReportFilename(=报表文件路径)和Action(=1打印)就可以了。如:
Private Sub Command1_Click()
CrystalReport1.ReportFileName = "c:\abc.rpt"
CrystalReport1.Action = 1
End Sub
关健问题是我们要先用报表设计器设计好一个报表文件:从外接程序中打开“报表设计器”,创建一个报表的步骤基本上有七步:先单击“File”“New”新建一个“Standard”报表,
第一步Tables:选择报表的数据源,可以选择一个数据库文件DataFile或ODBC数据源;
第二步Links:自动创建表间关系。这一步不用设置,直接“Next”下一步;
第三步Fields:选择要添加到报表的字段,只要将需要的字段从左边数据库窗口Add到右边的报表字段窗口就可以了;
第四步Sort:指定一个Group分组字段和排序方式(如升序或降序等);
第五步Total:指定在报表中显示哪些字段的统计信息;缺省情况下,向导将可以计算的字段都添加到右边TotalFields框中,对于一个统计字段,可以指定统计内容是字段总和(SUM)还是平均值(AVERAGE),最大值最小值等,只要在下拉框中选择一种即可。(注意去掉Add Grand Totals复选框),所选择的统计信息将在报表上显示出来;
第六步Select:直接下一步;
第七步Style:选择一种报表样式和输入报表标题。
OK,可以Preview了。
如果这时你对报表还有不满意的地方,可以单击Design设计标签,进行手动调整。
完成后将报表文件进行保存。
VB中提供的Crystal Report控件的属性和方法:
Destination属性:报表的输出目标,可选择To Window窗口(预览),To Printer打印,To File到文件,To MAPI到邮件。
ReportFilename属性:指定要导出的.rpt报表文件。
SelectionFormula属性:导出准则。即设置一个筛选条件,只导出满足条件的记录。注意格式:为一个字符串“字段-比较符号-值”,但有趣的是{字段}必须用大括号括起,而不能象SQL那样用中括号!怪!例如:CrystalReport1.SelectionFormula = "{invoice.name} LIKE ’符章秀’"
GroupSelectionFormula属性:分组导出准则吧?
DataFiles属性:报表所属的数据源集合,通常是DataFiles(0)=报表所属的数据库文件路径。也就是使用单个数据库作为报表数据源。
Action属性:设为1导出报表。
SortFields属性:排序字段(集合),将报表中的记录顺序按指定字段排序。如:SortFields(0)=”+{invoice.name}”,注意格式:字段用大括号,前加+加号表示升序,前加-减号表示降序。一个报表可同时按多个字段排序,SortFields(1)=”+{invoice.money}”…。
WindowTitle属性:打印预览窗口的标题文字。
★使用公式:Crystal Reports支持一套非常丰富的计算工具和函数,可以对一个字段进行几乎任何类型的计算。
首先创建好一个报表,然后通过insert菜单Formula Field加入一个公式字段,会弹出Formula Name文本框,输入公式名,接在在“编辑公式”对话框中构造好所需公式。
构造公式的具体方法,特别是其中的语法,本人还没搞清楚!
构造好的公式可以单击Check按纽来检查正确性,如果无误的话,可以单击Accept按纽并在报表相应位置上放置该字段。
真是没看懂,比如这个公式是什么意思:
WhilePrintingRecords;’确保打印时检查公式。
NumberVar Zip5Count;
Zip5Count;=Zip5Count+1;
再如下面这个:
WhilePringingRecords;
NumberVar StateCount;
NumberVar StateTotalCount;
NumberVar StateCost;
NumberVar StateUnitCost;
NumberVar FirstClassCount;
NumberVar FirstClassCost;
If StateCount>=10 then
StateCost :=StateCost+(StateCount*StateUnitCost)
Else
FirstClassCount :=FirstClassCount+StateCount;
If StateCount>=10 then
StateTotalCount :=StateTotalCount+StateCount;
If StateCount>=10 then
StateCount;
★改变记录的排序顺序:这是报表中需要最多的一种变化。通过VB代码,将报表中的记录按不同字段进行排序,使同一个报表的记录可以改换多种打印顺序。只要设置SortFields属性就行了,如:CrystalReport1.SortFields(0) = "+{invoice.number}",可以在代码中动态改变,每改变一次后使用Action=1就会Show出一个不同打印窗口。
★打印标签:比如信封标签等。全部的工作都在报表设计器中完成。新建一个Mail Label报表,然后选择DataFile数据源,添加需要的Field字段,然后选择一种Label类型,在Choose Mailing Label Type下拉框中选择一种,非常之多,对于一种选定类型,还可手动调整它的尺寸大小,就这样吧。
★在报表中添加图象和线条等:Insert菜单Graphic项或Line项。可以在报表中调整添加的图象和线条的位置大小,也可以通过在图象或线条上的右键菜单来做更多的调整。
第三部分:SQL语言
命名规则——表名,字段名限制在30个字符内,而且只能用数字,字母和下划线,不要用中文!!且必须以字母开头。除记录内容可能用到的中文外,全部用英文:数据库名,表名,字段名,索引名,查询名等。另外,SQL语句关健字用的都是大写字母,如果出现小写字母的表名字段名等最好用中括号括起(不管是否包含空格)。???有问题?一点习惯.
不能在引号内用行连接符,如SQLStr=”SELEC _
T * FROM [invoice]”但是可以:SQLStr=”SELEC” & _
“T * FROM [invoice]”
SQL基本作用是查询,查询分为两类:选择查询——按一定查询条件从数据库中返回一个记录集;动作查询——对数据库进行建立,修改,删除等
-------------------------------------------
一,查询语言Select。(1)返回一个表中几个字段:
select 字段1,字段2… from 表名
select 姓名,行业,垫付 from BB
(2)返回多个表中的多个字段。几个表共同返回一个记录集,要用一个字段作标准,对不同表各选定字段按顺序进行组合,才能融合成1个记录集。如下:
select BB.姓名,AA.发票 from BB,AA where BB.ID=AA.ID
用Where子句将不同表记录以ID字段为标准进行组合。
-------------------------
Where子句:指定查询条件,用来筛选表中满足条件的记录。这样理解:用select可对不同字段进行筛选(纵向),而又用where子句,可对不同记录进行筛选(横向)。 如:select 姓名,行业,定额,备注 from BB Where 定额>30
返回定额在30元以上的记录,条件表达式中的运算符可以是<,>,=,<=,>=,<>,like,between,in.其中,Like是用于查找与指定字符串相匹配的字符串,可用通配符%与_,一个_只代表1个字符,一个%可代表多个字符(在DAO中通配符是*和?),注意:只在Like子句中允许用通配符。如:
select 姓名,行业 from BB where 姓名 like ‘李%’
注:where子句可同时接多个表达式,用And,Or,Not等连接,where工作的方式是:对每一条记录,将指定字段值送入表达式比较,如“定额>30”,某记录的“定额”字段值为25,则返回false,就不会进入查询结果集里。象这样一条一条检查表中的每条记录。
between运算符指定一个范围,返回在两个端点之间的记录,如下:
select 姓名,行业,定额 from BB where 定额 between 30 and 40
等价于select 姓名,行业,定额 from BB where 定额>=30 and 定额<=40
in运算符是指定几个值,如:
select 姓名,行业,定额 from BB where 行业 in(’南杂’,’百货’)
等价于select 姓名,行业,定额 from BB where 行业=’南杂’ or 行业=’百货’
注:1,引用字符串的值时,用单引号,也可以在引用中用两个双引号表示一个引号,比如[name] LIKE “李春生”写到引用中是:SQLStr=”[name] LIKE “”李春生”””
2,字段名或表名中如果含有空格,该字段名或表名要用中括号[]括起,如:
select [all name] from students.
3,如果字段名或表名过长,可用As关健字改名,表名.字段名 as 新名。如:
select a.姓名,b.主要情况 as 简介 from 个体户管理 as a,详细资料 as b Where
a . ID=b . ID
此句改动了三处:表“个体户管理”改为a,表“详细资料”改为b,字段“主要情况”改为“简介”。
-----------------------------------------
ORDER BY子句:将查询结果集按某字段排序。选择升序或降序:在字段名后用DESC是降序,缺省情况是升序。如:
select * from BB order by 姓名 DESC
表示按姓名字段降序。
GROUP BY子句和HAVING子句:对源表记录按一个指定字段值为标准进行分组,凡是值相同的就合成单一‘记录(组)’返回。这是一个特殊结果集,因为源表中可能有多条记录在此字段上值相同,但在其他字段上的值不同,注意:其他字段不能直接从结果集中显示!除作为分组标准的字段可直接从结果集显示出来,其余只能与统计函数在一起才能显示,因此主要是进行计算,如:得到每种行业的人的个数:
select COUNT(BB.姓名)as num,行业 from BB group by 行业
返回“行业=南杂;num=6”、“行业=理发;num=2”…的结果。
再如合计每种行业收取的管理费多少,如下:
select SUM(BB.累计应交)as num,行业 from BB group by 行业
而不能写成SELECT 累计应交,行业from BB group by 行业,“累计应交”字段不能直接输出到用户。
可同时用多
个字段作分组标准,表示只有在多个字段值都相同时才把它们合成一条’记录组’,如SELECT [Name],[money] FROM [invoice] GROUP BY [Name],[money]。表示只有[Name]和[Money]都相同的记录才合并到同一组。
HAVING子句:返回组内指定条件的记录(where是指定表内符合条件的记录,having是指定用group by分组的结果集内的满足条件记录)。如:
select SUM(BB.累计应交)as num,行业 from BB group by 行业 having SUM(BB.累计应交)>200 返回单个行业合计管理费超过200元的“组记录”。
再如:SELECT [Name],[money] FROM [invoice] GROUP BY [Name],[money] HAVING COUNT(*)>1,返回用Name和money分组后每条记录组包含的原表记录数大于1个的记录(组)。好象不好理解,这里的*号实际上相当于其他字段,只能与统计函数一起使用,它返回的是每条记录(组)对应的源表记录数。慢慢理解吧。
---------------------------------------------
with owneraccess option 子句:对执行查询的用户查看查询结果的权限。一般用在多用户数据库中。
-------------------------------------
字段前的“谓词”。用在一个字段前面作限制,达到某些功能,一,distinct:忽略具有重复数据的记录。如 select DISTINCT name from photos.二,TOP:获取指定数目的记录。如获取表中后10条记录:select TOP 10 * from BB;再如,获取表中的前40%记录,用PERCENT联合:select TOP 40 PERCENT * From BB.
完整的select语句语法是:
select (多个)字段 from (多个)表 in 数据库
where 筛选记录的条件表达式
group by 字段 having 条件
order by 排序字段
with owneraccess option
变量当作查询值,要用PARAMETERS关健字定义,格式:
PARAMETERS 变量1 类型,变量2 类型,…
如下:
PARAMETERS lxn integer,ldd integer
lxn=30
ldd=50
select * from BB where 定额 between lxn and ldd
★ 将查询结果集生成一个独立表:select的into子句,格式:
select 多个字段 into新建表名 from 表名 where 条件 …
select 姓名,垫付 into outmoney from BB where 垫付>0
如果不指定条件,这条语句可以将整个表复制,达到备份的效果。
-----------------------------------------------------------
使用统计函数:对数据源中特定的字段进行一些统计。使用这些函数,通常返回包含单一记录的结果集(用GROUP BY分组的除外)。每个函数作为结果集的一个字段(用AS关健字定义字段名),可同时使用多个函数。
COUNT():返回指定字段中非NULL值的记录个数,而COUNT(*)返回全部记录个数,不进行空值检查。
SUM():返回指定数值型字段的总和。
AVG():返回指定数值型字段的平均值。
MIN():返回指定数值型字段的最小值。
MAX():返回指定数值型字段的最大值。
其参数是一个字段名。格式:
函数(字段名) AS 输出到结果的字段名
括号中的字段是你想在表中检查的字段,而输出结果的字段是你想保存输出结果的字段,一般它只含单一记录,它的名字用AS关健字自定,但不能与其他字段名重复。
如:select SUM(垫付) as lxn from Bb where 垫付>20
lxn字段的值就是表BB中垫付字段数值大于20元的和,如383(元)。只有这一个记录。再如 select count(*) as x ,AVG(定额) as y from BB ,x字段返回表BB的记录数。y字段返回定额字段的平均值,它构成了结果集中唯一记录的两个字段值。
-----------------------------------------------------------
使用表间连接来返回多个表中的记录:当从多个表中检索记录时,SQL语句的工作方式是:每个表中的一条记录都与其他表的所有记录搭配生成新记录,组成结果集。如:SELECT * FROM [invoice],[UnitRecord],这样的话,返回的结果集相当庞大,是多个表记录数的乘积,比如表A有3条记录,表B有4条记录,表C有2条记录,那么SELECT * FROM A,B,C的结果就有3×4×2=24条记录,且每条记录都包含原三个表的所有字段,因此,我们通常用WHERE来限定一些条件,以只返回多表中合适的记录搭配,有一种比WHERE更好的办法,它可以满足我们更多需要,即采用表链接返回记录集。用JOIN关健字,语法:
SELECT 多个字段 FROM 表1 链接方式 JOIN 表2 ON 表1.字段1=表2.字段2
SELECT a1.name,a2.email FROM a1 INNER JOIN a2 ON a1.ID=a2.ID
在FROM子句中指明JOIN连接方式并用ON来指定条件。
链接方式有INNER和LEFT、RIGHT三种,:INNER——内链接。当两个字段的值相等时,就将两个表中的记录组合成一个新记录(其实用where子句也一样,如:
SELECT [UnitRecord].[Name],[UnitRecord].[Address], [invoice].[Money] FROM
[UnitRecord] INNER JOIN [invoice] ON [invoice].[Name]=[UnitRecord].[Name]其结果等同
SELECT [UnitRecord].[Name],[UnitRecord].[Address], [invoice].[Money] FROM
[UnitRecord],[invoice] WHERE [invoice].[Name]=[UnitRecord].[Name],不过,如果使用的是LEFT或RIGHT关健字,采用左链接或右链接,结果就不同了,这也正是比WHERE更好的地方)。
LEFT:左链接。格式:SELECT 表1.字段,表2.字段…FROM 表1 LEFT JOIN 表2 ON 表1.某字段=表2.某字段。返回左侧表中的所有记录,返回右侧表与条件匹配的记录。它的结果是:INNER JOIN的结果集+左侧表中未满足ON条件而未筛选进入INNER JOIN的其余全部记录。
RIGHT:右链接,返回右侧表中全部记录,返回左侧表中与条件匹配的记录。其结果是INNER JOIN的结果集+右侧表中的其他全部记录。LEFT JOIN和RIGHT JOIN这两个关健字只要记一个就行了,因为把两个表的左右顺序换一下,就可以用同一个关健字达到两种效果。如:
SELECT [UnitRecord].[Name],[UnitRecord].[Address],[invoice].[Money] FROM [UnitRecor
d] LEFT JOIN [invoice] ON [invoice].[Name]=[UnitRecord].[Name] 等同于
SELECT [UnitRecord].[Name],[UnitRecord].[Address],[invoice].[Money] FROM [invoice] RIGHT JOIN [UnitRecord] ON [invoice].[Name]=[UnitRecord].[Name]
技巧:采用左链接或右链接时,其中一个表的所有记录都传到了结果集,它的一些记录值可能在另一个表中并没有关联记录(即匹配ON条件的记录),这时由于多表记录总是自动进行搭配,每条结果记录都包含原多表所有字段,因此出现某些字段值为空NULL的情况,利用此特性倒是很容易找出哪些记录在另一个表中没有匹配的记录,有时具有实际意义,如查找哪些个体户连一张发票都没交,加个WHERE检测结果集对应的原表字段是否为NULL就行了:
SELECT [UnitRecord].[Name],[UnitRecord].[Address],[invoice].[Money] FROM [invoice] RIGHT JOIN [UnitRecord] ON [invoice].[Name]=[UnitRecord].[Name] WHERE [invoice]
.[Money] IS NULL
------------------------------------------------------------------
使用IN关健字在WHERE子句中实现子查询:在一个SELECT语句里包含另一个SELECT查询语句,称为子查询,这个子查询并不是任意的,有限制,它只能返回一个字段,将这个返回字段与IN关健字前的字段进行逐一比较是否相等,作为满足WHERE条件。如:SELECT SUM([Money]) AS JIFU FROM [invoice] WHERE [Name] IN (SELECT [Name] FROM [UnitRecord] WHERE [UnitRecord].[Address] LIKE "%吉富%"),返回所有吉富个体户的已交管理费总和。先用子查询找出在吉富的个体户姓名,然后从发票表中找出这些人的发票进行累计。可看到,子查询只包含[Name]一个字段,且整个子查询语句包含在括号中。一目了然。
可以在IN前面加上关健字NOT,表示与指定字段不相等的情况时,视为满足WHERE条件,恰好反过来。如上面加上NOT后表示所有不在吉富的个体户管理费总和:SELECT SUM([Money]) AS JIFU FROM [invoice] WHERE [Name] NOT IN (SELECT [Name] FROM [UnitRecord] WHERE [UnitRecord].[Address] LIKE "%吉富%")。
------------------------------------------
在SQL语句中直接使用VB函数:严格地说,只在JET引擎的Access SQL中可以使用VB中的函数,如变为小写Lcase,变为大写Ucase,以及格式化(最常用)Format函数等。使用时也很简单,只要在返回字段时用“函数(字段名) AS 别名”就可以了,如:SELECT [name],Format([Money],”¥0.00”) AS VBFUN FROM [invoice],注意要用AS关健字来重新定义返回字段名,否则ACCESS SQL将用缺省的名称Expr1001,Expr1002来命名用了函数的字段,而不会用原来的字段名。此外,如果函数有参数,不能使用VB内置的常量名形式,而直接使用数字,如:SELECT StrConv([Money],4) FROM [invoice],而不能写SELECT StrConv([Money],vbWide) FROM [invoice],这样不能识别。JET引擎毕竟是独立于VB之外的。
------------------------------------------------
★向表中添加记录:INSERT语句,格式:
INSERT INTO 表名 VALUES(完整的记录值)
INSERT INTO BB VALUES("李新宁","复印",30,"六月",180,0,"")
也可以从其他表中复制记录。格式:
INSERT INTO 表名(字段1,字段2,……) SELECT 源字段 FROM 源表。如:
INSERT INTO [Test]([Name],[Money]) SELECT [name],[Money] FROM [Invoice] WHERE [money]>40,其实这种情形有点类似嵌套的SELECT。就象前面讲到的用IN创建SELECT子查询一样。都把一条完整的SELECT作为子句。
★删除满足条件记录:DELETE语句,可同时删除多条记录,格式:
DELETE FROM 表名 WHERE 条件表达式
delete from outplay where 垫付<40
将表outplay中“垫付”小于40的记录都删除。
★修改记录:UPDATE语句,可同时修改多条满足条件记录,格式:
UPDATE 表名 SET 字段=新值 WHERE 条件
UPDATE BB SET 垫付=0 WHERE BB.姓名="李春生"
可以同时更改多个字段,字段间用逗号隔开。对于数字型字段还可以使用算术符号,如:UPDATE [invoice] SET [Name]=”李某”,[Money]=[Money]*1.04 WHERE [Name] LIKE “李%” (闲话:一个%可以代替多个字符哦,别忘了,不要用星号*)
------------------------------------------
★ 在代码中创建表:SQL的CREATE TABLE语句,格式:
CREATE TABLE 表名(字段1名 类型(大小),字段2 类型(大小),……)
例如:
cn.Execute ("CREATE TABLE 通迅录(姓名 TEXT(14),地址 TEXT(40),电话 long)")
(说明:cn是ADO对象中的connection对象变量)
注意:表名和字段名中只能包含字母数字和下划线,因此“通讯录”“姓名”等中文可能不能识别,会出错,如遇此情况,请将全部字段名改用英文!!
其中,类型指明字段的数据类型,如LONG(数字),TEXT(文本)等。大小——是指当数据类型为文本TEXT类型时,每条记录的字符串长度,要将它用括号括起,只当类型为文本时需要指定,其他类型时则不写。是个可选参数。注意:在SQL中,数居类型的写法与VB不完全一样,不同的有逻辑型Boolean写为BIT,日期型Date写为DATETIME,短整型Integer写为SHORT,此外,SQL还另有“备注”型写为LONGTEXT,“长二进制”型(如图片)写为LONGBINARY,“自动编号”型写为COUNTER(即自动增加字段!!ID),其他的与VB写法一致。如LONG,BYTE,CURRENCY等。
★ 删除表:很简单:“DROP TABLE 表名” 即可。如:
DROP TABLE 通迅录
就删除了“通迅录”这个表。
------------------
★ 添加索引:CONSTRAINT子句,它插入在create table创建表语句中,在需要建立索引的字段后面,为create table 表名(字段1 类型(大小) CONSTRAINT 索引名 索引类型,字段2 类型(大小),……)
例如:CREATE TABLE 通迅录(姓名 TEXT(14) CONSTRAINT index1 UNIQUE,地址 TEXT (40),电话 long)
上例的意思是指定“姓名”字段建立唯一索引。索引名称为index1,“索引类型”有以下三种:UNIQUE——指定该字段是唯一索引;PRIMARY KEY——指定该字段是主码(主关健字);FOREIGN KEY——指定该字段是外码(外来关健字)。
也可以用专门的建立索引语句来建立索引:CREATE 索引类型 INDEX 语句,格式:
CREATE 类型 INDEX 索引名 ON 表名(字段名)
CREATE UNIQUE INDEX index1 ON 通迅录(姓名)
★ 添加/删除字段:ALTER TABLE语句。一次只能添加或删除一个字段,格式:
ALTER TABLE 表名 ADD [COLUMN] 字段 类型 ["大小"] [“索引”]
ALTER TABLE 表名 DROP [COLUMN] 字段名
其中,ADD后是要添加的字段列表,DROP后是要删除的字段。可选参数COLUMN指定字段在表中的排列顺序位置?——好象没什么意义。如从表“通迅录”中删除“电话”字段:
ALTER TABLE 通迅录 DROP 电话
添加字段如:ALTER TABLE [test] ADD [NewField] TEXT(5),比较简单。
添加字段和删除字段时要一个一个地添加/删除,不能同时几个字段,如:alter table UnitRecord add Phone long和alter table UnitRecord add Other TEXT(40)不要写成alter table UnitRecord add Phone long,Other TEXT(40),删除时也一样一个一个来。
在实际中,我们常会遇到要对表中的字段进行更改,而直接更改是不能的,只能先删除需要更改的字段,再添加更改了的字段。
★ 删除索引:在ALTER TABLE中用CONSTRAINT子句,格式:
ALTER TABLE 表名 DROP CONSTRAINT 索引名 类型(字段名)
例如要删除通迅录表中建立在“姓名”字段上的索引:
ALTER TABLE 通迅录 DROP CONSTRAINT index1 UNIQUE(姓名)
★ 创建交叉表查询:我们查询得到的结果集中,一般还是以源数据表的某些字段来作为列标头,源数据的记录ID来作为行标头,最多只是顺序变化或筛选取舍而已,交叉表查询与此不同,在它的查询结果中,列标头和行标头信息都是查询语句从数据源记录中得到的任意数据,因而可显示特定目的的复杂查询结果。
创建交叉表查询使用关健字TRANSFORM和PIVOT,格式如下:
TRANSFORM 每个交叉点信息 SELECT 行标头信息 PIVOT 列标头信息
其中交叉点就是每个行标头和每个列标头的对应点,即表格内容所在。行标头和列标头各指定一个字段,其中,行标头可用一个完整的SELECT来限定返回值,而PIVOT直接指定一个字段,它将罗列该字段所有不同值产生多列。如:
TRANSFORM SUM([invoice].[Money]) AS [allmoney] SELECT [invoice].[Name] FROM [unitrecord] INNER JOIN [invoice] ON [invoice].[Name]=[unitrecord].[Name] WHERE [invoice].[money]>30 GROUP BY [invoice].[name] PIVOT [Invoice].[dateend]
这是一个交叉表查询。实际上,交叉表查询常用于合计与算术运算,统计数据。
第四部分:ADO对象
ADO的对象模型,包括以下七个对象。
Connection.Command,Parameter,Recordset,Field,Property,Error.此外,还包括四个集合,Fields,Properties,Parameters,Errors.
这几个对象的功能如下:Connection对象提供与包含路径,口令和连接选项的数据源的链接;Command对象保存一个针对数据源的将被执行的命令,最常见的是SQL命令或存储过程;Recordset对象保存在记录集中执行查询参数的记录以及漫游记录的光标;Error对象包含关于数据访问期间可能发生错误的错误信息;Parameter对象存储由Command对象使用的单个参数;Field对象为记录集中包含的所有字段集合;Property对象是由Data Provider驱动程序返回的数据源的属性。
ADO的核心是Connection,Recordset,Command对象。这三个对象可独立使用,也可互相连接使用。而其他对象,如Error集合存储在Connection对象中,在使用这些对象前都必须先声明对象变量,然后用Set进行赋值,才可使用,在声明时还可以用WithEvents将事件也声明进来,使得ADO对象变得象控件那样易于使用。有两个对象中包含了事件,即Recordset对象和Connection对象。只要如Dim WithEvents rst As ADODB.Recordset这样声明后,就能在代码窗口的下拉表中找到该对象,真的和ADO控件一样易于使用,连事件也大致相同。
----------------------------------
Connection对象
用于建立与数据源的连接(包括客户机/服务器结构的连接)。在大多数应用程序中最好把一个Connection对象保存为全局级或模块级,这样就不用每次执行一个操作时都去创建这个对象。
属性:
★ ConnectionString属性:连接数据源的字符串,包含了各种所需信息。如指定与1个ODBC数据源(DSN)为mine的连接,连接字符串可写为:
Dim cn as ADODB.connection
Set cn=New ADODB.connection
cn.ConnectionString="DSN=mine;UID=an;PWD=pwd"
如果不使用ODBC数据源,则连接字符串需要按以下方式设置:
cn.ConnectionString="driver={SQL Server};server=mm;uid=sa;pwd=pwd;" & "Database=mine"
上面这个是连接到远程SQL Server的连接串,即依次说明OLE DB驱动,服务器名,用户名和密码及数据库名称。如:cn.ConnectionString=”driver={SQL Server};server=www.ndlxn.com;uid=ndlxn;pwd=848484;Database=pubs”
ConnectionString用多项“设置项=值”的方式来设定与数据源的连接,每个项之间用分号隔开。对于连接字符串的写法,精确固定的语法是没有的。因为不同类型数据库,有各自的设置项。一个技巧是先在窗体上放一个Adodc控件,然后利用其ConnectionString设置时的对话框来建立好字串,再粘贴到代码中,最后将Adodc控件删除。不要以为这是很笨的方法哦,许多高手也采用它哩。
★ ConnectionTimeout属性:设置连接时的最长等待时间,缺省为15秒,超时还未连接成功的话,中止连接,并返回出错信息。
★Mode属性:指定了该connection对象的读写权限,该属性值为枚举变量ConnectionModeEnum中的一个,有adModeRead、adModeReadWrite等。到对象浏览器中去找。
★CursorLocation属性:选择不同的游标位置,只能在建立连接之前设置该属性,并建立连接才有效,对于1已经建立的连接,设置该属性对连接不会产生影响。该属性有以下常量:adUseNone——不使用游标服务;adUseClient——使用客户端游标;adUseServer——使用服务端游标。
★ DefaultDatabase属性:该属性为connection对象指定1个缺省的数据库。
★ State属性:查看一个connection对象当前状态是已经建立还是关闭。只读。
★ Version属性:返回ADO的版本号。
★ Attributes属性:设置事务的处理方式,可选值AdXactCommitRetaining通过自动调用 CommitTrans 启动新事务。或AdXactAbortRetaining通过自动调用 RollbackTrans 启动新事务 。
★ CommandTimrout属性:终止操作数据源的命令并返回一个错误的等待时间。
★ Provider属性:返回连接的数据源(即数据提供者)的名字。
★ Errors属性:Error对象实际是一个与Connection平行的对象,也有一些如Description和Number等属性,但它的集合包含在Connection对象下,其中包含了全部错误对象,需要先声明一个ADODB.Error对象,然后用Set进行赋值,如Dim cnerr As ADODB.Error Set cnerr = DataEnvironment1.Connection1.Errors.Item(0)。
方法:
★ Open方法:建立与数据源的物理连接。格式:
connection.Open ConnectionString,UserID,Password,Options
注意:该方法是使Connection获得初始化的方法,只有使用了该方法,Connection对象才真正在内存中存在。
后面的参数都是可选参数,最简单如:cn.Open(cn是1个connection对象),但如果这样则需要预先设置好ConnectionString等参数。其中,connectionstring是前面提到的连接字符串,UserID是建立连接的用户的代号,Password是建立连接的用户的密码。该参数会覆盖掉在连接字符串中设置的密码;options提供了连接选择,可选值只有adAsyncConnect异步连接,缺省为-1同步连接。
★Close方法:关闭1个数据连接对象,使该连接对象只留在本机内存中,可对其属性更改后再重新建立连接。(注:如果不是关闭对象,而是将对象从内存中清除,应使用 Set connection对象变量=Nothing.).
★ 获取数据源上的有关信息:OpenSchema方法,该方法获取与数据源有关的信息,如获取数据源中所有表的名称等。格式:Set Recordset对象=cn.OpenSchema(查询类别,[明细条目])。两个参数都是常数值,其中,每个查询类别中包含多个明细条目,每个明细条目作为返回的Recordset的一个字段,可以省略第二个参数,这时返回指定类别下的所有明细条目的信息生成一个Recordset。例如类别为“表”adSchemaTables常数中包含了TABLE_NAME(表名称)和TABLE_TYPE(表类型)等多个明细项目常数,而主要应了解类别常数adSchema…以得到数据源某方面信息,可以查对象浏览器。举例如下(得到所有表名):
Dim rstSchema As ADODB.Recordset
Private Sub Form_Load()
DataEnvironment1.Command1 ’初始化数据环境
Set rstSchema = DataEnvironment1.Connection1.OpenSchema(adSchemaTables)
Do While Not rstSchema.EOF ’获取所有表名
List1.AddItem rstSchema.Fields("TABLE_NAME")
rstSchema.MoveNext
Loop
Set MSHFlexGrid1.DataSource = rstSchema ’可看到更多信息。
End Sub
★ Execute方法:执行1个SQL查询,既可是选择查询,也可是动作查询。如:
cn.Execute "Delete From BB where 姓名 like ’嫖客店’"
但要注意:使用Connection对象的Execute方法返回的游标类型是最基本的只能读和只能向前移动的游标adOpenForwardOnly,因此,如果该方法执行一个选择查询返回一个记录集时特别要明白。
举一个完整的例子如下:
Dim cn As ADODB.Connection
Dim rst As ADODB.Recordset
Private Sub Command2_Click()
rst.MoveNext
Print rst("姓名")
End Sub
Private Sub Form_Load()
Set cn = New ADODB.Connection
Set rst = New ADODB.Recordset
cn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.3.51;Persist Security Info=False;Data Source=C:\WINDOWS\Desktop\lxn.mdb" 连接字符串
cn.Open 连接
cn.Execute "Delete From BB where 姓名 like ’嫖客店’" 动作查询
Set rst = cn.Execute("Select * from BB") 选择查询,生成记录集
Do While Not rst.EOF
List1.AddItem rst("姓名")
rst.MoveNext
Loop
End Sub
★ 事务处理方法:BeginTrans:开始1个事务;
CommitTrans:提交事务,将事务中的操作写入数据源。
RollBackTrans:滚回事务,取消操作。
当同时更新多个表时,为了保证数据一致性而必须使用事务,比如有两个表,一个是支出表,一个是余额表,当支出一项费用时,支出费用增加,余额减少,需要对这两个表同时更新,但如果不用事务,倘若在更新支出表后发生错误,则余额表没有更新,不合要求。这时就要把它们封存装到一个事务里。确保多表操作的完整性。此外,也可以用它对同一个表的多步操作进行封装,使多步操作成为单个单元。
一般地,我们在BeginTrans处加一条On Error Goto ErrNum的出错捕获语句,然后在错误处理程序中使用RollBackTrans取消事务。形如:
cn.BeginTrans
on Error Goto ErrNum
…更新表1
…更新表2
…
cn.CommitTrans
Exit Sub
ErrNum:
cn.RollBackTrans
msgbox 出错提示
事务可以嵌套,由begintrans方法返回1个长整数表示当前事务是第几层,如返回1为当前事务不包含在任何事务中。CommitTrans和RollBackTrans结束最近的BeginTrans打开的那个事务。在程序中用begintrans开始1个事务后,应使用committrans或rollbacktrans方法结束,如果不用,则在程序结束后事务全部滚回,也就是说,系统不会自动去提交任何事务。例:
cn.BeginTrans
rst.MoveNext
cn.Execute "insert into BB values(’嫖客店’,’aaa’,0,’0’,’0’,0,’0’)"
cn.CommitTrans
有两种情况需要说明一下:在事务中也可能出现问题,导致被迫放弃事务:一种情况是一个关健字段被锁定,不能进行写操作;另一种情况是字段值超出范围,如字段为Integer,但实际值大于32767,字段为Text,但值字串长超过32K等,这样会导致事务强迫放弃。
-----------------------------------------------
Command对象:
命令对象:可完成对数据库的定义,修改,数据的查询。
★ ActiveConnection属性:从属于哪一个connection对象。要用Set赋值,如:Set cmd.ActiveConnection=cn.创建一个command对象时指明该对象从属于哪一个connection对象。如果事先没有建立Connection对象,则将该属性直接指定一个连接串,ADO将为这个Command对象创建新的隐含的Connection对象,并将该字符串作为ConnectionString自动建立起连接。可以为一个connection连接对象创建多个command命令,只需要将每个command命令对象的activeconnection属性都为该connection对象名,如:
Dim cmd as ADODB.command
Set cmd=New ADODB.command
Set cmd.ActiveConnection=cn (说明:cn是前面举例的connection对象)
★ CommandText属性:命令内容,为1条SQL选择或动作查询,或表名等。如:
cmd.CommandText="DELETE FROM students WHERE ID=98001"
★ CommandTimeout属性:等待命令执行完的最长时间,超时将中止该命令。如:
cmd.CommandTimeout=20 (单位为秒。)
★ CommandType属性:command对象的类型,可选值有:adCmdText(SQL语句),adCmdTable(表),adCmdStoredProc(存储过程)缺省为adCmdUnknow未知命令类型。例:
cmd.CommandText="BB"
cmd.CommandType=adCmdTable (是一张表)
★ Prepared属性:第1次执行时是否进行编译,以提高以后的执行速度。如:
cmd.Prepared=True表示进行命令的预编译,提高以后的执行速度。
★ Execute方法:执行命令。有两种情况,如果命令会返回记录,如Select或干脆就是1个表名等,则要将返回记录(当作记录集)赋予1个Recordset对象,格式为
Set Recordset对象=command对象.Execute()
如果命令不返回记录(如Update,Delete等),则直接用"command对象.Execute"即可。
★ State属性:对象的当前状态,可能值有:adStateClosed对象已关闭;adStateOpen对象已打开;adStateConnecting对象正在连接;adStateExecuting正在执行命令;adStateFetching表明Recordset对象的行正在被取回。State属性实际是一个通用属性,因为在连接对象Connection,命令对象Command,记录集Recordset中都有这个属性。
★ CreateParameter方法和Parameters集合:创建1个新的Parameter对象,如果CommandText(命令)是带参数的SQL Server存储过程,可用此方法创建参数对象,格式:
Set parameter对象= command对象.CreateParameter(对象名name,参数类型type,输入/输出参数direction,参数长度size,参数值value)
其中,Type指定对象值的数据类型如adInteger,adVariant等;Direction参数指定参数类型,可选值有adParamUnknown未知;adParamInput输入参数;adParamoutput输出参数;adParamInputOutput输入/输出参数;adParamReturnValue是一个返回值参数。
Size参数指定对象值的最大长度。
Value:对象的值。
用CreateParameter方法仅在内存中创建参数对象,并不真正包含进Command对象中,要用命令对象中Parameters集合的Append方法添加上,才算真正建立。格式:Command对象.Parameters.Append Parameter对象变量。
我们通常在打开SQL Server上带参数的存储过程时使用此方法传送所需参数,例如:
Dim cn as ADODB.Connection
Dim cmd as ADODB.Command
Dim rst as ADODB.Recordset
Dim param as ADODB.Parameter
Set cn=New ADODB.Connection
cn.Open “driver={SQL Server};server=www.ndlxn.com;uid=ndlxn;pwd=848484;
database=pubs”
Set cmd=New ADODB.Command
cmd.ActiveConnection=cn
cmd.CommandText=”mystoredinsqlserver” 存储过程的名称。
cmd.CommandType=adCmdStoredProc
Set param=cmd.CreateParameter(“par1”,adBoolean,adParamReturnValue)
cmd.Parameters.Append param
Set param=cmd.CreateParameter(“par2”,adInteger,adParaminput,,Val(text1.text))
cmd.Parameters.Append param 下面只用一行也可以达到同样的添加参数目的。
cmd.Parameters.Append cmd.CreateParamter(“par3”,adInteger,adParamOutput)
Set rst=cmd.Execute
Msgbox rst(0).Value
Msgbox cmd(“par1”)
Msgbox cmd(“par3”)
这里,三个参数中,par1是一个返回值,par3是一个输出参数,可以在程序中显示出来。
参数查询例如我们想让程序运行时,由用户自己来输入commandtext命令的where参数值,建立1个Parameter对象,用如下的方式来创建和使用参数:
cmd.CommandText="DELETE FROM students WHERE ID BETWEEN ? AND ?"
其中的两个问号未直接给出值,相当于两个“变量”,要用Parameter参数对象。
Dim Par as ADODB.Parameter
Dim Par1 as ADODB.Parameter
Set Par =New ADODB.Parameter
Par.Name= “myid”
Par.Type=adInteger
par.size=5
par.value=98001 ‘只要赋予变量即实现用户控制,如par.value=cint(text1.text)
par.Direction=adParamInput
cmd.Parameters.Append par
Set Par1=New ADODB.Parameter
par1.name= ”my”
par1.type=adinteger
par1.size=5
par1.value=98008
par1.Direction=adParamInput
cmd.Parameters.Append par1
cmd.Execute
这段代码是查询students表中98001—98008之间的所有记录,在command对象cmd的变量集中的变量par,par1会自动依次代入两个?号。
在实际使用中,如果不知参数的类型,可设type为adVariant(变体),参数的name,
size和direction是可选属性,可用缺省值。再举1例:
Private Sub Command2_Click()
cmd.CommandText = "select * from BB where 姓名 like ?"
Set par = cmd.CreateParameter ("abc", adVariant, adParamInput, 6,Text1.text)
’Set par = New ADODB.Parameter 上面这一句顶这么多!
’par.Name = "abc"
’par.Size = 6
’par.Type = adVariant
’par.Value = Text1.Text
’par.Direction = adParamInput
cmd.Parameters.Append par
Set lxn = New ADODB.Recordset
Set lxn = cmd.Execute()
End Sub
★Cancel方法:取消一个未执行的,异步的Execute或Open方法的调用。前面讲过。
------------------------------
Recordset对象补充
★ CursorLocation属性:指定记录集的光标位置,有adUseServer和adUseClient两种。如果在connection对象连接前未指定游标,则必须在此设置。
★ CursorType属性:光标类型。
★ UpdateBatch方法:同时保存多条被更改的记录。
★ Open方法:建立1个记录集,格式:
Recordset.Open Source,Activeconnection,Cursortype,Locktype,Options
其中,Source即RecordSource参数可以是1个查询、存储过程名或表名等;或者1个Command对象变量名(此时要省略ActiveConnection参数,即为空),ActiveConnection参数指明该记录集基于哪个Connection连接对象,这个连接对象必须是已建立的连接,当没有Connection对象时,该参数就直接指定一个ConnectionString连接串;Cursortype指明游标类型,Locktype指明记录锁定方式(记录集是否可修改/只读),Options是说Source参数中内容的类型,如表,存储过程等,与Command对象的Commandtype类似。
例如:
rst.Open "students",cn,adOpenDynamic,adLockOptimistic,adCmdTable
使用Open方法,不要事先建立Connection和Command对象,也可打开数据源——其实,它们三个对象本来就是平行的嘛,如:
Dim rst As New ADODB.Recordset
Private Sub Form_Load()
Const cnStr = "Provider=Microsoft.Jet.OLEDB.3.51;Persist Security Info=False;Data Source=C:\工商所收费系统\MyDatabase.mdb"
rst.Open "select * from Unitrecord", cnStr, adOpenDynamic, adLockOptimistic
End Sub
只要这么几句,就打开一个记录集了。
★ Save方法:将记录集存为1个文件。本方法不会关闭记录集。格式:
recordset对象变量.Save 路径和文件名
该方法在记录集建立后才能使用。在第1次使用该方法存储记录集后,如果需要往同一文件存储同样的记录集,要省略文件名。
我在使用ADO对象时遇到1难题:竟没用来!我在声明段和Form_load事件中声明了对象变量,也设置了connectionstring,open属性,也给记录集对象赋予了Execute方法得到的记录,可是,记录集对象不可用,如:(红色代码为修改后的正确写法。)
Dim cn As ADODB.Connection
Dim cmd As ADODB.Command
Dim rst As ADODB.Recordset
rivate Sub Form_Load()
Set cn = New ADODB.Connection
cn.ConnectionString = "FILE NAME=C:\WINDOWS\Desktop\Savelink.UDL"
cn.Cursorlocation=adUseClient
cn.Open
Set cmd = New ADODB.Command
Set cmd.ActiveConnection = cn
cmd.CommandText = "select * from sub1"
Set rst = New ADODB.Recordset
‘ Set rst = cmd.Execute() ‘缺省情况下,记录集为只读,如果要修改记录,需要设定记录集的LockType属性,或在记录集对象的OPEN方法中一并设置。
rst.Open "sub1", cn, adOpenDynamic, adLockOptimistic
(注:第1个参数”sub1”也可采用1个command对象名,但那样的话要省略后面cn,如下:
rst.Open cmd, , adOpenDynamic, adLockOptimistic)
Label2.Caption = "本过程共" & rst.RecordCount & "步。"
rst . addnew
rst(0) = "搞试验"
rst(1) = "我的实验"
rst.Update ‘这句不能丢!设为adLockOptimistic对记录的修改不会自动进行保存!!!!
End Sub
执行到label2.caption=…rst.RecordCount…和rst . addnew时就出错了,好象根本就没有rst似的。
为什么?缺省情况下,ADO对象中connection对象是无游标的,必须在open之前设置好其CursorLocation属性(也可以设置Recordset对象的CursorLocation属性),而用connection或command对象赋予的记录集是只读的,不能Addnew,要全面操作数据库必须用记录集的Open方法