书城计算机网络综合应用软件设计
8724600000020

第20章 数据分析、设计及实现(3)

cust_address char(50),

cust_credit_limit money,

GO

sp_bindrule id_chk,’cust_sample.cust_id’

GO

⑥触发器(trigger)。

触发器是一种特殊类型的存储过程,当使用UPDATE、INSERT或DELETE的一种或多种操作时,触发器会自动执行。触发器可以查询其他表,也可以包含复杂的SQL语句。它主要用于强制复杂的业务规则或要求。例如,可以控制是否允许基于顾客的当前账户状态插入订单。触发器还有助于强制引用完整性,以便在添加、更新或删除表中的行时保留表之间已定义的关系。然而,强制引用完整性的最好方法是在相关表中定义主键和外键约束。如果使用数据库关系图,则可以在表之间创建关系以自动创建外键约束。

下面的触发器示例表示在数据库pubs中执行插入和更新操作的时候,显示提示信息。

USE pubs

IF EXISTS(SELECT name FROM sysobjects

WHERE name=’reminder’AND type=’TR’)

DROP TRIGGER reminder

GO

CREATE TRIGGER reminder

ON titles

FOR INSERT,UPDATE

AS RAISERROR(50009,16,10)

GO

下面的例子,显示在删除主表tab_armstore中记录的时候,同时删除其3个从表中的对应记录,从而保持数据的一致性。

CREATE TRIGGER Tri_armstore ON dbo.tab_armstore

FOR delete

As

begin tran

delete tab_accessarystore

where tab_accessarystore.storeid in

(select storeid from deleted)

delete Tab_StorePicture

where Tab_StorePicture.storeid in

(select storeid from deleted)

delete Tab_StoreVary

where Tab_StoreVary.storeid in

(select storeid from deleted)

if@@error>;0

rollback tran

else

commit tran

6)数据库的实现

根据逻辑设计和物理设计的结果,在计算机系统上建立起实际数据库结构,装入数据、测试和试运行的过程称为数据库的实现阶段。实现阶段主要有3项工作:

①建立实际数据库结构。对描述逻辑设计和物理设计结果的程序,经DBMS编译成目标模式和执行后,建立了实际的数据库结构。

②装入测试数据对应用程序进行调试。应使测试数据尽可能覆盖现实操作的各种情况。

测试数据可以是实际数据,也可由手工生成或用随机数发生器生成。

③装入实际数据,进入试运行状态。测量系统的性能指标,是否符合设计目标。如果不符合,则返回前面的物理设计,甚至逻辑设计,并对数据库的设计进行调整。

5.2典型数据库设计模式

5.2.1如何设计主从关系的表

在数据库的设计中,主从复合结构(Master/Detail)是基于“一对多”的关系的一种常见的数据存储模式。在一张表中存储主题信息,可称之为主表,另一张表中存储对应的详细信息,称之为从表。两个表之间通过外键相互关联。

例如,在仓库管理系统的开发中,需要记录进货单的数据。对于一张进货单,不能将其信息存储在一张表中,因为其中的数据可以分为两部分,一部分是表单信息,包括:表单号(OrderID)、进货日期(OrderDate)、供货厂商(Vendor)、总价(TotalPrice)。另一部分是货物的详细信息,包括货物编号(ProductID)、货物名称(ProductName),货物单价(UnitPrice)、货物数量(ProductNum)、货物价格小计(ProductSum)。对于同一张进货单,表单信息是固定的,不同的货物有不同的详细信息。如果将两部分存储在一张表中,对于每一条记录,都要同时存储表单信息和货物的详细信息,那么要存储大量重复的表单信息,这样的表结构产生了大量的冗余信息。

为了更加清晰地存储进货单数据,减少冗余,使用主从复合结构(Master/Detail)来存储进货单数据。根据上面对于进货单中数据的分类,建立主表:T_Order,来记录表单信息;然后建立从表:T_OrderDetail,记录货物信息,其中增加字段DetailID作为自动增长的主键,唯一标识货物记录。主从表之间是一对多关系,在从表T_OrderDetail中加入主表的主键作为外键,用来关联两表间的信息。

5.2.2如何设计出入库类型的表

仓库管理系统中,入库和出库是经常用到的操作。货物入库,首先要在入库表里面记录入库操作,然后在货物表里面增加相对应货物的数量。一般来说,货物表里面不记录货物的库存数量,而是用单独的一张表记录货物数量,这里为了跟踪显示货物数量的变化,在货物表里面加上库存字段。货物出库的操作同货物入库相似,需要判断库存数量是否满足出库数量,如果满足,则减去出库数量。货物表和进货表之间,货物表和出货表之间都是一对多的关系,货物表的各个字段分别为:ProductID(货物编号)、ProductName(货物名称)、ProductPrice(货物单价)、ProductStoreNum(库存数量)。

