1 / 248

第 12 章 应用开发实例

第 12 章 应用开发实例. 本章学习目标 l 理解 ADO 对象结构和编程模型,并正确为项目添加 ADO l 通过在 Delphi 中使用数据库对象加深对 SQL Server 数据库的理解 l 完成基于 SQL Server 的数据库系统实例开发. 12.1 ActiveX 数据对象 ——ADO. 12.1.1 ADO 对象结构 1 . ADO 简介

tania
Download Presentation

第 12 章 应用开发实例

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第12章 应用开发实例

  2. 本章学习目标 • l理解ADO对象结构和编程模型,并正确为项目添加ADO • l通过在Delphi中使用数据库对象加深对SQL Server 数据库的理解 l完成基于SQL Server的数据库系统实例开发

  3. 12.1 ActiveX数据对象——ADO 12.1.1 ADO对象结构 1.ADO简介 ADO(Active Data Objects)是微软公司推出的一个功能强大的数据库应用编程接口,它的主要功能是用于应用程序与OLE DB兼容的数据源的连接。应用程序可以通过ADO实现对各种类型数据库的连接,对数据的查询、修改、更新等,因而,通过ADO存取数据已经成为最佳选择。 介绍ADO,不能不提到UDA。Universal Data Access (UDA)是微软公司推出的对数据库操作的一个策略,它通过易用的API接口能在一个程序中从多种数据源中轻易的访问数据。UDA通过Microsoft Data Access Components(MDAC)来实现,而MDAC则包括ADO、Open Database Connectivity(ODBC)与OLE DB。其中,OLE DB被微软公司归类为系统级的接口,定义了一套COM接口,提供从关联数据库及文件系统访问数据的能力,设计用来给系统级的程序员使用。它虽然灵活、功能强大,但仍属于较低级的接口,并且对程序员的要求较高,需要较高水平的知识。ADO是在OLE DB之上的一个层面,被用来沟通这个低级接口与数据库,简化并实现OLE DB的强大功能,它是为应用程序员设计的。ODBC为了向后兼容也包含在MDAC中,但ODBC有被OLE DB替代的趋势。OLE DB可直接用于Microsoft Access、Microsoft SQL以及Oracle等。ODBC、OLE DB、ADO在访问数据存储体时的层次关系如图12-1所示。

  4. 图12-1 ODBC,OLE DB,ADO的层次关系

  5. 2.ADO对象结构 图12-2给出了ADO对象总体结构。如图中所见,ADO存在五个主要的对象: • lConnection 程序和数据存储之间的连接。 • lCommand 允许运行相对于数据存储的命令。 • lRecordser 包含从数据存储的特定操作中返回的所有数据。 • lRecord 允许处理半结构(semi-structured)存储中存储的数据(如在某个目录结构中的文件),就像这些数据记录在数据库中一样。 • lStream 允许处理Web资源中的数据,如HTML文件。 ADO的五个主要对象处在同一层次上,也就是说,可以在程序中建立任何一个所需要的对象,而无需建立父级对象。例如,可以使用Recordset对象产生数据存储的直接请求,此时不需要首先建立显式的Connection对象,ADO将自动进行这些必要的工作。

  6. 还有四个子对象——Property、Parameter、Field和Error(以及它们的相关集合Propertys, Parameters, Fields和Errors),图12-2中只给出了三个集合,Properties集合被有意隐去,这样可以很容易地看到主对象相互之间的作用关系。Properties集合与其他对象之间的关系如图12-3所示。 图12-2 ADO对象结构

  7. 图12-3 Properties集合与其他对象之间的关系

  8. Delphi将ADO的一些常用对象,封装为TADOConnection, TADOCommand, TADODataSet。另外,为了与Delphi接口的统一,Delphi亦建立了几个类似BDE组件的TADOTable, TADOQuery, TADOStoredProc,这些都放在ADO选项卡中。为了方便读者掌握和理解后面用Delphi开发的综合实例,我们先对Delphi中的ADO组件作简要介绍。

  9. 12.1.2 TADOConnection组件 TADOConnection组件封装ADO的Connection对象,它专用于数据库的连接,且可以提供作为多个TADODataSet, TADOCommand共享的数据来源。虽然ADOConnection并非必要,因为ADOCommand, ADODataSet都可以通过ConnectionString属性直接连接到数据存储体,但是,通过单一ADOConnection连接有两个最大的优点,就是它能减少资源的浪费,同时,它允许我们建立跨多个DataSet的事务。

  10. 1.TADOConnection组件常用的属性 • lCommandCount 通过ADOConnection连接已打开的ADOCommand对象。 • lCommands 通过ADOConnection连接已打开的ADOCommand对象数组。 • lConnected Connected属性用来设置连接,也用来检查目前是否处于连接打开的状 态。 • lConnectionString 设置ADO连接字符串参数,其参数定义如下所示: • uProvider 数据提供者的名称。 • uFile name 包含连接信息的文件名称。 • uRemote Provider 提供客户端连接的远程数据提供者名称。 uRemote Server 提供客户端连接的服务器路径名称。

  11. 这些参数虽然看似复杂,但我们可以利用它的向导帮助,很轻松地设置这个参数字符串,步骤如下:这些参数虽然看似复杂,但我们可以利用它的向导帮助,很轻松地设置这个参数字符串,步骤如下: ①进入Delphi集成开发环境,单击【ADO】选项卡,如图12-4,向Form中添加一个【ADOConnection】对象,选中该对象,如图12-5。 图12-4 【ADO】选项卡

  12. 图12-5 向Form中添加一个ADOConnection对象

  13. ②在如图12-6所示的【Object Inspector】属性设置窗口中,选择【ConnectionString】辅助按钮或由组件的快捷菜单【Edit Connection String】进入设置对话框,如图12-7。 图12-6 【属性设置】窗口图12-7 【ConnectionString】设置对 话框

  14. ③选择【Build...】按钮,打开【数据链接属性】对话框,如图12-8所示。③选择【Build...】按钮,打开【数据链接属性】对话框,如图12-8所示。 图12-8 【数据链接属性】对话框

  15. ④单击【下一步】按钮,设置【连接】选项卡,选择服务器名称、用户名称、密码、数据库名称等,如图12-9;可以单击【测试连接】按钮,测试是否连接成功,单击【确定】按钮完成设置,如图12-10所示④单击【下一步】按钮,设置【连接】选项卡,选择服务器名称、用户名称、密码、数据库名称等,如图12-9;可以单击【测试连接】按钮,测试是否连接成功,单击【确定】按钮完成设置,如图12-10所示 图12-9 设置【连接】选项卡

  16. 图12-10 完成设置对话框

  17. lConnectionTimeout 设置尝试连接的时间秒数,默认15秒。超过指定时间时,若尚未连接成功或取消连接,则中断连接要求,并触发异常(Exception)。 • lConnectOptions 连接选项,用来设置同步或异步连接,默认同步。通常,除非连接的服务器很慢,否则,不需要设置为异步连接。 • lCursorLocation 指定采用客户端或服务器端记录指针,默认采用客户端指针(clUseClient)。虽然采用服务器端指针比较缺乏灵活性,但有时候为了防止空间不足,或者配合特定数据库系统的访问方式,会采用服务器记录指针。 • lDataSetCount 通过ADOConnection连接、已打开的DataSetCount对象。 lDataSets 通过ADOConnection链接、己打开的DataSets对象数组。

  18. lErrors Errors实现ADO模型的错误集合,但很少(也不建议)直接使用,请参考Microsoft Data Store SDK说明。 • lProperties Properties属性记录ADO模型对应的Properties集合对象,请参考Microsoft Data Store SDK说明。 • lProvider 指定ADO连接的数据提供者(见图12-6)。 • lState 取得目前ADOConnection的连接状态,可能的状态如下所示: • uStClosed ADOConnection未连接,无法使用。 • uStOpen 己连接(但不一定成功)。 • uStConnecting 正在尝试连接中。 • uStExecuting 正在执行指令。 • uStFetching 正在提取数据。 lVersion 取得ADO目前使用版本。

  19. 2.TADOConnection组件常用的方法 • lBeginTrans 开始一个新的事务,其对象为ADOConnection连接的数据保存体。调用BeginTrans成功后,触发OnBeginTransComplete事件,并将属性InTransaction设为True。 • lCancel Cancel仅用于异步的数据连接,并且,该连接必须在调用Open后,但尚未连接成功前。 lCommitTrans 用来确认事务的执行,将该事务开始直到调用CommitTrans期间所有对数据库的操作改变,写回数据库。成功时触发OnCommitTransComplete事件,并结束事务(InTransaction属性设为False)。

  20. lExecute 执行CommandText属性的SQL命令字符串,其参数中,ExecuteOptions用来设置Execute的选项,可能值如下所示: • uEoAsyncExecute 以异步执行。 • uEoAsyncFetch 以异步提取数据。 • uEoAsyncFetchNonBlocking 无阻碍地以异步方式提取数据。 • uEoExecuteNoRecords 不返回记录。 • lGetFieldNames 取得数据库中指定数据表的所有字段。 • lGetTableNames 取得数据库中,所有的数据表名称,默认只取得非系统数据表。 lRollbackTrans 用来取消事务的所有变动,并结束该事务。调用RollbackTrans成功后,触发OnRollbackTransComplete事件,并且将InTransaction设为True。

  21. 3.TADOConnection组件常用的事件 • lOnBeginTransComplete 当BeginTrans成功后,会触发这个事件,参数中,TransactionLevel表示成功的这个事务的事务层数。 • lOnCommitTransComplete 当CommitTrans成功后,会触发这个事件。 • lOnConnectComplete 连接到数据保存体成功时,触发这个事件,这个事件通常通过 Connected设为True或调用Open方法触发。 • lOnDisconnect Connected设为False或调用Close方法触发这个事件。 lOnExecuteComplete 当成功调用Execute方法时,会触发此事件,参数中,Connection表示执行此命令的Connection对象,RecordsAffected则取得成功执行此命令受影响的记录条数。

  22. lOnWillConnect 当Connected设为True或调用Open方法尝试连接时,触发这个事件。 lOnWillExecute当调用Execute在真正执行前,会触发此事件。  12.1.3 TADOCommand组件 TADOCommand组件用来处理无返回DataSet的SQL指令,它对应到ADO模型的Command对象,通过Execute方法执行CommandText属性中的SQL指令(若包含参数,则由Parameters属性设置)。

  23. 1.TADOCommand组件常用的属性 • lCommandObject 用来直接访问ADO对象模型的Command对象,这对不直接由TADOCommand组件提供的属性、方法,是非常有用的。直接访问Command对象必须对ADO有较深入的了解,请读者参考"Microsoft Data Store SDK"文件说明。 • lCommandText 设置或取得TADOCommand执行的SQL指令字符串。 • lCommandType 设置或取得指令类型,也就是告诉TADOCommand该如何看待 CommandText字符串。其可能值如下: • uCmdUnknown 未知类型(不指定),此为默认值,但指定明确类型效率会较好。 • uCmdText 将CommandText字符串视为SQL指令(包含对预存程序的调用)。 • ucmdTable CommandText字符串仅包含数据表名称。 ucmdStoredProc CommandText字符串仅包含数据库预存程序(Stored Procedure) 的名称。

  24. lConnection 指定通过哪个ADOConnection组件连接,不指定连接组件时,则直接指定ConnectionString连接字符串。 • lParameters 设置或取得ADOCommand的参数名称、参数值及数据类型,这个属性仅适用于CommandType为cmdText或cmdStoredProc的SQL叙述。 lStates 取得目前ADOCommand的状态,其可能值为:stClosed, stOpen, stConnecting, stExecuting、stFetching。

  25. 2.TADOCommand组件常用的方法 • lAssign Assign方法复制参数中的另一个ADOCommand组件,复制的内容包括: Connection(若不存在,则复制ConnectionString)、CommandText, CommandTimeout, CommandType、Prepared及Parameters。 • lCancel Cancel用来中断尚在CommandTimeout时间内的“异步”执行,若对象是同步执行操作,会触发异常。如同前述,要指定异步执行,只要设置ExecuteOptions为eoAsyncExecute即可。 lExecute 执行CommandText指令,若返回Recordset,则可以通过ADODataSet接收,如“ADOQuery1.Recordset:=ADOCommand1.Execute:”或“ADODataSet1.Recordset:=ADOCommandl.Execute;”。

  26. 12.1.4 TADODataSet组件 TADODataSet组件用来从单一或多个窗体中获取数据或操作数据存储体的数据,它除了允许通过TADOConnection连接,也可以直接连接到数据服务器。 ADODataSet与ADOCommand相同,都可以用来取得返回的Recordset,最大的不同在于,ADOCommand必须借助其他ADODataSet组件保存返回的Recordset,但却可以处理非返回Recordset的一些操作查询,而ADODataSet则仅能用来取得、存放这些数据记录。 1.TADODataSet组件常用的属性 l RDSConnection RDSConnection属性用来指定ADODataSet的RDS数据连接来源。RDS数据连接用在以ADO为基础的商业逻辑对象(多层架构的服务端应用程序),此处不予探讨。这个属性与Connection属性是互斥的。

  27. lCacheSize CacheSize用来设置一次由服务器端读到客户端内存的数据记录数。当记录指针移动超出指定的记录数范围时,会再读下一批记录。 • lCursorType 记录指针的类型,其可能值如下所示: • uCtUnspecified 不指定。 • uCtOpenForwardOnly 记录指针只能向前移动,无法往回移动,如此,会有较好 的效率。 • uCtKeyset 看不到别人添加的记录,并且,无法访问己被删除的记录,此为默认值。 • uCtDynamic 看得见其他人添加、修改、删除的记录变动,同时可以向前、向后移动记录。 • uCtStatic 静态指针,将原始记录全部复制一份,原始记录的所有变化,都看不 见,静态指针常用于报表。 CursorType必须配合前述的CursorLocation(客户端或服务器端的记录指针)。当设置为客户端光标 (clUseClient ) 时,则CursorType只能是ctStatic。此外,若数据提供者不支持指定的光标类型,会以其他最接近、可用的光标类型代替,但这个替代的光标类型,仍会反映到CursorType属性。

  28. l时,同LockType LockType属性用来设置或取得DataSet打开时,记录如何锁定,其可能值如下所示: • u1tUnspecified 不指定锁定类型。 • u1tReadOnly 目前打开的DataSet是只读的,无法修改数据。 • u1tPessimistic 悲观锁定。悲观锁定在修改模式时,记录以一条一条为基础,以 确保同一个记录不会同时被多人改变。 • u1tOptimistic 优化锁定。优化锁定较适用于多人使用的系统,它只有在真正更 新到数据库时,才会锁定记录。例如,若同时两人更新某条记录,无论谁先更新都可以成功。 • u1tBatchOptimistic 批量优化锁定。批量优化锁定类似优化锁定,但是,它允许整批更新。 与CursorType相同,不同数据库系统支持的LockType也不尽相同,当指定该数据提供者不支持的LockType样会自动转换为最接近、支持的锁定类型。

  29. lMaxRecords 指定ADODataSet选取的最大数据条数,默认为0,表示不限制条数。但是,并非所有数据库都支持这个属性,例如,使用Access测试便无结果。 • lRecNo 目前记录所在的位置。 • lRecordCount 记录条数。TADODataSet继承自TCustomADODataSet尚有另一类似的属性RecordSize,但该属性并未实现,会取得错误值。 • lRecordset Recordset属性提供直接访问ADO的Recordset对象。 • lSort 排序字段,多个字段排序时,以逗号隔开,如“'ORDERDATE ASC,ORDERNO DESC'”依订单日期顺向排序,相同日期时,则再根据订单编号反向排序。需注意的一点,ASC, DESC必须是大写的,省略时,默认顺向排序,取消排序则只要将Sort字符串清除。此外,排序的行为与数据库记录指针的设置值、数据库系统皆有关。 lIsUnidirectional 用来判断DataSet是否仅支持单向操作。

  30. 2. TADODataSet组件常用的方法 • lCancelBatch 取消所有由批次更新模式打开,且等待更新的DataSet。其传入参数 AffectRecords可能值如下: • uArCurrent 仅影响目前记录。 • uarf filtered 更新符合Filter条件设置的所有记录。 • uarAll 更新全部记录。 • uarAllChapters 更新全部Chapter记录,对阶层式Recordset而言,即目前等级的全部记录。 要使用批次更新,CursorType必须是默认的ctKeySet或ctStatic,且LockType必须指定为ItBatchOptimistic。

  31. lDeleteRecords 删除一条或多条记录,其参数同CancelBatch的参数AffectRecords当指定的DataSet不能允许删除操作时,会触发异常。 • lSupports 用来检测指定的操作是否被支持,可查询的功能包括: • uCoHoldRecords 未更新变更,仍能撷取更多的记录。 • uCoMovePrevious 是否允许记录往回移动。 • uCoAddNew 是否允许新增记录。 • uCoDelete 是否允许删除记录。 • uCoUpdate 是否允许修改记录。 • uCoBookmark 是否允许定位到指定记录位置。 • uCoApproxPosition 是否支持RecNo属性。 • uCoUpdateBatch 是否支持批量更新。 • uCoResync 是否支持Resync方法更新。 • uCoNotify 是否支持自动通知并返回事件。 • uCoFind 是否支持Locate方法。 • uCoSeek 是否支持Seek方法。 • uCoIndex 是否允许使用IndexName属性指定索引。

  32. 使用Supports的方式很简单,如以下程序代码片段,用来检查是否允许往回移动记录指针:使用Supports的方式很简单,如以下程序代码片段,用来检查是否允许往回移动记录指针: If ADOdataSet1.Supports([coMovePervious]) then ShowMessage(‘允许往回移动’); l UpdateBatch 执行批次更新到数据存储体。

  33. 3.TADODataSet组件常用的事件 • lOnEndOfRecordset 当Recordset的记录指针移到最后一条时,触发此事件,这个事件通常是内部自行触发,或者通过直接操作ADO的Recordset组件的方法来触发。 • lOnFetchComplete 当异步提取数据时,在数据提取完成后,会触发此事件。 • lOnFetchProgress 异步数据提取的期间,会触发此事件。 • lOnFieldChangeComplete 当Recordset的Field变更时,会触发此事件。 • lOnMoveComplete 当Recordset记录移动时,会触发此事件,需注意的一点,Recordset记录移动与ADODataSet的记录移动是无关的。 lOnRecordChangeComplete 当Recordset一条或多条记录变更完成时,触发此事件。OnRecordChangeComplete事件触发同样与ADODataSet数据变更的事件无关。

  34. lOnRecordsetCreate 当Recordset属性第一次被初始化时,触发此事件。 • lOnWillChangeField 当Recordset的Field正要被改变前,触发此事件,此事件的触发同样与ADODataSet数据变更的事件无关。 • lOnWillChangeRecord 当Recordset的记录变更前,触发此事件,此事件的触发,同样与ADODataSet数据变更无关。 • lOnWillChangeRecordset 当Recordset对象变更前,触发此事件,此事件的触发同样与ADODataSet数据变更的事件无关。 • lOnWillMove 当Recordset记录指针移动前,会触发此事件,此事件的触发同样与 ADODataSet组件的BeforeScroll, AfterScroll等事件无关。

  35. 12.1.5 TADOTable组件 TADOTable组件用来操作使用ADO的数据存储体单一数据表,它同样允许直接连接数据存储体,而不通过TADOConnection。 1. TADOTable组件常用的属性 • lMasterSource, MasterFields 通过这两个属性,同样设置Master/Detail的DataSource的关联字段。 • lTableDirect 默认为False,表示ADOTable必须通过SELECT取得字段对应数据,设为True时,ADOTable允许直接通过Table名称取得数据库的字段数据。需注意的一点,并非所有数据提供者都支持直接由数据表名称取得来源的字段数据。 lTableName 设置ADOTable操作的数据表名称,改变此值前,必须先关闭ADOTable (调用Close方法或将Active设为False)。

  36. 2.TADOTable组件常用的方法 • lGetIndexNames 取得该数据表可用的索引名称,类似TADOConnection提到的 GetFieldNames, GetTableNames。 12.1.6 TADOQuery组件 TADOQuery组件通过SQL命令操作数据存储体的单一或多个数据表,它同样允许直接连接数据存储体,而不通过TADOConnection。事实上,与TADOTable相同,TADOQuery亦不存在于ADO对象模型,它同样是为了让ADO选项卡中的组件接口与BDE组件相同,方便Delphi程序设计器使用而产生。它常用的属性、方法如下:

  37. 1. TADOQuery组件常用的属性 • lDataSource 用来自动填满与参数相同名称的字段对应值,它可以被用于Master/Detail的连接设置。 • lRowsAffected ADOQuery:最后一次更新或删除数据的条数,当其值为-1时,通常 会伴随着触发异常。 • lSQL TADOQuery执行的SQL字符串。 2. TADOQuery组件常用的方法 • lClose 关闭数据集。 • lCreate 创建TADOQuery组件的实例。 lExecSQL 调用ExecSQL执行SQL查询操作。SELECT命令直接用Open方法,而不使用ExecSQL方法,只有在执行没有返回结果集的SQL字符串时使用ExecSQL。

  38. 3. TADOQuery组件常用的事件 TADOQuery组件的事件及其说明与TADODataSet组件的事件说明相同。 12.1.7 ADO程序框架 要用ADO组件创建数据库应用程序,应该了解ADO程序的框架。由于Delphi很好地封装了ADO对象,提供了连接组件和数据集组件,因此,建立数据库连接就像开发基于BDE数据库引擎的应用程序那样,使用数据源组件和数据感应组件就可以实现对数据库的各种操作。ADO程序的框架如图12-11所示。从图中可以看出,如果要在一个DBRrid控件中显示数据库中的数据,方法之一是:创建一个DataSource组件,一个ADOQuery组件,一个ADOConnection组件。如果不显式地创建ADOConnection组件,则必须设置ADOQuery组件的ConnectionString属性以连接到数据库。

  39. 图12-11 ADO程序的框架 至于如何在Delphi中用ADO组件创建数据库应用程序,如何使用SQL Server数据库表、数据库视图以及如何使用SQL语句对数据库进行操作等,请阅读下一节。

  40. 12.2 基于SQL Server的数据库系统开发实例 本节以一个“学生成绩管理系统”为综合实例,既介绍了Delphi数据库应用程序的开发过程,又可从中理解和掌握利用ADO对象对SQL Server 2000数据库进行操作的方法。 12.2.1 系统设计 如同其他管理信息系统一样,“学生成绩管理系统”不仅要对学生的成绩进行管理,还要对与学生成绩有关的其他信息进行管理,如学生的基本信息、系部信息、班级信息、课程信息等管理模块,对每类信息的管理一般都应具有增加、删除、修改和查询功能,有些信息还要对其进行统计和分析。 1. 系统功能描述 本系统的每个管理模块所应完成的任务此处省略。 2. 系统功能划分 本系统的功能如图12-12所示。

  41. 图12-12 “学生成绩管理系统”功能划分

  42. 3. 系统流程 一般来说,对于一个实用的计算机管理信息系统,都具有对不同的用户赋予不同的操作权限功能,因此不同的用户的操作流程是不一样的。本系统也提供了简单的用户管理功能,如果用户名是“admin”,则表示超级用户。超级用户除可以修改自身的口令外,还可以增加和删除其他用户;普通用户登录后只能修改自己的口令。本系统的流程如图12-13所示。 图12-13 “学生成绩管理系统”系统流程

  43. 12.2.2 数据库设计 数据库设计主要包括创建数据库和数据库逻辑结构设计。在设计数据库时通常要进行规范化分析,是各个数据库表满足某种范式的要求,要注意的是并不是将表分割得越细越好,过细不利于提高数据库的存取效率。 在“学生成绩管理系统”实例中使用了前面章节用到的“XSCJ”数据库,其设计过程在此不再赘述,但要在原“XSCJ”数据库的基础上给每个用户表增加关系、主键、外键和CHECK约束。 1. “学生基本信息表” 在SQL Server 2000企业管理器中所增加的关系、主键和外键如图12-14、图12-15和图12-16所示。

  44. 图12-14 “学生基本信息表”的关系、主键和外键 图12-15 “学生基本信息 表”的关系、主键和外键

  45. 图12-16“学生基本信息表”的关系、主键和外键图12-16“学生基本信息表”的关系、主键和外键

  46. 2. “系部表” “系部表”的主键、外键如图12-17、图12-18所示 图12-17 “系部表”的主键、外键 图12-18 “系部表”的主键、外键

  47. 3. “班级表” “班级表”的主键、外键如图12-19、图12-20和图12-21所示。 图12-19 “班级表”的主键、外键 图12-20 “班级表”的主键、外键

  48. 图12-21 “班级表”的主键、外键 图12-22 “班级表”的主键、外键

  49. 图12-23 “课程信息表”的主键、外键 图12-24 “课程信息表”的主键、外键 4. “课程信息表” “课程信息表”的主键、外键如图12-22、图12-23和图12-24所示。

  50. 图12-25 “成绩表”的关系、CHECK约束 图12-26 “成绩表”的关系、CHECK约束 5. “成绩表” “成绩表”的关系、CHECK约束如图12-25、图12-26和图12-27所示。

More Related