进货表的字段为:InStoreID(进货编号)、ProductID(货物编号)、InStoreDate(进货日期)、InStoreNum(进货数量)。

出货表的字段为:OutStoreID(进货编号)、ProductID(货物编号)、OutStoreDate(进货日期)、OutStoreNum(进货数量)。

5.2.3如何实现基于角色的数据库设计

管理信息系统中,系统的操作人员属于不同的角色,角色是一组用户账户的集合。每种角色具有不同的权限,权限即是角色可以执行的操作。对于每个用户,要将其加入具体的角色中,此时这个用户就具有这个角色的权限,也就是可以执行这个角色的各种操作。由ER图可以知道用户—角色、角色—权限之间都是多对多的关系。

通过ER图,可以得到的对应表有:用户表(T_User)、角色表(T_Role)、权限表(T_Permission)、用户角色关系表(T_UserRole)、角色权限关系表(T_RolePermission)。其中,表T_RolePermission中的字段Paction表示可以执行的操作。例如,可以将Paction中的取值对应于网页上不同的操作标题。不同的用户,显示不同的操作标题,这样来实现用户的不同权限。通过上面的设计,可以非常灵活地添加和更改各种角色和权限,而无需更改表的结构。

5.2.4如何设计树形结构的数据库

树形结构设计的思路是,用一个ParentCategoryID指向该类别所属的父类别ID,对于根节点数据,他们没有父类ID,可以设为预先定义好的标记,如“0”。这种设计可以用于多种场合,如公司职员表中ReportsTo列就是该员工的负责人,显然该负责人也属于员工,也应该在这张表中。但应该注意一点,这张表虽然也实现了员工间的层次关系,但它与Category表的设计还有差别。Category表的ParentCategoryID列不允许为空,所以对于根节点,必定有一个预先约定的值,而这一预先约定的值必定不在这张表中,所以无法设置从ParentCategoryID到CategoryID的外键引用关系。但是Employees表中的Reports列允许为空,所以对于根节点这一列的值可以为NULL,因而可以设置从ReportsTo列到EmployeeID列的外键关系。

5.3数据库编程常见问题

5.3.1如何实现多表连接查询

在系统的实际应用中,常常会需要查询汇总多个表中的信息,如上面的订货单的例子,用户常常会查询某一张订货单中的某一货物的进货数量。因此需要连接主从表,来实现多表查询,要使用innerjoin语句来连接两张表,下面的SQL语句是查询进货单号为100的进货单中产品号为200的货物的进货数量:

SELECT ProductNum

FROM dbo.T_Order INNER JOIN

dbo.T_OrderDetail ON dbo.T_Order.OrderID=dbo.T_OrderDetail.OrderID

WHERE dbo.T_Order.OrderID=100 AND dbo.T_OrderDetail. ProductID=200

通过以上语句实现了多表查询,当然了,也可以建立视图,然后从视图中按条件查询记录。

5.3.2如何实现主从表删除

主从表在删除过程中,可以直接删除从表中的记录,但是如果删除主表中的记录,也要删除从表的对应记录,否则容易造成数据的不一致。以上面介绍的进货单为例,如果删除了主表中的一条记录,而没有删除从表中对应这一主表的货物记录,那么这些货物记录的外键(OrderID)在主表中就没有了对应的进货单记录,数据的不一致由此产生。可见,要保持数据的一致性,就要做到主从表对应数据的全部删除,为了实现对应数据的全部删除,可以使用级联删除,也可以使用触发器。

级联删除的实现比较简单,上面介绍的建立主从表连接的操作中,在关系图中选中主从表之间的连接线,单击右键,选择“属性”,在弹出的对话框中选择“关系”标签,然后选中其中的“级联删除相关的记录”,这样在删除主表中的一条记录的时候,从表中的对应记录会自动删除。

使用触发器,在删除主表记录的时候,会自动执行触发器,删除从表中的对应记录,下面是对应于进货单主从表删除操作的触发器:

CREATE TRIGGER Tri_Order ON dbo.T_Order

FOR delete

as

begin tran

delete T_OrderDetail

where T_OrderDetail.OrderID in

(select OrderID from deleted)

if@@error>;0

rollback tran

else

commit tran