SQLServer2005 数据库系统开发案例精选

y493571521

贡献于2013-05-16

字数:0 关键词: SQL Server 数据库服务器 SQL

数据库系统开发从技术到实践 S Q L S erver 2005 数据库系统开发案例精选 明日科技 编著 杨湖 李凤蕾 王斌 人民邮电出版社 北 京 图书在版编目(CIP)数据 SQL Server 2005 数据库系统开发案例精选/明日科技编著. —北京:人民邮电出版社, 2007.7 (数据库管理系统开发从技术到实践) ISBN 978-7-115-16149-9 Ⅰ.S… Ⅱ.明… Ⅲ.关系数据库-数据库管理系统,SQL Server 2005 Ⅳ.TP311.138 中国版本图书馆 CIP 数据核字(2007)第 057474 号 内 容 简 介 本书精选了 7 个当前应用最广泛的数据库系统,详细介绍了使用 SQL Server 2005 开发数据库管理系 统的思路、方法和技术。主要内容包括天下鲜美食网、电子商城、物流信息网、供求信息网、企业客户管 理系统、学生管理系统、图书综合管理系统等。这些系统既可以独立使用,也可作为综合管理系统的重要 组成部分。 本书附赠光盘不但包含了书中所有数据库系统实例的源程序(5 套界面风格)和相关开发素材,同时 还包含免费赠送的程序设计速查宝典、数十种实用软件工具和 7 个设计范例。本书所有源程序都经过精心 调试,在 Windows XP 和 Windows 2000 下全部通过,保证能够正常运行。 本书内容精练、重点突出、实例丰富,是各级程序开发人员必备的和不可多得的数据库系统开发图书, 本书也非常适合大中专院校师生学习参考。 数据库管理系统开发从技术到实践 SQL Server 2005 数据库系统开发案例精选 ♦ 编 著 明日科技 杨 湖 李凤蕾 王 斌 责任编辑 屈艳莲 ♦ 人民邮电出版社出版发行 北京市崇文区夕照寺街 14 号 邮编 100061 电子函件 315@ptpress.com.cn 网址 http://www.ptpress.com.cn 北京鸿佳印刷厂印刷 新华书店总店北京发行所经销 ♦ 开本:787×1092 1/16 印张:29 彩插:2 字数:718 千字 2007 年 7 月第 1 版 印数:1– 5 000 册 2007 年 7 月北京第 1 次印刷 ISBN 978-7-115-16149-9/TP 定价:52.00 元(附光盘) 读者服务热线:(010)67132692 印装质量热线:(010)67129223 前 言 数据库管理系统作为和操作系统同等重要的基础软件平台,已经成为企业日常管理中 不可缺少的组成部分。如果不借助数据库管理系统的帮助,许多简单的工作将变得效率低 下、错误百出,甚至难以实现。无论是超市、银行、车站和图书馆,还是日益火爆的互联 网上服务(如搜索引擎、门户网站、网上聊天、电子邮件等),都离不开数据库管理系统的 支持。 本书内容 本书精选了当前较为热门的数据库管理系统,包括天下鲜美食网、电子商城、物流信 息网、供求信息网、企业客户管理系统、学生管理系统、图书综合管理系统等。这些系统 既可独立使用,也可作为综合管理系统的重要组成部分。 特色注释 迅速提高编程水平的方法是阅读大量代码,但冗长的代码往往让编程爱好者望而却步。 为使读者在阅读代码时透彻理解代码的含义和使用技巧,本书对代码中重要的对象、函数、 语句和重点知识等设计了一些非常有用的特色说明,以帮助读者理解和学习,主要包括以 下几部分。  代码导读。对于代码中比较重要的内容,通过注释不好讲解,在代码前使用了标 注文字(、⋯⋯)进行标识,然后统一放在代码导读中进行解释。如: realname = Mid(filename,InStrRev(filename,"/")+1)  If(realname <> "")Then rs_2("Img_Name") = realname Else rs_2("Img_Name") = "空" End If  For i=1 To Len(Str)  代码导读  If...Then...Else 语句:根据表达式的值有条件地执行一组语句。  len 函数:返回字符串内字符的数目,或是存储一变量所需的字节数。  线性标注。在代码中,为解释一段代码实现的功能,在代码中使用了虚线框和线 性标注解释代码段的功用和需要注意的问题。 getcondition = Replace(trim(request("condition")),"’","’’") getkey = Replace(trim(request("key")),"’","’’") if(getcondition = "" or getkey = "")then Sql = "Select * from tb_User order by JoinTime Desc" 默认情况下检索数据库中的全部数据 II 特色标识  注意:用于强调当前讨论问题的附加信息和注意事项。  注意 在应用 While...Wend 语句进行记录集中的数据输出时,必须加入 rs.MoveNext,否 则将出现死循环,rs 为记录集名称。  技巧:提供了作者开发中积累的编程捷径、技巧和高招。 技巧 本书将数据库连接文件命名为 Conn.asp,为了方便以后维护网站,将其存放在站点 根目录的 Conn 文件夹下。读者在程序开发时,也应养成良好的命名规则,方便操作和 维护网站。  链接:对于多个实例涉及的内容,为了避免重复,又能让读者方便找到相关的技 术解答,本书通过链接提供对重复内容的快速索引。  链接 物流知识、车辆信息、企业信息这几个功能模块的实现与货物信息模块的实现方法 相似,在此笔者不再分别进行详细介绍。  技术细节:重点介绍开发过程中用到的关键技术或方法。 技术细节 在编写 ASP 应用程序时,常常会遇到一些重复代码段。而且当希望修改或者增强这 些相同代码段的功能时,必须逐一修改,这就会导致编程效率的降低和错误的增加。此 时,可以通过嵌入代码模块的方法来解决,将这些公用代码段封装到某个位置,即可在 其他任何地方调用该代码段。 如果希望 ASP 程序中包含代码模块,需要事先定义好模块,并将它储存在一个后缀 名为 inc 的文件里,然后在其他任何想调用此模块的地方使用 include 标签署,其语句为: 本书的约定 在本书的章首页中,详细说明了每个实例开发需要的技术,并对程序各方面内容 进行了说明。读者在学习前,一定要仔细阅读本章章首页。 在本书书后有技术查询目录,如果读者阅读本书时遇到疑问,可通过技术查询目 录进行查询解决。另外,本书光盘还提供了速查电子词典。 因篇幅限制,本书实例讲解部分只介绍重点模块和关键代码,其他模块和代码, 请读者参见光盘中实例的源程序。 本书光盘多媒体程序只能在光盘上执行,不能复制到计算机上执行。 技术支持 本书由明日科技组织编写,参加编写的有孙明丽、王斌、李凤蕾、顾彦玲、高春艳等。 III 由于作者水平有限,疏漏之处在所难免,请广大读者批评指正。 如果读者在使用本书时遇到问题,可以访问明日科技网站,我们将通过该网站全面为 读者提供网上服务和支持。对于读者使用本书时遇到的问题,我们将在 5 个工作日内回复。 服务网站:www.mingrisoft.com 服务信箱:mingrisoft@mingrisoft.com 服务电话:0431-84978981 84978982 编者 2007 年 5 月 丛丛 书书 特特 色色 数据库系统开发案例精选 全程服务、品质保障 为帮助广大开发者透彻理解本丛书,明日科技将通过明日科技 网站全面为读者提供网上服务和支持。对于读者使用本丛书时遇到 的问题,我们将在 5 个工作日内回复。 全程服务网站:www.mingrisoft.com 服务信箱:mingrisoft@mingrisoft.com 数据库系统开发案例精选 轻松学习、轻松修改 本丛书结构清晰、讲解透彻,每个实例都提供了软件的安装配置录 像和主要模块的开发录像,让读者轻松学习数据库系统的开发技术和过 程。另外,本丛书实例非常容易更换程序界面和风格。每个实例都提供 了 5 套界面风格程序。对于主程序界面,本书光盘提供了 PSD 格式的 文件,用户可以轻松修改成自己喜欢的界面风格。 数据库系统开发案例精选 “易用”、“易查”、“易扩展” “易用”,每个数据库实例都可直接使用,案例界面设计友好,操作 简便,维护方便,功能强大,适合不同层次的用户和单位使用,同时, 丛书光盘还提供了所有实例的安装说明书、使用说明书和界面修改说明 书;“易查”,本丛书克服了实例型图书技术不易查找的缺点,通过双目 录和速查电子手册,读者可以快速查找相关技术在实例中的应用;“易扩 展”,丛书提供的实例完全参照程序设计的要求设计,用户可以轻松添加 功能和修改功能,可以快速开发出适合企业的优秀的管理系统。 数据库系统开发案例精选 案例丰富、轻松上手 本书通过 7 个当前应用非常广泛的数据库管理系统,循序渐进地 介绍数据库管理系统的详细开发过程,在讲解中穿插了大量技术细 节、代码导读、注意、技巧等内容。可以帮助读者快速掌握数据库系 统的开发思路和方法,从而领会相应开发工具的精髓。 数据库系统开发案例精选 光盘内容丰富 本丛书光盘不但包含了书中所有数据库系统实例的五套风格界 面的源程序和相关开发素材,同时还附有程序设计速查宝典、数十 种实用软件工具和 7 个毕业设计范例。 光 盘 说 明 天下鲜美食网 电子商城 物流信息网 供求信息网 企业客户管理系统 学生管理系统 高校毕业论文设计范例 mingrisoft 速查宝典 实用工具 天下鲜美食网(风格二) 天下鲜美食网 天下鲜美食网(风格三) 天下鲜美食网(风格四) 天下鲜美食网(风格五) 物流信息网 物流信息网(风格二) 物流信息网(风格三) 物流信息网(风格四) 物流信息网(风格五) 企业客户管理系统 企业客户管理系统(风格二) 企业客户管理系统(风格三) 企业客户管理系统(风格四) 企业客户管理系统(风格五) 电子商城(风格三) 电子商城(风格二) 电子商城(风格四) 电子商城(风格五) 电子商城 供求信息网(风格二) 供求信息网(风格三) 供求信息网(风格四) 供求信息网(风格五) 供求信息网 学生管理系统(风格二) 学生管理系统(风格三) 学生管理系统(风格四) 学生管理系统(风格五) 学生管理系统 图书综合管理系统 代码速查宝典 图书综合管理系统(风格二) 图书综合管理系统(风格三) 图书综合管理系统(风格四) 图书综合管理系统(风格五) 图书综合管理系统 多媒体光盘学习程序 光盘使用说明 2 目目 录录 第 1 章 SQL SERVER 2005 的起步 ......................................................................................... 1 1.1 安装 SQL Server 2005...............................................................................................................2 1.1.1 SQL Server 2005 版本 ....................................................................................................2 1.1.2 安装 SQL Server 2005 ....................................................................................................3 1.2 SQL Server 2005 管理工具.......................................................................................................7 1.2.1 SQL Server Configuration Manager................................................................................7 1.2.2 SQL Server Management Studio.....................................................................................7 1.2.3 SQL Server Profiler.........................................................................................................7 1.2.4 SQL Server Business Intelligence Development Studio..................................................8 1.2.5 Reporting Services 配置管理器......................................................................................8 1.2.6 SQL Server 外围应用配置器 .........................................................................................9 1.2.7 数据库引擎优化顾问 .....................................................................................................9 1.3 配置 SQL Server 2005.............................................................................................................10 1.3.1 启动、暂停和关闭 SQL Server 2005 服务 .................................................................10 1.3.2 配置连接 SQL Server 2005 ..........................................................................................11 1.3.3 注册/删除 SQL Server 2005 服务器 ............................................................................15 1.4 数据库管理..............................................................................................................................16 1.4.1 创建数据库...................................................................................................................17 1.4.2 分离/删除数据库..........................................................................................................17 1.4.3 脱机与联机用户数据库 ...............................................................................................18 1.5 添加/删除表.............................................................................................................................20 1.6 修改表......................................................................................................................................21 1.6.1 添加字段.......................................................................................................................21 1.6.2 修改字段属性...............................................................................................................21 1.6.3 设置主键/索引..............................................................................................................22 1.7 视图管理..................................................................................................................................23 1.7.1 创建视图.......................................................................................................................23 1.7.2 修改视图.......................................................................................................................24 2 1.7.3 删除视图.......................................................................................................................24 1.8 存储过程管理..........................................................................................................................24 1.8.1 创建存储过程...............................................................................................................25 1.8.2 修改存储过程...............................................................................................................25 1.8.3 删除存储过程...............................................................................................................25 1.9 触发器管理..............................................................................................................................26 1.9.1 创建触发器...................................................................................................................26 1.9.2 修改触发器...................................................................................................................26 1.9.3 删除触发器...................................................................................................................26 1.10 编辑数据库的数据................................................................................................................26 1.10.1 添加新记录.................................................................................................................26 1.10.2 修改记录.....................................................................................................................27 1.10.3 删除记录.....................................................................................................................27 1.11 维护数据库............................................................................................................................27 1.11.1 数据库备份.................................................................................................................27 1.11.2 数据库还原.................................................................................................................28 1.11.3 分离数据库.................................................................................................................29 1.11.4 附加数据库.................................................................................................................30 1.11.5 导入数据库.................................................................................................................30 1.11.6 导出数据库.................................................................................................................31 第 2 章 数据查询技术.............................................................................................................. 33 2.1 SELECT 语句查询 ..................................................................................................................34 2.1.1 简单的 SELECT 语句查询...........................................................................................34 2.1.2 WHERE 条件查询........................................................................................................37 2.1.3 ORDER BY 排序查询..................................................................................................43 2.1.4 GROUP BY 分组查询 ..................................................................................................45 2.2 筛选分组结果..........................................................................................................................47 2.2.1 为聚合函数计算产生新列起个别名 ...........................................................................48 2.2.2 与 GROUP BY 子句一起用 .........................................................................................48 2.2.3 消除统计重复记录 .......................................................................................................49 2.3 嵌套查询..................................................................................................................................49 2.3.1 简单的嵌套查询...........................................................................................................49 2.3.2 IN 的嵌套查询..............................................................................................................50 2.3.3 some 和 any 的嵌套查询..............................................................................................52 2.3.4 all 的嵌套查询..............................................................................................................53 2.3.5 exists 嵌套查询.............................................................................................................54 2.4 连接查询..................................................................................................................................55 2.4.1 内连接...........................................................................................................................55 2.4.2 外连接...........................................................................................................................56 2.4.3 交叉连接.......................................................................................................................58 3 2.4.4 自身连接.......................................................................................................................59 2.4.5 多表连接.......................................................................................................................60 2.5 使用空值..................................................................................................................................61 2.5.1 检测空值.......................................................................................................................61 2.5.2 处理空值.......................................................................................................................62 2.6 交叉表查询..............................................................................................................................64 2.6.1 CASE 实现交叉表查询................................................................................................64 2.6.2 SQL Server 2005 新增加的 PIVOT 和 UNPIVOT 实现交叉表查询..........................65 2.6.3 动态交叉表...................................................................................................................70 2.7 SQL Server 2005 新增加的 CTE.............................................................................................71 2.7.1 Common Table Expression............................................................................................71 2.7.2 使用递归 CTE 查询......................................................................................................73 2.8 插入数据..................................................................................................................................76 2.8.1 为指定的列插入值 .......................................................................................................77 2.8.2 为所有列插入值...........................................................................................................79 2.8.3 批量添加数据...............................................................................................................80 2.9 修改数据..................................................................................................................................82 2.9.1 修改个别行中的个别列 ...............................................................................................84 2.9.2 修改多个列...................................................................................................................85 2.9.3 修改所有行中的某一列 ...............................................................................................85 2.10 删除数据................................................................................................................................86 2.10.1 用 WHERE 子句删除部分数据.................................................................................88 2.10.2 删除表中所有数据 .....................................................................................................89 2.10.3 删除表中多余的重复行数据 .....................................................................................89 第 3 章 天下鲜美食网.............................................................................................................. 91 3.1 概述..........................................................................................................................................93 3.2 系统分析..................................................................................................................................93 3.2.1 需求分析.......................................................................................................................93 3.2.2 可行性分析...................................................................................................................93 3.3 总体设计..................................................................................................................................93 3.3.1 项目规划.......................................................................................................................93 3.3.2 系统功能结构图...........................................................................................................94 3.4 系统设计..................................................................................................................................94 3.4.1 设计目标.......................................................................................................................94 3.4.2 开发及运行环境...........................................................................................................95 3.4.3 Windows XP 系统中的 IIS 配置 ..................................................................................95 3.5 数据库设计..............................................................................................................................97 3.5.1 数据表的实体 E-R 图...................................................................................................97 3.5.2 主要数据表的结构 .......................................................................................................98 3.5.3 数据表概要说明.........................................................................................................100 4 3.6 技术准备................................................................................................................................101 3.6.1 读者知识要求.............................................................................................................101 3.6.2 命名规则.....................................................................................................................101 3.6.3 文件管理规划.............................................................................................................101 3.7 前台主要功能模块详细设计................................................................................................102 3.7.1 前台文件总体架构 .....................................................................................................102 3.7.2 文件架构.....................................................................................................................102 3.7.3 前台页面的运行结果 .................................................................................................103 3.7.4 创建数据库连接.........................................................................................................104 3.8 特色美食模块设计................................................................................................................104 3.8.1 特色美食展示.............................................................................................................105 3.8.2 特色美食查询.............................................................................................................106 3.8.3 详细信息展示.............................................................................................................108 3.9 名店加盟模块设计................................................................................................................109 3.9.1 名店加盟信息添加 .....................................................................................................110 3.9.2 名店加盟信息展示 .....................................................................................................112 3.10 公告栏模块设计..................................................................................................................114 3.10.1 滚动显示...................................................................................................................114 3.10.2 详细信息显示...........................................................................................................115 3.11 美食留言模块设计..............................................................................................................116 3.11.1 用户注册模块 ...........................................................................................................116 3.11.2 发表留言模块 ...........................................................................................................121 3.12 后台主要功能模块详细设计..............................................................................................124 3.12.1 后台总体架构...........................................................................................................124 3.12.2 后台管理页面的实现过程 .......................................................................................125 3.13 用户管理模块设计..............................................................................................................125 3.13.1 用户信息查询...........................................................................................................125 3.13.2 用户信息修改...........................................................................................................127 3.13.3 用户信息删除...........................................................................................................128 3.14 名店介绍管理模块设计......................................................................................................128 3.14.1 名店信息查询...........................................................................................................128 3.14.2 名店信息添加...........................................................................................................130 3.14.3 名店信息修改...........................................................................................................134 3.14.4 名店信息删除...........................................................................................................136 3.15 疑难问题分析解决..............................................................................................................136 3.15.1 日期时间的显示 .......................................................................................................136 3.15.2 如何根据下拉列表的值显示不同控件 ...................................................................138 3.16 程序调试及错误处理..........................................................................................................139 第 4 章 电子商城.....................................................................................................................141 4.1 概述........................................................................................................................................143 5 4.2 系统分析................................................................................................................................143 4.2.1 需求分析.....................................................................................................................143 4.2.2 可行性分析.................................................................................................................143 4.3 总体设计................................................................................................................................144 4.3.1 项目规划.....................................................................................................................144 4.3.2 系统功能结构图.........................................................................................................144 4.4 系统设计................................................................................................................................145 4.4.1 设计目标.....................................................................................................................145 4.4.2 开发及运行环境.........................................................................................................145 4.4.3 Windows 2000 的 IIS 配置 .........................................................................................145 4.5 数据库设计............................................................................................................................146 4.5.1 数据表的实体 E-R 图.................................................................................................146 4.5.2 主要数据表的结构 .....................................................................................................147 4.5.3 数据表概要说明.........................................................................................................149 4.6 技术准备................................................................................................................................149 4.6.1 读者知识要求.............................................................................................................149 4.6.2 命名规则.....................................................................................................................150 4.6.3 文件管理规划.............................................................................................................151 4.7 前台主要功能模块详细设计................................................................................................152 4.7.1 前台文件总体架构 .....................................................................................................152 4.7.2 文件架构.....................................................................................................................152 4.7.3 前台页面的运行结果 .................................................................................................152 4.8 会员管理模块设计................................................................................................................154 4.8.1 会员注册模块.............................................................................................................154 4.8.2 会员登录模块.............................................................................................................157 4.9 商城调查模块设计................................................................................................................159 4.10 购物车模块设计..................................................................................................................162 4.10.1 添加商品至购物车 ...................................................................................................163 4.10.2 查看购物车...............................................................................................................165 4.10.3 从购物车中移去指定商品及清空购物车 ...............................................................168 4.10.4 修改购物车中指定商品的购买数量 .......................................................................168 4.11 收银台模块设计..................................................................................................................171 4.11.1 填写订单信息 ...........................................................................................................171 4.11.2 处理订单信息 ...........................................................................................................176 4.12 后台主要功能模块详细设计..............................................................................................178 4.12.1 后台总体架构...........................................................................................................178 4.12.2 后台管理页面的实现过程 .......................................................................................179 4.13 商品信息管理模块设计......................................................................................................179 4.13.1 商品信息添加...........................................................................................................179 4.13.2 商品信息修改...........................................................................................................182 4.13.3 商品信息删除...........................................................................................................183 6 4.14 会员资料管理模块设计......................................................................................................184 4.14.1 会员资料查询...........................................................................................................184 4.14.2 会员资料删除...........................................................................................................186 4.15 疑难问题分析解决..............................................................................................................187 4.15.1 实现销售排行...........................................................................................................187 4.15.2 应用 Cookie 防止在线调查中的作弊行为..............................................................187 4.15.3 实现图片与下拉列表的关联 ...................................................................................188 4.15.4 Insert Into 和 AddNew 的区别 .................................................................................188 4.16 程序调试及错误处理..........................................................................................................189 第 5 章 物流信息网.................................................................................................................191 5.1 概述........................................................................................................................................193 5.2 系统分析................................................................................................................................193 5.2.1 需求分析.....................................................................................................................193 5.2.2 可行性分析.................................................................................................................193 5.3 总体设计................................................................................................................................193 5.3.1 项目规划.....................................................................................................................193 5.3.2 系统功能结构图.........................................................................................................194 5.4 系统设计................................................................................................................................194 5.4.1 设计目标.....................................................................................................................194 5.4.2 开发及运行环境.........................................................................................................195 5.4.3 Windows 2003 的 IIS 配置 .........................................................................................195 5.4.4 Web 服务扩展.............................................................................................................196 5.5 数据库设计............................................................................................................................197 5.5.1 数据表的实体 E-R 图.................................................................................................197 5.5.2 主要数据表的结构 .....................................................................................................197 5.5.3 数据表概要说明.........................................................................................................200 5.6 文件管理规划........................................................................................................................201 5.7 前台主要功能模块详细设计................................................................................................201 5.7.1 前台文件总体架构 .....................................................................................................201 5.7.2 文件架构.....................................................................................................................201 5.7.3 前台页面的运行结果 .................................................................................................202 5.8 车牌号码所属地区查询模块设计........................................................................................203 5.9 会员管理模块设计................................................................................................................206 5.9.1 会员注册.....................................................................................................................207 5.9.2 找回密码.....................................................................................................................210 5.9.3 会员登录.....................................................................................................................211 5.10 货物信息模块设计..............................................................................................................212 5.10.1 货物信息发布...........................................................................................................212 5.10.2 货物详细信息显示 ...................................................................................................214 5.11 信息查询模块设计..............................................................................................................216 7 5.12 后台主要功能模块详细设计..............................................................................................220 5.12.1 后台总体架构...........................................................................................................220 5.12.2 后台管理页面的实现过程 .......................................................................................221 5.13 企业信息管理模块设计......................................................................................................222 5.13.1 企业信息查询...........................................................................................................222 5.13.2 企业信息删除...........................................................................................................224 5.14 物流知识管理模块设计......................................................................................................225 5.14.1 物流知识添加...........................................................................................................225 5.14.2 物流知识修改...........................................................................................................227 5.14.3 物流知识删除...........................................................................................................228 5.15 会员信息管理模块设计......................................................................................................229 5.16 疑难问题分析解决..............................................................................................................231 5.16.1 应用 FileSystemObject 组件实现网站计数器.........................................................231 5.16.2 关闭子窗口时刷新父窗口 .......................................................................................232 5.16.3 强行关闭主窗口 .......................................................................................................232 5.16.4 使用 session 参数存储用户登录信息......................................................................233 5.17 程序调试及错误处理..........................................................................................................233 第 6 章 供求信息网................................................................................................................ 235 6.1 概述........................................................................................................................................237 6.2 系统分析................................................................................................................................237 6.2.1 需求分析.....................................................................................................................237 6.2.2 可行性分析.................................................................................................................237 6.3 总体设计................................................................................................................................238 6.3.1 项目规划.....................................................................................................................238 6.3.2 系统功能结构图.........................................................................................................238 6.4 系统设计................................................................................................................................238 6.4.1 设计目标.....................................................................................................................238 6.4.2 开发及运行环境.........................................................................................................238 6.5 数据库设计............................................................................................................................239 6.5.1 数据表的实体 E-R 图.................................................................................................239 6.5.2 主要数据表的结构 .....................................................................................................239 6.5.3 数据表概要说明.........................................................................................................241 6.6 技术准备................................................................................................................................241 6.6.1 读者技术要求.............................................................................................................241 6.6.2 配置 IIS.......................................................................................................................241 6.6.3 文件管理规划.............................................................................................................243 6.7 公共模块编写........................................................................................................................243 6.7.1 Web.Config 文件设计.................................................................................................243 6.7.2 DB(数据库操作)类................................................................................................244 6.7.3 创建用户控件.............................................................................................................245 8 6.8 网站前台主要功能模块设计................................................................................................248 6.8.1 前台文件总体架构 .....................................................................................................248 6.8.2 网站首页设计.............................................................................................................248 6.8.3 信息展示页设计.........................................................................................................252 6.8.4 用户注册模块设计 .....................................................................................................253 6.8.5 信息发布页设计.........................................................................................................256 6.8.6 留言板模块设计.........................................................................................................259 6.8.7 详细信息显示页.........................................................................................................263 6.9 后台主要功能模块详细设计................................................................................................264 6.9.1 后台总体架构.............................................................................................................264 6.9.2 后台登录页设计.........................................................................................................265 6.9.3 后台首页设计.............................................................................................................267 6.9.4 会员信息展示页设计 .................................................................................................268 6.9.5 资料删除页设计.........................................................................................................270 6.9.6 供求信息审核页设计 .................................................................................................273 6.9.7 留言板信息管理模块 .................................................................................................275 6.10 疑难问题分析解决..............................................................................................................278 6.10.1 DataReader 和 DataSet 的区别.................................................................................278 6.10.2 常用的正则表达式 ...................................................................................................279 6.11 程序调试与错误处理..........................................................................................................279 第 7 章 企业客户管理系统.....................................................................................................281 7.1 概述........................................................................................................................................283 7.2 系统分析................................................................................................................................283 7.2.1 需求分析.....................................................................................................................283 7.2.2 可行性分析.................................................................................................................283 7.3 总体设计................................................................................................................................283 7.3.1 项目规划.....................................................................................................................283 7.3.2 系统功能结构图.........................................................................................................284 7.4 系统设计................................................................................................................................284 7.4.1 设计目标.....................................................................................................................284 7.4.2 开发及运行环境.........................................................................................................285 7.5 数据库设计............................................................................................................................285 7.5.1 数据表的实体 E-R 图.................................................................................................285 7.5.2 主要数据表的结构 .....................................................................................................286 7.5.3 数据表概要说明.........................................................................................................287 7.5.4 存储过程设计.............................................................................................................287 7.6 技术准备................................................................................................................................290 7.6.1 读者知识要求.............................................................................................................290 7.6.2 存储过程的创建.........................................................................................................290 7.6.3 存储过程的使用.........................................................................................................291 9 7.7 网站总体架构........................................................................................................................292 7.7.1 功能模块介绍.............................................................................................................292 7.7.2 文件夹及文件架构布局 .............................................................................................292 7.7.3 文件架构.....................................................................................................................292 7.8 公共模块编写........................................................................................................................293 7.8.1 用户控件设计.............................................................................................................293 7.8.2 Web.Config 文件配置.................................................................................................294 7.8.3 实体类编写.................................................................................................................295 7.8.4 数据库操作类.............................................................................................................295 7.9 网站开发................................................................................................................................305 7.9.1 用户登录模块.............................................................................................................305 7.9.2 主页模块设计.............................................................................................................307 7.9.3 站内搜索模块.............................................................................................................311 7.9.4 详细信息显示模块 .....................................................................................................313 7.9.5 发布信息添加模块 .....................................................................................................316 7.9.6 任务分配模块.............................................................................................................318 7.9.7 用户信息添加模块 .....................................................................................................323 7.9.8 服务调查查看模块 .....................................................................................................327 7.9.9 反馈信息添加模块 .....................................................................................................330 7.9.10 修改密码模块...........................................................................................................333 7.10 疑难问题解析......................................................................................................................335 7.11 程序调试与错误处理..........................................................................................................336 第 8 章 学生管理系统............................................................................................................ 339 8.1 概述........................................................................................................................................341 8.2 系统分析................................................................................................................................341 8.2.1 需求分析.....................................................................................................................341 8.2.2 可行性分析.................................................................................................................341 8.3 总体设计................................................................................................................................341 8.3.1 项目规划.....................................................................................................................341 8.3.2 系统功能结构图.........................................................................................................342 8.4 系统设计................................................................................................................................342 8.4.1 设计目标.....................................................................................................................342 8.4.2 开发及运行环境.........................................................................................................342 8.5 数据库设计............................................................................................................................343 8.5.1 数据表的实体 E-R 图.................................................................................................343 8.5.2 主要数据表的结构 .....................................................................................................343 8.5.3 数据表概要说明.........................................................................................................344 8.6 网站总体架构........................................................................................................................345 8.6.1 模块功能介绍.............................................................................................................345 8.6.2 文件夹及文件架构布局 .............................................................................................345 10 8.6.3 文件架构.....................................................................................................................345 8.7 公共模块设计........................................................................................................................346 8.7.1 Web.Config 文件设计.................................................................................................346 8.7.2 DB(数据库操作)类................................................................................................346 8.7.3 网站样式、外观和主题 .............................................................................................347 8.7.4 用户控件设计.............................................................................................................348 8.8 网站开发................................................................................................................................354 8.8.1 网站首页设计.............................................................................................................354 8.8.2 学生基本信息显示模块 .............................................................................................356 8.8.3 学生详细信息显示模块 .............................................................................................359 8.8.4 留言信息模块设计 .....................................................................................................361 8.8.5 回复留言信息模块设计 .............................................................................................365 8.8.6 公告管理模块设计 .....................................................................................................367 8.8.7 学生基本信息管理模块 .............................................................................................370 8.8.8 内容页(Student.aspx).............................................................................................375 8.9 疑难问题分析解决................................................................................................................379 8.9.1 DataList 控件绑定数据的几种方法...........................................................................379 8.9.2 如何实现多个 DropDownList 控件的联动 ...............................................................380 8.10 程序调试及错误处理..........................................................................................................380 第 9 章 图书综合管理系统.....................................................................................................383 9.1 概述........................................................................................................................................385 9.2 系统分析................................................................................................................................385 9.2.1 需求分析.....................................................................................................................385 9.2.2 可行性分析.................................................................................................................385 9.3 总体设计................................................................................................................................385 9.3.1 项目规划.....................................................................................................................385 9.3.2 系统功能结构图.........................................................................................................386 9.4 系统设计................................................................................................................................387 9.4.1 设计目标.....................................................................................................................387 9.4.2 开发及运行环境.........................................................................................................387 9.4.3 编码设计.....................................................................................................................387 9.5 数据库设计............................................................................................................................388 9.5.1 数据表的实体 E-R 图.................................................................................................388 9.5.2 主要数据表的结构 .....................................................................................................388 9.5.3 概念结构设计.............................................................................................................391 9.6 技术准备................................................................................................................................391 9.6.1 函数准备.....................................................................................................................391 9.6.2 控件准备.....................................................................................................................392 9.7 主要功能模块设计................................................................................................................393 9.7.1 系统架构设计.............................................................................................................393 11 9.7.2 公共模块设计.............................................................................................................394 9.7.3 系统登录设计.............................................................................................................395 9.7.4 程序主窗体.................................................................................................................398 9.7.5 图书类别管理.............................................................................................................402 9.7.6 读者信息管理.............................................................................................................407 9.7.7 入库管理.....................................................................................................................412 9.7.8 入库查询.....................................................................................................................419 9.7.9 库存上下限设置.........................................................................................................423 9.7.10 销量分析...................................................................................................................425 9.7.11 添加操作员 ...............................................................................................................427 9.7.12 库存打印报表...........................................................................................................430 9.8 疑难问题分析与解决............................................................................................................433 9.8.1 如何将图书类别和存放位置列表中的内容赋给 MSFlexGrid 表格........................433 9.8.2 如何锁定 DataGrid 表格的指定列 ............................................................................434 9.8.3 数据批量录入.............................................................................................................434 9.9 程序调试与错误处理............................................................................................................435 9.9.1 字段长度问题导致数据添加失败 .............................................................................436 9.9.2 由于 ADO 控件记录源属性的命令类型设置错误而出现的问题...........................436 9.9.3 语句中忘记书写连接运算符 .....................................................................................437 9.9.4 End if 语句没有配对出现 ..........................................................................................437 9.9.5 提示文件未找到的错误信息 .....................................................................................441 9.9.6 解决在打印报表时弹出的无效数据源的问题..........................................................442 9.9.7 解决报表的宽度大于纸的宽度的问题 .....................................................................442 1 SQL Server 2005 的起步 开发导读 录像视频位置 光 盘 \swf\list\ 安 装 SQL Server 2005.swf 光 盘 \swf\list\ 注 册 SQL Server 2005.swf 光 盘 \swf\list\ 删 除 SQL Server 2005.swf 光 盘 \swf\list\ 创 建 数 据 库.swf 光 盘 \swf\list\ 分 离 数 据 库.swf 光 盘 \swf\list\ 删 除 数 据 库.swf 光盘\swf\list\添加表.swf 光 盘 \swf\list\ 创 建 视 图.swf 光盘\swf\list\创建存储过 程.swf 光 盘 \swf\list\ 创 建 触 发 器.swf 光 盘 \swf\list\ 添 加 新 纪 录.swf 光 盘 \swf\list\ 备 份 数 据 库.swf 光 盘 \swf\list\ 导 入 数 据 库.swf 光 盘 \swf\list\ 导 出 数 据 库.swf。  SQL Server 2005 中提供许多 SQL Server 2000 中没有的功能,而且也对原有的各部分功能加 以改进以提高质量。  本章主要介绍 SQL Server 2005 的安装、管 理工具及基本操作。 2 SQL Server 2005 数据库系统开发案例精选 1.1 安装 SQL Server 2005 SQL Server 2005 为了满足不同使用人员对其性能、价格等多方面的需求,SQL Server 2005 提供了 5 个版本供使用人员选择,不同的版本对计算机软件及硬件的要求也不同。 1.1.1 SQL Server 2005 版本 可以根据使用人员的相关需求来选择 SQL Server 2005 中的某个版本。SQL Server 2005 的 5 个版本如表 1.1 所示。 表 1.1 SQL Server 2005 的 5 个版本 SQL Server2005 的 版本 支持的操作系统 功 能 说 明 Enterprise Edition (企业版) 支持 32 位和 64 位的操作系统,其中包 括:Windows 2000 Server SP4、Windows 2000 Advanced Server SP4 、 Windows 2000 Data Center Server SP4、Windows Server 2003 SP1 、 Windows 2003 Enterprise SP1、Windows 2003 Datacenter SP1 支持大型企业进行联机事务处理 (OLTP)、高度复杂的数据分析、数据 仓库系统和网站所需的性能。全面的 商业智能和分析能力及高可用性的 功能(如故障转移群集),可以处理 大多数关键业务,是最全面的 SQL Server 版本 Standard Edition (标准版) 支持 32 位和 64 位的操作系统,其中包 括:Windows 2000 Profesisonal SP4、 Windows 2000 Server SP4、Windows 2000 Advanced Server SP4 、 Windows 2000 Data Center Server SP4、Windows XP Profesisonal SP2、Windows Server 2003 SP1、Windows 2003 Enterprise SP1、 Windows 2003 Datacenter SP1 包括电子商务、数据仓库和业务流解 决方案所需的基本功能。集成商业智 能和高可用性的功能 Workgroup Edition (工作组版) 仅支持 32 位的操作系统,其中包括: Windows 2000 Profesisonal SP4、Windows 2000 Server SP4 、 Windows 2000 Advanced Server SP4 、 Windows 2000 Data Center Server SP4、Windows XP Profesisonal SP2、Windows Server 2003 SP1、Windows 2003 Enterprise SP1、 Windows 2003 Datacenter SP1 可以用作前端 Web 服务器,也可以 用于部门或分支机构的运营。包括 SQL Server 产品系列的核心数据库 功能,具有可靠、功能强大且易于管 理的特点 Developer Edition (开发版) 支持 32 位和 64 位的操作系统,其中包 括:Windows 2000 Profesisonal SP4、 Windows 2000 Server SP4、Windows 2000 Advanced Server SP4 、 Windows 2000 Data Center Server SP4、Windows XP Home SP2 、 Windows XP Professional SP2、Windows Server2003 SP1、Windows 2003 Enterprise SP1 、 Windows 2003 Datacenter SP1 开发人员可以在 SQL Server 上生成 任何类型的应用程序。包括 Enterprise Edition(企业版)的所有 功能,但有许可限制,只能用于开发 和测试系统,而不能用作生产服务器 3 C H A P T E R 1 第 1 章 SQL Server 2005 的起步 续表 SQL Server2005 的 版本 支持的操作系统 功 能 说 明 Express Edition (学习版) 仅支持 32 位的操作系统,其中包括: Windows 2000 Profesisonal SP4、Windows 2000 Server SP4 、 Windows 2000 Advanced Server SP4 、 Windows 2000 Data Center Server SP4、Windows Server 2003 SP1、Windows 2003 Enterprise SP1、 Windows 2003 Datacenter SP1、Windows 2003 Web SP1 免费、易用且便于管理的数据库。 Express Edition(学习版)与 Microsoft Visual Studio 2005 集成在一起,可以 轻松开发功能丰富、存储安全、可快 速部署的数据驱动应用程序。可以起 到客户端数据库以及基本服务器数 据库的作用 1.1.2 安装 SQL Server 2005 本节以 SQL Server 2005 Enterprise Edition(企业版)为例讲解 SQL Server 2005 的安装 需求及安装过程。 1.安装需求 在安装 SQL Server 2005 前,先来了解一下 SQL Server 2005 对计算机硬件环境的要求。 SQL Server 2005 的硬件环境要求如表 1.2 所示。 表 1.2 SQL Server 2005 对硬件环境要求 硬 件 需 求 CPU Pentium III 兼容处理器或更高速度的处理器(600 MHz) 内存 512MB 或更高 Express Edition(学习版)对内存要求为 192 MB 或更高) 数据库引擎和数据文件、复制以及全文搜索 150MB Analysis Services 和数据文件 35KB Reporting Services 和报表管理器 40MB Notification Services 引擎组件、客户端组件和规则组件 5MB Integration Services 9MB 客户端组件 12MB 管理工具 70MB 开发工具 20MB SQL Server 联机丛书和 SQL Server Mobile 联机丛书 15MB 硬盘 示例和示例数据库 390MB 光驱 CD 或 DVD 驱动器 网卡 10/100M 兼容网卡 监视器 VGA 或更高分辨率:分辨率至少为 1024×768 像素 除了对硬件的要求外,SQL Server 2005 还对网络环境、操作系统以及操作系统组件有 要求。具体要求如下。  网络环境要求 IE 浏览器版本需要在 Microsoft Internet Explorer 6.0 SP1 以上,因为 Microsoft 管理控制 台(MMC)和 HTML 帮助都需要它。只需 Internet Explorer 的最小安装即可满足要求。如果 4 SQL Server 2005 数据库系统开发案例精选 只安装客户端组件且不需要连接到要求加密的服务器,则 Internet Explorer 4.01(带 Service Pack 2)即可。 SQL Server 2005 中的 Reporting Services(SSRS)服务需要 IIS 5.0 或更高版本才能安装。 而且 Reporting Services 还需要 ASP.NET 2.0,如果在 Reporting Services 安装时尚未启用 ASP.NET,则 SQL Server 2005 安装程序将启用 ASP.NET。  操作系统要求 SQL Server 2005 Enterprise Edition(企业版)支持 32 位和 64 位的操作系统,具体操作 系统版本如下: Windows 2000 Server SP4、Windows 2000 Advanced Server SP4、Windows 2000 Data Center Server SP4。 Windows Server 2003 SP1、Windows 2003 Enterprise SP1、Windows 2003 Datacenter SP1。  操作系统组件要求 Microsoft Windows .NET Framework 2.0。 Microsoft Windows Installer3.1 或更高版本。 Microsoft 数据访问组件(MDAC)2.8 SP1 或更高版本。 2.安装 下面介绍安装 SQL Server 2005 Enterprise Edition(企业版),具体操作步骤如下。 视频录像:光盘.......\.swf...\.list....\.安装..SQL Server 2005.swf................. (1)将 SQL Server 2005 安装盘放入光驱内,光驱将会自动运行,并打开“开始”对 话框。 (2)在“开始”对话框中选择“服务器组件、工具、联机丛书和示例(C)”命令,执 行安装程序,打开“最终用户许可协议”对话框,如图 1.1 所示。 (3)在“最终用户许可协议”对话框中,选择“我接受许可条款和条件”复选框,单 击【下一步】按钮,打开图 1.2 所示的“安装必备组件”对话框。 图 1.1 “最终用户许可协议”对话框 图 1.2 “安装必备组件”对话框 (4)单击【安装】按钮,自动安装 SQL Server 2005 必备组件。单击【下一步】按钮, 5 C H A P T E R 1 第 1 章 SQL Server 2005 的起步 打开“SQL Server 安装向导”对话框。 (5)单击【下一步】按钮,打开“系统配置检查”对话框,检查系统中是否存在潜在 的安装问题。 (6)单击【下一步】按钮继续进行安装。在打开的“注册信息”对话框中要求用户输 入相关注册信息及正确的产品序列号。 (7)单击【下一步】按钮,在打开的“要安装的组件”对话框中选择需要升级或安装 的组件,如图 1.3 所示。 通过【高级】按钮选 取更多安装组件 图 1.3 “要安装的组件”对话框 部分安装组件的说明如表 1.3 所示。 表 1.3 部分安装组件的说明 服务器组件 描 述 SQL Server Database Services 数据库引擎包括数据库引擎(用于存储、处理和保护数据的核心服务)、复制、 全文搜索以及用于管理关系数据和 XML 数据的工具 Analysis Services Analysis Services 包括用于创建和管理联机分析处理(OLAP)以及数据挖掘应用 程序的工具 Reporting Services Reporting Services 包括用于创建、管理和部署表格报表、矩阵报表、图形报表 以及自由格式报表的服务器和客户端组件。Reporting Services 还是一个可用于 开发报表应用程序的可扩展平台 Notification Services Notification Services 是一个平台,用于开发和部署将个性化即时信息发送给各 种设备上的用户的应用程序 Integration Services Integration Services 是一组图形工具和可编程对象,用于移动、复制和转换数据 (8)单击【下一步】按钮,打开“实例名”对话框,选择实例的命名方式,这里选择 “默认实例”单选按钮,如图 1.4 所示。 (9)单击【下一步】按钮,打开“服务账户”对话框,在此选择登录时使用的账户。 选择“为每个服务账户进行自定义”复选框,可以对不同的服务定义使用不同的账户。服 务账户选项包括了“使用内置系统账户”(本地系统账户、网络服务账户或本地服务账户) 和“使用域用户账户”(一个使用 Windows 身份验证的域用户账户)。选中相应的 SQL Server “安装结束时启动服务”复选框,如图 1.5 所示。 (10)单击【下一步】按钮,打开图 1.6 所示的“身份验证模式”对话框,选择客户端 6 SQL Server 2005 数据库系统开发案例精选 和服务器连接时身份验证所用的安全模式。如果选择“混合模式(Windows 身份验证和 SQL Server 身份验证)”,则可以输入并确认 SQL Server 系统管理员(sa)密码。 图 1.4 “实例名”对话框 图 1.5 “服务账户”对话框 (11)“排序规则设置”对话框用于设置默认排序规则。选择排序规则后,单击【下一 步】按钮继续进行安装。 (12)单击【下一步】按钮,打开“报表服务器安装选项”对话框,选择报表服务器安 装设置,这里笔者选择“安装默认配置”单选按钮,如图 1.7 所示。 图 1.6 “身份验证模式”对话框 图 1.7 “报表服务器安装选项”对话框 (13)在“错误和使用情况报告设置”对话框中,选择传输报告的内容,单击【下一步】 按钮继续进行安装。 (14)单击“准备安装”对话框中的【安装】按钮开始安装。  注意 在安装时出现提示放入光盘 2 时,请将光盘 1 从光驱中取出并放入光盘 2,继续安装。 (15)当“安装进度”对话框中所用产品安装完成后,单击【下一步】按钮,打开“完 成 Microsoft SQL Server 2005 安装”对话框,单击“完成”按钮即可完成 SQL Server 2005 7 C H A P T E R 1 第 1 章 SQL Server 2005 的起步 的安装。 1.2 SQL Server 2005 管理工具 SQL Server 2005 提供了设计、开发、部署和管理关系数据库,Analysis Services 多维 数据集,数据转换包、复制拓扑、报表服务器和通知服务器所需的工具。 1.2.1 SQL Server Configuration Manager SQL Server Configuration Manager 即 SQL Server 配置管理器。用于管理与 SQL Server 相关联的服务、配置 SQL Server 使用的网络协议以及从 SQL Server 客户机管理网络连接配 置。它集成了 SQL Server 2000 中的服务器网络实用工具、客户端网络实用工具和服务管理 器的功能。SQL Server Configuration Manager 如图 1.8 所示。 图 1.8 SQL Server Configuration Manager 1.2.2 SQL Server Management Studio SQL Server Management Studio 即 SQL Server 管理控制台。用于访问、配置、控制、管 理和开发 SQL Server 的所有组件。是一组多样化的图形工具与多种功能齐全的脚本编辑器 的组合。它将以前版本的 SQL Server 中的企业管理器、查询分析器和 Analysis Manager 功 能整合到同一环境中。SQL Server Management Studio 如图 1.9 所示。 图 1.9 SQL Server Management Studio 1.2.3 SQL Server Profiler SQL Server Profiler 是用于 SQL 跟踪的图形用户界面,用来监视 Microsoft 数据库引擎 或 Analysis Services 的实例。可以捕获关于每个数据库事件的数据,并将其保存到文件或 8 SQL Server 2005 数据库系统开发案例精选 表,可供以后分析。SQL Server Profiler 如图 1.10 所示。 图 1.10 SQL Server Profiler 1.2.4 SQL Server Business Intelligence Development Studio Business Intelligence Development Studio 即业务智能开发工具。是用于开发包括 Analysis Services、Integration Services 和 Reporting Services 项目在内的商业解决方案的主要 环境。每个项目类型都提供了用于创建商业智能解决方案所需对象的模板,并提供了用于 处理这些对象的各种设计器、工具和向导,是包含特定于 SQL Server 2005 商业智能的附加 项目类型的 Microsoft Visual Studio 2005。Business Intelligence Development Studio 如图 1.11 所示。 图 1.11 Business Intelligence Development Studio 1.2.5 Reporting Services 配置管理器 Reporting Services 是一种基于服务器的新型报表平台,可用于创建和管理包含来 自关系数据源和多维数据源的数据的表报表、矩阵报表、图形报表和自由格式报表。 可以通过基于 Web 的连接来查看和管理您创建的报表。Reporting Services 配置管理器 可以配置 SQL Server 2005 Reporting Services 的安装。Reporting Services 配置如图 1.12 所示。 9 C H A P T E R 1 第 1 章 SQL Server 2005 的起步 图 1.12 Reporting Services 配置 1.2.6 SQL Server 外围应用配置器 SQL Server 外围应用配置器可以启用、禁用、开始或停止 SQL Server 2005 安装的一 些功能、服务和远程连接。SQL Server 外围应用配置器如图 1.13 所示。 图 1.13 SQL Server 外围应用配置器 1.2.7 数据库引擎优化顾问 数据库引擎优化顾问可以优化数据库,提高查询处理的性能。数据库引擎优化顾问如 图 1.14 所示。 10 SQL Server 2005 数据库系统开发案例精选 图 1.14 数据库引擎优化顾问 1.3 配置 SQL Server 2005 使用 SQL Server 2005 之前,需要配置其连接方式、设置启动服务、注册 SQL Server 2005 服务器等操作。 1.3.1 启动、暂停和关闭 SQL Server 2005 服务 启动、暂停和关闭 SQL Server 2005 服务是通过 SQL Server Configuration Manager 操作 的,当中可以对如下部分服务进行操作。 Analysis Services:该服务用于数据挖掘与分析工具。 FullText Search:该服务用于创建与维护全文搜索索引。 Reporing Services:该服务用于创作、管理以及发布用数据库创建的报表。 SQL Server:该服务用于 SQL Server 中的核心服务,主要针对运算查询、数据访问、 分配系统资源等功能。 SQL Server Agent:该服务用于自动化服务功能。 SQL Server Browser:该服务用于负责监听网络,与服务器中安装的实例信息。 操作相关服务的步骤如下。 (1)通过“开始”→“程序”→“Microsoft SQL Server 2005”→“配置工具”→“SQL Server Configuration Manager”命令,打开 SQL Server Configuration Manager 管理工具。 (2)在 SQL Server Configuration Manager 内部右边的树型结构中,选择“SQL Server 2005 服务”选项,如图 1.15 所示。 11 C H A P T E R 1 第 1 章 SQL Server 2005 的起步 图 1.15 选择“SQL Server 2005 服务” (3)在 SQL Server Configuration Manager 右侧的框架内选择需要操作的服务,单击鼠 标右键,在弹出的菜单中选择要对服务所作的操作。如启动、停止、暂停、恢复、重新启 动等操作,如图 1.16 所示。 图 1.16 服务的操作菜单 1.3.2 配置连接 SQL Server 2005 1.连接协议 SQL Server 2005 为服务器与客户端连接提供了 4 种协议。这 4 种协议如下。  Shared Memory 协议 Shared Memory 协议的客户端仅可以连接到同一台计算机上运行的 SQL Server 2005 实 例。这个协议对于其他计算机上的数据库是没用的。  Named Pipes 协议 Named Pipes 协议是管道协议,用内存中的一部分,通过某个进程向另一个进程传递信 息,相当于一个进程的输出就是另一个进程的输入。第二个进程可以是本地的(与第一个 进程位于同一台计算机上),也可以是远程的(位于互联网的计算机上)。  TCP/IP 协议 可以与网络中硬件结构和操作系统各异的计算机进行通信。当中包括路由网络流量的 标准,并能够提供高级安全功能。  VIA 协议 虚拟接口适配器(VIA)协议和 VIA 硬件一同使用。是 SQL Server 2005 新推出的协议, 非常适合在局域网中使用。 12 SQL Server 2005 数据库系统开发案例精选 2.配置 SQL Server 2005 服务器、客户端的连接协议 要将 SQL Server 2005 服务器与客户端连接起来,需要分别配置服务器、客户端的连接 协议后,才能正常连接。配置服务器、客户端连接的协议都可以通过 SQL Server Configuration Manager 工具实现。配置服务器、客户端的连接协议步骤分别如下。  服务器 (1)通过“开始”→“程序”→“Microsoft SQL Server 2005”→“配置工具”→“SQL Server Configuration Manager”命令,打开 SQL Server Configuration Manager 管理工具。 (2)在 SQL Server Configuration Manager 内部右边的树型结构中,单击“SQL Server 2005 网络配置”左边的 ,将“SQL Server 2005 网络配置”展开,选择其下面的子节点 “MSSQLSERVER 的协议”,如图 1.17 所示。 图 1.17 选择“MSSQLSERVER 的协议” (3)双击右边需要使用的协议,打开这个协议的属性窗口。例如双击“TCP/IP”协议 后打开“TCP/IP 属性”窗口,如图 1.18 所示。通过协议的属性窗口设置连接属性。 图 1.18 “TCP/IP 属性”窗口 (4)设置完成相应的连接协议后,还需要启动这个协议。启动方法是右键单击要启动 的协议,在弹出的菜单中选择“启动”命令,这时会出现“警告”对话框,提示需要重新 启动 SQL Sercver 服务,所作的更改才能生效。例如启动 TCP/IP 协议,如图 1.19 所示。弹 13 C H A P T E R 1 第 1 章 SQL Server 2005 的起步 出的“警告”对话框如图 1.20 所示。 图 1.19 启动 TCP/IP 协议 图 1.20 “警告”对话框 (5)重新启动 SQL Sercver 服务后,即可完成服务器的连接配置。  客户端 (1)通过“开始”→“程序”→“Microsoft SQL Server 2005”→“配置工具”→“SQL Server Configuration Manager”命令,打开 SQL Server Configuration Manager 管理工具。 (2)在 SQL Server Configuration Manager 内部右边的树型结构中,单击“SQL Native Client 配置”左边的 ,将“SQL Native Client 配置”展开,选择其下面的子节点“客户端 协议”,如图 1.21 所示。 图 1.21 选择“客户端协议协议” (3)在右边选择需要启动的协议,单击鼠标右键,在弹出的菜单中选择“启动”命令, 启动这个协议。例如启动“TCP/IP”协议,如图 1.22 所示。 图 1.22 启动客户端“TCP/IP”协议 14 SQL Server 2005 数据库系统开发案例精选 (4)选择展开的“SQL Native Client 配置”下面的子节点“别名”,如图 1.23 所示。 图 1.23 选择“别名” (5)在右边框架内单击鼠标右键,选择弹出菜单中的“新建别名”命令。打开“别名 —新建”对话框,如图 1.24 所示。 图 1.24 “别名—新建”对话框 (6)通过“别名—新建”对话框设置客户端连接服务器使用的协议及其相应的设置等 信息。设置完成后,单击【确定】按钮即可完成客户端连接服务器时的配置。然后可以使 用 SQL Server Management Studio 连接相应的数据库服务器进行操作。 3.连接 SQL Server 2005 服务器和客户端 (1)通过“开始”→“程序”→“Microsoft SQL Server 2005”→“SQL Server Management Studio”命令,打开 SQL Server Management Studio 管理工具。 (2)在“连接到服务器”对话框中输入服务器类型、名称及登录服务器使用的用户信 息,如图 1.25 所示。 (3)单击【选项】按钮,在“连接属性”选项卡中输入相关的连接信息,如使用的连 接协议、网络数据包大小等。“连接属性”选项卡如图 1.26 所示。 (4)相关信息输入完成后,单击【确定】按钮即可将服务器与客户端连接起来。 15 C H A P T E R 1 第 1 章 SQL Server 2005 的起步 图 1.25 “连接到服务器”对话框 图 1.26 “连接属性”选项卡 1.3.3 注册/删除 SQL Server 2005 服务器  注册 SQL Server 2005 服务器 视频录像:光盘.......\.swf...\.list....\.注册..SQL Server 2005.swf................. (1)通过“开始”→“程序”→“Microsoft SQL Server 2005”→“SQL Server Management Studio”命令,打开 SQL Server Management Studio 管理工具。 (2)在“连接到服务器”对话框中单击【取消】按钮,将“连接到服务器”对话框 关闭。 (3)选择“视图”→“已注册的服务器”命令,添加“已注册的服务器”窗口,并在 16 SQL Server 2005 数据库系统开发案例精选 “已注册服务器”窗口内单击鼠标右键,在弹出的菜单中选择“新建”→“服务器注册”命 令,如图 1.27 所示。 图 1.27 添加“已注册的服务器”对话框 (4)在“新建服务器注册”对话框中输入相关的注册服务器信息。如服务器名称、登 录服务器的用户名、使用的连接协议等。信息输入完毕,单击【测试】按钮,测试是否能 正常连接服务器。测试成功后单击【保存】按钮,即可完成服务器的注册。 删除 SQL Server 2005 服务器 视频录像:光盘.......\.swf...\.list....\.删除..SQL Server 2005.swf................. (1)通过“开始”→“程序”→“Microsoft SQL Server 2005”→“SQL Server Management Studio”命令,打开 SQL Server Management Studio 管理工具。 (2)在“连接到服务器”对话框中单击【取消】按钮,将“连接到服务器”对话框 关闭。 (3)选择“视图”→“已注册的服务器”命令,添加“已注册的服务器”窗口。 (4)在“已注册的服务器”版面选择要删除注册的服务器,单击鼠标右键,在弹出的 菜单中选择“删除”命令,将弹出“确认删除”对话框,如图 1.28 所示。 图 1.28 “确认删除”对话框 (5)单击“确认删除”对话框中的【是】按钮,即可将所选的注册服务器删除。 1.4 数据库管理 数据库是为特定目的(例如搜索、排序和重新组合数据)而组织和表示的信息、表和 其他对象的集合。 17 C H A P T E R 1 第 1 章 SQL Server 2005 的起步 1.4.1 创建数据库 视频录像:光盘.......\.swf...\.list....\.创建数据库......swf.... (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中选择“数据库”项,单击鼠标右键,在弹出的菜单 中选择“新建数据库”命令,打开“新建数据库”对话框,如图 1.29 所示。 图 1.29 “新建数据库”对话框 (3)在“新建数据库”对话框中输入创建数据库的相关信息。如数据库名称、数据库 文件及日志的存放位置等。信息输入完毕后,单击【确定】按钮,即可成功创建数据库。 1.4.2 分离/删除数据库 分离数据库是将数据库从 SQL Server 2005 数据库引擎实例中去除,但保留完整的数据 库及其数据文件和事务日志文件。 删除数据库是将数据库文件及其数据都从服务器上的磁盘中彻底删除。  分离数据库 视频录像:光盘.......\.swf...\.list....\.分离数据库......swf.... (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”。 18 SQL Server 2005 数据库系统开发案例精选 (3)展开“数据库”后,使用鼠标右键单击要分离的数据库,在弹出的菜单中选择“任 务”→“分离”命令。 (4)在“分离数据库”对话框中确认分离的信息与数据库后,单击【确定】按钮即可 将数据库分离。  删除数据库 视频录像:光盘.......\.swf...\.list....\.删除数据库......swf.... (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”。 (3)展开“数据库”后,使用鼠标右键单击要删除的数据库,在弹出的菜单中选择“删 除”命令。 (4)在“删除对象”对话框中确认选择数据库,单击【确定】按钮即可将该数据库 删除。 1.4.3 脱机与联机用户数据库 当 SQL Server 2005 服务器中某个用户数据库需要暂停使用时,可以使用脱机数据库的 方式暂停使用,在需要时再将数据库联机继续使用。  脱机数据库 (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”。 (3)展开“数据库”后,使用鼠标右键单击要暂停使用的数据库,在弹出的菜单中选择 “任务”→“脱机”命令,如图 1.30 所示。 图 1.30 脱机数据库 19 C H A P T E R 1 第 1 章 SQL Server 2005 的起步 (4)在“使数据库脱机”对话框显示脱机成功后,单击【关闭】按钮即可完成数据库 脱机。“使数据库脱机”对话框如图 1.31 所示。 图 1.31 “使数据库脱机”对话框  联机数据库 (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”。 (3)展开“数据库”后,右键单击要联机的数据库,在弹出的菜单中选择“任务”→“联 机”命令,如图 1.32 所示。 图 1.32 联机数据库 (4)在“使数据库联机”对话框显示联机成功后,单击【关闭】按钮即可将数据库联 机。“使数据库联机”对话框如图 1.33 所示。 20 SQL Server 2005 数据库系统开发案例精选 图 1.33 “使数据库联机”对话框 1.5 添加/删除表 表是以行(记录)和列(字段)组成的二维表格式,用来组织和存储数据。下面介绍 在 SQL Server 2005 中如何添加和删除表。  添加表 视频录像:光盘.......\.swf...\.list....\.添加表....swf.... (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”→“数据库名称” →“表”。 (3)右键单击表,在弹出的菜单中选择“新建表”命令。 (4)在右边表的选项卡中输入表中列的信息后,单击工具栏中的 按钮,如图 1.34 所示。 图 1.34 单击工具栏按钮保存表 21 C H A P T E R 1 第 1 章 SQL Server 2005 的起步 (5)在“选择名称”对话框中输入创建新表的名称,单击【确定】按钮创建该表。  删除表 (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”→“数据库名称” →“表”。 (3)右键单击要删除的表,在弹出的菜单中选择“删除”命令。 (4)在“删除对象”对话框中确认选择的表,单击【确定】按钮即可将该表删除。 1.6 修 改 表 1.6.1 添加字段 (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”→“数据库名称” →“表”。 (3)右键单击要修改的表,在弹出的菜单中选择“修改”命令。 (4)在右边表的选项卡中空白行处输入要添加字段的列名、数据类型等信息,如图 1.35 所示。 图 1.35 添加字段 (5)添加完列相关的信息后,单击工具栏中的 按钮即可完成添加字段操作。 1.6.2 修改字段属性 表中每列称为一个字段,字段具有自己的属性,如字段类型、字段大小等。字段类型 是字段最重要的属性,决定了字段能够存储哪种数据。它有 5 种基本字段类型:字符型、 文本型、数值型、逻辑型、日期时间型。 22 SQL Server 2005 数据库系统开发案例精选 下面介绍如何修改字段属性,具体步骤如下。 (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”→“数据库名称” →“表”。 (3)右键单击要修改的表,在弹出的菜单中选择“修改”命令。 (4)在右边表的选项卡中选择需要修改的列,在列属性选项卡内修改其列名、大小、 数据类型、默认值等相关属性信息,如图 1.36 所示。 图 1.36 修改列属性 (5)修改完列相关的信息后,单击工具栏中的 按钮即可完成修改字段操作。 1.6.3 设置主键/索引 主键是惟一地标识表中所有行的一列或一组列,主键不允许空值,任何两行都不能有 相同的主键值。如果有多个键可以惟一地标识表中的行,则这些键都称为候选键。只有一 个候选键可以选择作为表的主键;所有其他候选键都称为备用键。 索引是一个单独的、物理的数据库结构。在数据库中,索引使数据库程序无须对整个 表进行扫描,就可以在其中找到所需数据。 设置主键及索引的步骤如下。 (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”→“数据库名称” →“表”。 (3)右键单击要修改的表,在弹出的菜单中选择“修改”命令。 (4)在右边表的选项卡中选择需要设置为主键/索引的列,单击鼠标右键,根据设置需 求选择“设置主键”、“索引/键”、“全文本索引”和“XML 索引”等菜单命令,如图 1.37 所示。 23 C H A P T E R 1 第 1 章 SQL Server 2005 的起步 图 1.37 设置主键及索引 (5)设置完成后,单击工具栏中的 按钮保存设置操作。 1.7 视 图 管 理 视图是一个虚拟表,是从一张或多张表或视图中导出的表,其内容由查询定义。视图 中也包含一系列带有名称的列和行数据,但这些数据并不在数据库中以存储数据值集的形 式存在。 1.7.1 创建视图 视频录像:光盘.......\.swf...\.list....\.创建视...图..swf.... (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”→“数据库名称” →“视图”。右键单击“视图”,在弹出的菜单 中选择“新建视图”命令,打开“添加表”对 话框,如图 1.38 所示。 (3)通过“添加表”对话框,添加视图 中需要的表。选择需要的表后,单击【添加】 按钮即可将表添加。添加完成后单击【关闭】 按钮,在视图对话框中设计视图,如图 1.39 所示。  关系图窗格:显示正在查询的表和其他表值对象。每个矩形代表一个表或表值对 象,并显示可用的数据列。联接用矩形之间的连线来表示。  条件窗格:包含一个类似于电子表格的网格,在该网格中可以指定相应的选项, 例如要显示的数据列、要选择的行、行的分组方式等。 图 1.38 “添加表”对话框 24 SQL Server 2005 数据库系统开发案例精选 关系图窗格 条件窗格 SQL 窗格 结果窗格 图 1.39 设计视图  SQL 窗格:显示查询或视图的 SQL 语句,可以自行编辑。  结果窗格:显示一个网格,用来包含查询或视图检索到的数据。 (4)在关系图窗格中选择视图中需要显示的列,单击工具栏中的 按钮,在“选择名 称”对话框中输入创建视图的名称,单击【确定】按钮完成创建视图。 1.7.2 修改视图 修改视图通过在“对象资源管理器”窗口中展开连接的服务器中的“数据库”→“视 图”。在“视图”文件夹内找到要修改的视图单击鼠标右键,在弹出的菜单中选择“修改” 命令,即可打开该视图进行修改。 1.7.3 删除视图 删除视图通过在“对象资源管理器”窗口中展开连接的服务器中的“数据库”→“视 图”。在“视图”文件夹内找到要删除的视图单击鼠标右键,在弹出的菜单中选择“删除” 命令。在“删除对象”对话框中确认该视图,确认无误后单击【确定】按钮,即可将该视 图删除。 1.8 存储过程管理 存储过程是一组为了完成某种特定功能的 T-SQL 语句集合,编译后被存储在 SQL Server 服务器端数据库中,存储过程可以分为系统存储过程和自定义存储过程。利用存储 过程可以加速 SQL 语句的执行。 25 C H A P T E R 1 第 1 章 SQL Server 2005 的起步 1.8.1 创建存储过程 视频录像:光盘.......\.swf...\.list....\.创建存储过程.......swf.... (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”→“数据库名称” →“可编程性”→“存储过程”。右键单击“存储过程”,在弹出的菜单中选择“新建存储 过程”命令,打开 SQL 窗格,如图 1.40 所示。 图 1.40 创建存储过程打开的 SQL 窗格 (3)在 SQL 窗格中写入创建存储过程的 SQL 语句,单击工具栏中 按钮创建存 储过程。 1.8.2 修改存储过程 (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”→“数据库名称” →“可编程性”→“存储过程”。在“存储过程”中选择要修改的存储过程单击鼠标右键, 选择弹出菜单中的“修改”命令。该存储过程将被 SQL 窗格打开。 (3)在 SQL 窗格中修改该存储过程,单击工具栏中 按钮完成对存储过程的修改。 1.8.3 删除存储过程 (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”→“数据库名称” →“可编程性”→“存储过程”。在“存储过程”中右键单击要删除的存储过程,在弹出的 菜单中选择“删除”命令,打开“删除对象”对话框。 (3)在“删除对象”对话框中确认该存储过程,确认无误后单击【确定】按钮,即可 26 SQL Server 2005 数据库系统开发案例精选 将该存储过程删除。 1.9 触发器管理 触发器是一种特殊类型的存储过程,存储过程可以通过存储过程名来进行调用,而触 发器主要通过事件触发而被执行的,当对某表进行如 Delete、Insert 等数据记录操作时,SQL Server 就会自动执行触发器事先定义好的语句。 1.9.1 创建触发器 视频录像:光盘.......\.swf...\.list....\.创建触发器......swf.... (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”→“数据库名称” →“表”→表名称→“触发器”。右键单击“触发器”,在弹出的菜单中选择“新建触发器” 命令,打开 SQL 窗格。 (3)在 SQL 窗格中写入创建触发器的 SQL 语句,单击工具栏中 按钮创建触发器。 1.9.2 修改触发器 (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”→“数据库名称” →“表”→表名称→“触发器”。右键单击需要修改的“触发器”,在弹出的菜单中选择“修 改”命令,打开 SQL 窗格。 (3)修改 SQL 窗格中的触发器代码,单击工具栏中 按钮保存修改后的触发器。 1.9.3 删除触发器 (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”→“数据库名称” →“表”→表名称→“触发器”。在“触发器”中右键单击需要删除的触发器,在弹出的菜 单中选择“删除”命令,打开“删除对象”对话框。 (3)在“删除对象”对话框中确认该触发器,确认无误后单击【确定】按钮将该触发 器删除。 1.10 编辑数据库的数据 1.10.1 添加新记录 视频录像:光盘.......\.swf...\.list....\.添加新记录......swf.... (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”→“数据库名称” →“表”。 27 C H A P T E R 1 第 1 章 SQL Server 2005 的起步 (3)右键单击要添加新记录的表,在弹出的菜单中选择“打开表”命令。 (4)选中左边行内容都为“NULL”的记录添加新记录,如图 1.41 所示。 图 1.41 添加记录 (5)添加完记录后,将该表关闭,记录会自动保存。 1.10.2 修改记录 (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”→“数据库名称” →“表”。 (3)右键单击修改记录的表,在弹出的菜单中选择“打开表”命令。 (4)选中左边需要修改的记录行修改该记录。 (5)修改后将表关闭,修改的记录会自动保存。 1.10.3 删除记录 (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”→“数据库名称” →“表”。 (3)右键单击删除记录的表,在弹出的菜单中选择“打开表”命令。 (4)右键单击需要删除的记录,在弹出的菜单中选择“删除”命令。 (5)单击删除时提示对话框中的【是】按钮,将该条记录永久删除。 1.11 维护数据库 1.11.1 数据库备份 数据库备份类型分为完全备份及差异备份。数据库完全备份是将整个数据库备份,如 28 SQL Server 2005 数据库系统开发案例精选 数据库文件、日志文件等。而差异备份是在一次完全备份数据库后,将数据库完全备份后 所作的修改内容备份。下面介绍完全备份数据库的步骤。 视频录像:光盘.......\.swf...\.list....\.备份数据库......swf.... (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”。 (3)右键单击需要备份的数据库,在弹出的菜单中选择“任务”→“备份”,打开“备 份数据库”窗口,如图 1.42 所示。 图 1.42 “备份数据库”窗口 (4)通过“备份数据库”窗口选择备份数据库的类型、备份名称、备份文件保存位置 等信息。设置完成后单击【确定】按钮即可备份数据库。 1.11.2 数据库还原 由于某种原因导致数据库中的数据发生错误,这时就可以通过还原数据库操作,将数 据库中的数据恢复到备份时的状态。数据库还原的步骤如下。 (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”。 (3)右键单击需要还原的数据库,在弹出的菜单中选择“任务”→“还原”→“数据 库”,打开“还原数据库”窗口,如图 1.43 所示。 (4)通过“还原数据库”窗口设置还原数据库的文件与还原信息,单击【确定】按钮 即可还原数据库。 29 C H A P T E R 1 第 1 章 SQL Server 2005 的起步 图 1.43 “还原数据库”窗口 1.11.3 分离数据库 分离数据库可以将数据库中暂时不用的数据库的数据文件与日志文件分离出来,从而 减少 SQL Server 服务器的负担。分离数据库的步骤如下。 (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”。 (3)右键单击“数据库”内需要分离的数据库,在弹出的菜单中选择“任务”/“分离” 命令,打开“分离数据库”窗口,如图 1.44 所示。 图 1.44 “分离数据库”窗口 30 SQL Server 2005 数据库系统开发案例精选 (4)单击【确定】按钮即可分离该数据库。 1.11.4 附加数据库 附加数据库可以将数据库的日志文件与数据文件,附加到另一个 SQL Server 服务上作 为一个完整的数据库运行。附加数据库的步骤如下。 (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”。 (3)右键单击“数据库”,在弹出的菜单中选择“附加”命令,打开“附加数据库”窗 口,如图 1.45 所示。 图 1.45 “附加数据库”窗口 (4)单击【添加】按钮添加附加数据库的数据文件后,单击【确定】按钮即可附加该 数据库。 1.11.5 导入数据库 导入数据库可以将其他数据库或文件当中的数据导入到数据库中。导入数据库步骤 如下。 视频录像:光盘.......\.swf...\.list....\.导入数据库......swf.... (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”。 (3)右键单击需要导入数据的数据库,在弹出的菜单中选择“任务”→“导入数据” 命令,打开“SQL Server 导入和导出向导”窗口,如图 1.46 所示。 (4)通过“SQL Server 导入和导出向导”设置导入数据源、导入的数据库、导入数据 的内容等相关信息,并导入数据。 31 C H A P T E R 1 第 1 章 SQL Server 2005 的起步 图 1.46 “SQL Server 导入和导出向导”窗口 1.11.6 导出数据库 视频录像:光盘.......\.swf...\.list....\.导出数据库......swf.... (1)使用 SQL Server Management Studio 连接 SQL Server 2005 服务器。 (2)在“对象资源管理器”窗口中展开连接的服务器中的“数据库”。 (3)右键单击需要导出数据的数据库,在弹出的菜单中选择“任务”→“导出数据” 命令,打开“SQL Server 导入和导出向导”窗口,如图 1.47 所示。 图 1.47 “SQL Server 导入和导出向导”窗口 (4)通过“SQL Server 导入和导出向导”设置导出数据源、导出的数据库、导出数据 的内容等相关信息,并导出数据。 2 数据查询技术 本章导读 本章详细讲解了 SQL Server2005 中 SQL 查询 技术。  SELECT 的查询  嵌套查询  连接查询  使用空值  交叉表查询  CTE 查询  插入数据  修改数据  删除数据 34 SQL Server 2005 数据库系统开发案例精选 2.1 SELECT 语句查询 SELECT 语句是数据库结构化查询语言 SQL 的核心内容。SELECT 语句可以以多种不 同的方式查询数据库中的数据,并且可以显示通过现有数据推导、计算出的数据信息,如 显示平均年龄、不同学期的平均成绩等。 2.1.1 简单的 SELECT 语句查询 SELECT 语句的基本语法如下: SELECT select_list [ INTO new_table ] FROM table_source [ WHERE search_condition ] [ GROUP BY group_by_expression ] [ HAVING search_condition ] [ ORDER BY order_BY_expression [ASC| DESC ] ] 在上述代码中各参数的具体说明如表 2.1 所示。 表 2.1 SELECT 语句的参数说明 参 数 描 述 select_list 指定由查询返回的列。它是一个逗号分隔的表达式列表。每个表达式同时定义 格式(数据类型和大小)和结果集列的数据来源。每个选择列表表达式通常是 对从中获取数据的源表或视图的列的引用,但也可能是其他表达式,例如常量 或 T-SQL 函数。在选择列表中使用 * 表达式指定返回源表中的所有列 new_table new_table_name 指定新表的名称,创建新表并将查询行插入新表中 table_source 要查询的表。这些表可能包括基表、视图和链接表。FROM 子句还可包含联接 说明,该说明定义了 SQL Server 用来在表之间进行导航的特定路径。FROM 子 句还用在 DELETE 和 UPDATE 语句中以定义要修改的表 search_conditions 查询条件。WHERE 子句还用在 DELETE 和 UPDATE 语句中以定义目标表中 要修改的行 group_by_expression 分组表达式。GROUP BY 子句根据 group_by_list 列中的值将结果集分成组。 例如,student 表在“性别”列中有两个值。GROUP BY 性别 子句将结果集分 成两组,每组对应于性别的一个值 search_conditions HAVING 子句是分组或聚合的查询条件。逻辑上讲,HAVING 子句从中间结果 集对行进行筛选,这些中间结果集是用 SELECT 语句中的 FROM、WHERE 或 GROUP BY 子句创建的。HAVING 子句通常与 GROUP BY 子句一起使用,尽 管 HAVING 子句前面不必有 GROUP BY 子句 order_BY_expression ASC ORDER BY 子句定义结果集中的行排列的顺序。order_BY_expression 指定组成 排序列表的结果集的列。ASC 关键字用于指定行按升序排序 order_BY_expression DESC ORDER BY 子句定义结果集中的行排列的顺序。order_BY_expression 指定组成 排序列表的结果集的列。DESC 关键字用于指定行是按降序排序 1.选择所有字段 SELECT 子句用于选择表中的字段。如果要显示数据表中所有的字段值,SELECT 子 句后用星号(*)表示。 35 C H A P T E R 2 第 2 章 数据查询技术 示例: 查询 student 表的所有字段。SQL 语句如下。 Use db_student SELECT * from student 执行过程如图 2.1 所示。 图 2.1 显示 student 表的所有字段 2.选择部分字段 在查询表时,很多时候只查询部分字段的记录。这时在 Select 子句后分别列出各个字 段名称即可。并且各个字段名称之间用逗号相隔。 示例: 查询 student 表的姓名、性别和年龄字段的所有记录。SQL 语句如下: Use db_student SELECT 姓名,性别,年龄 from student 执行过程如图 2.2 所示。 图 2.2 查询 student 表的部分字段 3.不显示重复记录 DISTINCT 关键字用于去除查询的结果集中重复的记录。如果用户没有指定 DISTINCT 关键字,那么系统默认将返回符合条件的所有记录,其中包括重复的记录。 示例: 在 course 表中,显示没有重复记录的“课程类别”字段的信息。SQL 语句如下: Use db_student SELECT DISTINCT课程类别 from course 执行过程如图 2.3 所示。 当多个字段使用 DISTINCT 关键字时,查询结果只显示每个有效组合的一个例子。即 结果表中没有完全相同的两个行。 36 SQL Server 2005 数据库系统开发案例精选 图 2.3 显示 course 表的没有重复记录的课程类别字段信息 例如在 grade 表中显示“学号”和“课程代号”的不同值。SQL 语句如下: Use db_student SELECT DISTINCT学号,课程代号 from grade 上述例子不会出现学号和课程代号完全相同的记录。 4.TOP 关键字 TOP 关键字可以限制查询结果显示的行数。 TOP 关键字的语法: SELECT TOP n [PERCENT] from table WHERE ORDER BY⋯ 参数说明: n:TOP n 返回满足 WHERE 子句的前 n 条记录。如果子句中满足条件的记录少于 n,那么返回满足条件的记录。n 是介于 0~4294967295 之间的整数。 [PERCENT]:从查询结果集中输出前百分之 n 记录。n 必须是 0~100 之间的整数。 示例: 查询 course 表的前 3 条记录。SQL 语句如下: Use db_student SELECT TOP 3 * from course 实现的过程如图 2.4 所示。 图 2.4 显示 course 表的前 3 条记录 TOP 关键字还可以按百分比返回记录的行数。 例如显示 student 表中的前 6%的记录。SQL 语句如下: Use db_student SELECT TOP 6 PERCENT * from student 37 C H A P T E R 2 第 2 章 数据查询技术 TOP 关键字可以显示结果记录的后几行,是用 ORDER BY 关键字降序排列实现的。 例如显示 studnet 表中的年龄最大的一名学生信息。在查询分析器中输入 SQL 语句如下: Use db_student SELECT top 1 * from student ORDER BY 年龄 desc 2.1.2 WHERE 条件查询 包含 WHERE 子句的 SELECT 语句称为条件查询语句。因为一个表通常会有数千条记 录,在查询结果中,用户仅需其中的一部分记录,这时需要使用 WHERE 子句指定一系列 的查询条件。下面是 WHERE 子句简单的语法: SELECT<字段列表> from<表名> WHERE<条件表达式> 为了实现许多不同种类的查询,WHERE 子句提供了丰富的搜索条件,主要包括以下 5 个基本的搜索条件。 比较运算符(如=、<>、<和>)。 范围说明(BETWEEN 和 NOT BETWEEN)。 可选值列表(IN 和 NOT IN)。 模式匹配(LIKE 和 NOT LIKE)。 上述条件的逻辑组合(AND、OR、NOT)。 1.比较查询条件 比较查询条件由比较运算符连接表达式组成,系统将根据该查询条件的真假来决定某 一条记录是否满足该查询条件,只有满足该查询条件的记录才会出现在最终的结果集中。 SQL Server 比较运算符如表 2.2 所示。 表 2.2 比较运算符 运 算 符 说 明 = 等于 > 大于 < 小于 >= 大于等于 <= 小于等于 !> 不大于 !< 不小于 <>或!= 不等于 在 course 表中,查询学分大于 7 的课程信息。SQL 语句如下: Use db_student SELECT * from course WHERE 学分>7 实现的过程如图 2.5 所示。 38 SQL Server 2005 数据库系统开发案例精选 图 2.5 查询 course 表中学分大于 7 的记录 例如在 course 表中,查询“学分”小于等于 7 的,SQL 语句如下: Use db_student SELECT * from course WHERE 学分<=7 例如在 course 表中,查询“学分”在 7~9 之间(包括 7 和 9)的所有课程信息。SQL 语句如下: Use db_student SELECT * from course WHERE 学分>=7 and 学分<=9 例如在 course 表中,查询“学分”不小于 7 的所有课程信息。SQL 语句如下: Use db_student SELECT * from course WHERE 学分 !<7 换一种写法。查询“学分”不小于 7 的所有课程信息。SQL 语句如下: Use db_student SELECT * from course WHERE 学分>=7 例如在 course 表中,查询“学分”不等于 7 的所有课程信息。SQL 语句如下: Use db_student SELECT * from course WHERE 学分!=7 知识扩展:搜索满足条件的记录行,要比消除所有不满足条件的记录行快得多, 所以将否定的 WHERE 条件改写为肯定的条件会提高性能,这是一个需要记住的准则。 2.范围查询条件 通常使用 BETWEEN⋯AND 和 NOT⋯BETWEEN⋯AND 来指定范围查询条件。 使用 BETWEEN⋯ AND 查询条件时,指定的第一个值必须小于第二个值。因为 BETWEEN⋯AND 实质是查询条件“大于等于第一个值,并且小于等于第二个值”的简写 形式。即 BETWEEN⋯AND 要包括两端的值,等价于比较运算符(>=...<=)。 示例: 在 course 表中,查询学分在 7~9 之间的所有课程信息。SQL 语句如下: Use db_student SELECT * from course WHERE 学分BETWEEN 7 AND 9 实现的过程如图 2.6 所示。 上述 SQL 也可以用>=⋯<= 符号来改写。相当的 SQL 语句如下: Use db_ student SELECT * from course WHERE 学分>=7 AND 学分<=9 而 NOT⋯BETWEEN⋯AND 语句返回某个数据值在两个指定值的范围以外的,但并不 包括两个指定的值。 39 C H A P T E R 2 第 2 章 数据查询技术 图 2.6 在 course 表中查询学分在 7~9 之间的课程信息 例如在 course 表中,显示学分不在 7~9 之间的课程信息。SQL 语句如下: Use db_student SELECT * from course WHERE 学分 NOT BETWEEN 7 AND 9 3.列表查询条件 当测试一个数据值是否匹配一组目标值中的一个时,通常使用 IN 关键字来指定列表搜 索条件。IN 关键字的格式是 IN(目标值 1、目标值 2、目标值 3、⋯),目标值的项目之间 必须使用逗号分隔,并且括在括号中。 示例: 在 course 表中,查询课程代号是 k01、k02 和 k04 的课程信息。SQL 语句如下: Use db_student SELECT * From course WHERE 课程代号in(’k01’,’k02’,’k04’) 实现的过程如图 2.7 所示。 图 2.7 在 course 表中查询课程代是 k01、k02、k04 的课程信息 IN 运算符可以与 NOT 配合使用排除特定的行。测试一个数据值是否匹配任何目标值。 例如在 course 表中,查询课程代号不是 k01、k03 和 k04 的课程信息。SQL 语句如下: Use db_student SELECT * from course WHERE 课程代号 NOT IN (’k01’,’k02’,’k04’) 下面对数值型字段的 IN(列表)查询来举例。 例如在 course 表中,查询学分是 6、8 和 9 的课程信息。SQL 语句如下: Use db_student SELECT * from course WHERE 学分 IN(6 , 8 , 9) 4.模糊 LIKE 查询 有时用户对查询数据表中数据的了解可能不全面,例如不能确定所要查询人的姓名而 只知道他姓李,查询某个人的联系方式只知道是以“3451”结尾等,这时需要使用 LIKE 40 SQL Server 2005 数据库系统开发案例精选 进行模糊查询。LIKE 关键字需要使用通配符在字符串内查找指定的模式,所以用户需要了 解通配符及其含义。通配符的含义如表 2.3 所示。 表 2.3 LIKE 关键字中的通配符及其含义 通 配 符 说 明 % 由零个或更多字符组成的任意字符串 _ 任意单个字符 [ ] 用于指定范围,例如[A~F],表示 A~F 范围内的任何单个字符 [^ ] 表示指定范围之外的,例如[ ^ A~F]范围以外的任何单个字符 (1)“%”通配符 “%”通配符能匹配 0 个或更多个字符的任意长度的字符串。 示例: 在 student 表中,查询姓“李”的学生信息。SQL 语句如下: Use db_student SELECT * from student WHERE 姓名 LIKE ’李%’ 执行的过程如图 2.8 所示。 图 2.8 在 student 表中查询姓李的学生信息 在 SQL Server 语句中,可以在查询条件的任意位置放置一个“%”符号来代表任意长 度的字符串。 例如在 student 表中,查询姓“李”的并且联系方式是以“2”打头的学生信息。SQL 语句如下: Use db_student SELECT * from student WHERE 姓名 LIKE ’李%’ AND 联系方式 LIKE ’2%’ (2)“_”通配符 “_”号表示任意单个字符,该符号只能匹配一个字符,利用“_”号可以作为通配符组 成匹配模式进行查询。 示例: 在 student 表中,查询姓“刘”的、并且名字只有两个字的同学信息。SQL 语句如下: Use db_student SELECT * from student WHERE 姓名 LIKE ’刘_’ 实现的过程如图 2.9 所示。 “_”符号无论放在查询条件的什么位置,都只能代表一个字符。 41 C H A P T E R 2 第 2 章 数据查询技术 图 2.9 查询姓“刘”的、并且名字只有两个字的同学信息 例如在 student 表,查询姓“李”的并且末尾字是“葱”的同学信息。SQL 语句如下: Use db_student SELECT * from student WHERE 姓名 LIKE ’李_葱’ (3)“[ ]”通配符 在模式查询中可以使用“[ ]”符号来查询一定范围内的数据。“[ ]”符号用于表示一定 范围内的任意单个字符,它包括两端数据。 示例: 在 student 表中,查询联系方式以“3451”结尾并且开头数字位于 1~5 之间的学生信 息。SQL 语句如下: Use db_student SELECT * from student WHERE 联系方式 LIKE ’[1-5]3451’ 实现的过程如图 2.10 所示。 图 2.10 查询联系方式以 3451 结尾并且开头数字位于 1~5 之间的学生信息 例如在 grade 表中,查询学号是“B001”~“B003”之间的学生成绩信息。SQL 语句 如下: Use db_student SELECT * from grade WHERE 学号 LIKE ’b00[1-3]’ (4)“[^ ]”通配符 在模式查询中可以使用“[^ ]”符号查询不在指定范围内的数据。“[^ ]”符号用于表示 不在某范围内的任意单个字符,它包括两端数据。 示例: 在 student 表中,查询联系方式以“3451”结尾,但不以 2 开头的学生信息。SQL 语句 如下: Use db_student SELECT * from student WHERE 联系方式 LIKE ’[^2]3451’ 实现的过程如图 2.11 所示。 42 SQL Server 2005 数据库系统开发案例精选 图 2.11 查询联系方式以 3451 结尾但不以 2 开头的学生信息 NOT LIKE 的含义与 LIKE 关键字正好相反,查询结果将返回不符合匹配模式查询。 例如查询不姓“李”的学生信息。SQL 语句如下: SELECT * from student WHERE 姓名 NOT LIKE ’李%’ 例如查询除了名字是两个字的姓“李”的其他同学信息。SQL 语句如下: SELECT * from student WHERE 姓名 NOT LIKE ’李_’ 例如查询除了电话号码以“3451”结尾并且开头数字位于 1~5 之间的其他的学生信息。 SQL 语句如下: SELECT * from student WHERE 联系方式 NOT LIKE ’[1-5]3451’ 例如查询电话号码不符合如下条件的学生信息,这些条件是电话号码是以“3451”结 尾,但不以 2 开头的。SQL 语句如下: SELECT * from student WHERE 联系方式 NOT LIKE ’[^2]3451’ 5.复合查询条件 在很多情况下,在 where 子句中仅仅使用一个条件不能准确地从表中检索到需要的数据, 这时就需要逻辑运算符 AND、OR 和 NOT。使用逻辑运算符时,遵循的指导原则如下。 (1)使用 AND 返回满足所有条件的行。 (2)使用 OR 返回满足任一条件的行。 (3)使用 NOT 返回不满足表达式的行。 例如用 OR 进行查询。查询学号是“B001”或者是“B003”的学生信息。SQL 语句如下: Use db_student SELECT * from student WHERE 学号=’B001’ OR 学号=’B003’ 例如用 AND 进行查询。查询性别是“女”并且年龄大于 20 岁的学生信息。SQL 语句 如下: Use db_student SELECT * from student WHERE 性别=’女’ AND 年龄>20 就像数据运算符乘和除一样,它们之间是具有优先级顺序的,NOT 优先级最高,AND 次之,OR 的优先级最低。下面举例用 AND 和 OR 结合进行查询。 示例: 在 student 表中,要查询年龄大于 21 女生或者年龄大于等于 19 的男生信息。SQL 语句 如下: Use db_student SELECT * from student WHERE 年龄> 21 AND 性别=’女’ OR 年龄>=19 AND 性别=’男’ 实现的过程如图 2.12 所示。 43 C H A P T E R 2 第 2 章 数据查询技术 图 2.12 复合搜索 使用逻辑关键字 AND、OR、NOT 和括号把搜索条件分组,可以构建非常复杂的搜索 条件。 例如在 student 表中,查询年龄大于 20 的女生或者年龄大于 22 的男生,并且电话号码 都是“23451”的学生信息。在查询分析器中输入的 SQL 语句如下: use db_student SELECT * from student where (年龄>20 and 性别=’女’ or 年龄>22 and 性别=’男’) and 联系方式 = ’23451’ 2.1.3 ORDER BY 排序查询 如果数据表比较小,不用 ORDER BY 子句,查询结果会按照在数据表中的顺序排列。 但如果数据表比较大,则必须使用 ORDER BY 子句,方便查看查询结果。 ORDER BY 子句由关键字 ORDER BY 后跟一个用逗号分开的排序列表组成。 语法: [ ORDER BY { order_by_expression [ ASC | DESC ] } [ ,...n ] ] 参数说明如表 2.4 所示。 表 2.4 ORDER BY 语句的参数说明 设 置 值 说 明 order_by_expression 指定要排序的列。可以将排序列指定为列名或列的别名(可由表名或视图名限定) 和表达式,或者指定为代表选择列表内的名称、别名或表达式的位置的负整数。 可指定多个排序列。ORDER BY 子句中的排序列序列定义排序结果集的结构 ORDER BY 子句可包括未出现在此选择列表中的项目。然而,如果指定 SELECT DISTINCT, 或者如果 SELECT 语句包含 UNION 运算符,则排序列必定出现在选择列表 中。此外,当 SELECT 语句包含 UNION 运算符时,列名或列的别名必须是在 第一选择列表内指定的列名或列的别名 ASC 指定按递增顺序,从低到高对指定列中的值进行排序。默认就是递增顺序 DESC 指定按递减顺序,从高到低对指定列中的值进行排序 1.单级排序 排序的关键字是 ORDER BY,默认状态下是升序,关键字是 ASC。可以按照某一个字 段排序,排序的字段是数值型,也可以是字符型、日期和时间型。 示例: 在 course 表中,按学分显示课程信息。SQL 语句如下: Use db_student SELECT * from course ORDER BY 学分 44 SQL Server 2005 数据库系统开发案例精选 执行的过程如图 2.13 所示。 图 2.13 course 表按学分升序显示 查询结果以降序排序,必须在列名后指定关键字的 DESC。 例如在 grade 表中,按照“课程成绩”降序排序。SQL 语句如下: Use db_student SELECT * from grade ORDER BY 课程成绩 desc 2.多级排序 按照一列进行排序后,如果该列有重复的记录值,则重复记录值这部分就不会进行有 效的排序,这就需要再附加一个字段,作为第二次排序的标准,对没有排序的记录进行再 排序。 示例: 在 grade 表中,按照学生的“学期”降序排列,然后再按照“课程成绩”升序排序。 SQL 语句如下: Use db_student SELECT * from grade ORDER BY 学期desc, 课程成绩 实现的过程如图 2.14 所示。 图 2.14 grade 表按多个字段排序 当排序字段是字符类型时,将按照字符数据中字母或汉字的拼音在字典中的顺序排序, 先比较第一个字母在字典中的顺序,位置在前的表示该字符串小于后面的字符串,若第一 个字符相同,则继续比较第二个字母,直至得出比较结果。 例如在 course 表中,先按照“课程类别”升序排列,再按照“课程内容”降序排列。 SQL 语句如下: Use db_student SELECT * from course ORDERY BY 课程类别 ASC ,课程内容 DESC 45 C H A P T E R 2 第 2 章 数据查询技术 2.1.4 GROUP BY 分组查询 GROUP BY 子句可以将表的行划分为不同的组。分别总结每个组,这样就可以控 制想要看见的详细信息的级别。例如按照学生的性别分组、按照不同的学期分组等。 下面介绍使用 GROUP BY 子句的注意事项。 (1)在 SELECT 子句的字段列表中,除了聚集函数外,其他所出现的字段一定要 GROUP BY 子句中有定义才行。例如“GROUP BY A,B”,那么“SELECT SUM(A),C”就有 问题,因为 C 不在 GROUP BY 中,但是 SUM(A)还是可以的。 (2)SELECT 子句的字段列表中不一定要有聚集函数,但至少要用到 GROUP BY 子句 列表中的一个项目。例如“GROUP BY A,B,C”,则“SELECT A”是可以的。 (3)在 SQL Server 中 text、ntext 和 image 数据类型的字段不能作为 GROUP BY 子句 的分组依据。 (4)GROUP BY 子句不能使用字段别名。 1.按单个字段分组 GROUP BY 子句可以基于指定某一列的值将数据集合划分为多个分组,同一组内所 有记录在分组属性上具有相同值。 示例: 在 student 表中,按照“性别”分组。SQL 语句如下: Use db_student SELECT * from student GROUP BY 性别 实现的过程如图 2.15 所示。 图 2.15 student 表按照性别分组 在下列查询中,“姓名”列既不包含在 GROUP BY 子句中,也不包含在分组函数中, 所以是错误的。错误的 SQL 语句如下: Use student SELECT 姓名,性别 from student GROUP BY 性别 2.按多个字段分组 GROUP BY 子句可以基于指定多列的值将数据集合划分为多个分组。 示例: 在 student 表中,按照“性别”和“年龄”字段进行分组。SQL 语句如下: Use db_student SELECT 性别,年龄 from student GROUP BY 性别,年龄 46 SQL Server 2005 数据库系统开发案例精选 实现的过程如图 2.16 所示。 图 2.16 student 表按照性别、年龄列分组 在 student 表中,首先按照性别分组,然后再按照年龄分组。 3.与 HAVING 一起使用 分组之前的条件要用 where 关键字,而分组之后的条件要使用关键字 HAVING。 示例: 在 course 表中,先按照“课程类别”和“学分”分组,然后筛选出学分大于 6 的课程 信息。SQL 语句如下: Use db_student SELECT 课程类别,学分 from course GROUP BY 课程类别,学分 having 学分>6 实现的过程如图 2.17 所示。 图 2.17 course 表按照多列分组然后再与 having 一起使用 4.对统计结果排序 统计结果并不能保证结果集内记录按一定顺序排列,如果使用 ORDER BY 子句,就可 以使结果集中的结果按一定的顺序(升序、降序)排序。 示例: 在 course 表中,先按照“课程类别”和“学分”分组,然后再按照“学分”排序。SQL 语句如下: Use db_student SELECT 课程类别,学分 from course GROUP BY 课程类别,学分 ORDER BY学分 实现的过程如图 2.18 所示。 47 C H A P T E R 2 第 2 章 数据查询技术 图 2.18 course 表按照课程类别和学分分组后再按学分排序 例如在 grade 表中,按“学号”分组,并按课程的平均成绩升序排序。SQL 语句如下: Use db_student SELECT 学号,AVG(课程成绩) AS 平均成绩 from grade GROUP BY 学号 ORDER BY 平均成绩 2.2 筛选分组结果 SQL 提供一组聚合函数,它们能够对整个数据集合进行计算,将一组原始数据转换为 有用的的信息,以便用户使用。例如求成绩表中的总成绩、学生表中平均年龄等。 SQL 的聚合函数如表 2.5 所示。 表 2.5 聚合函数 聚 合 函 数 支持的数据类型 功 能 描 述 SUM() 数字 对指定列中的所有非空值求和 AVG() 数字 对指定列中的所有非空值求平均值 min() 数字、字符、日期 返回指定列中的最小数字、最小的字符串和最早的 日期时间 max() 数字、字符、日期 返回指定列中的最大数字、最大的字符串和最近的 日期时间 COUNT([distinct] *) 任意基于行的数据类型 统计结果集中全部记录行的数量。最多可达 2147483647 行 count_big([distinct] *) 任意基于行的数据类型 类似于 count()函数,但因其返回值使用了 bigint 数据类型,所以最多可以统计 2^63-1 行 下面用聚集函数分别举例。 例如在 grade 表中,求所有的课程成绩的总和,SQL 语句如下: Use db_student SELECT SUM(课程成绩) from grade 例如在 student 表中,求所有学生的平均年龄。SQL 语句如下: Use db_student SELECT AVG(年龄) from student 例如在 Student 表中,查询最早出生的学生。SQL 语句如下: Use db_student SELECT min(出生日期) from student 例如在 grade 表中,查询课程成绩最高的学生信息。SQL 语句如下: Use db_student SELECT max(课程成绩) from grade 48 SQL Server 2005 数据库系统开发案例精选 例如在 student 表中,求所有女生的人数。SQL 语句如下: Use db_student SELECT COUNT(年龄) from student COUNT(*)就可以求整个表所有的记录数。 例如求 student 表中所有的记录数,SQL 语句如下: Use db_student SELECT COUNT(*) from student 2.2.1 为聚合函数计算产生新列起个别名 利用 SELECT 语句查询统计值是没有列名的,可以用 AS 关键字为新产生的列起个别名。 示例: 在 course 表中,求最高学分、最低学分和平均学分。SQL 语句如下。 Use db_student SELECT max(学分)AS 最高学分,min(学分) AS 最低学分,AVG(学分) AS 平均学分 From course 实现的过程如图 2.19 所示。 图 2.19 在 course 表中求最高学分、最低学分和平均学分 2.2.2 与 GROUP BY 子句一起用 聚集函数与 GROUP BY 子句一起使用,在实际编程中会有很大的意义。例如按性别统 计年龄的平均值,按学期统计课程成绩的平均值等。 每个聚集函数都为每一组生成一个值,而不是对整个表生成一个值。 示例: 在 course 表中,按课程类别求平均学分。SQL 语句如下: Use db_student SELECT AVG(学分) AS 平均学分 From course GROUP BY 课程类别 实现的过程如图 2.20 所示。 图 2.20 在 course 表按课程类别求平均学分 49 C H A P T E R 2 第 2 章 数据查询技术 2.2.3 消除统计重复记录 指定 DISTINCT 关键字不但可以消除查询结果中的重复记录。而且在使用 SUM()、 AVG()和 COUNT()聚合函数时,可以从列中消除重复的值。DISTINCT 关键字和聚合 函数使用的格式是:聚合函数名称(DISTINCT 列名)。 例如在 grade 表中,统计多少学生参加考试。SQL 语句如下: Use db_student SELECT count(distinct 学号) from grade 例如在 grade 表中,统计学生参加考试共有多少门课程。SQL 语句如下: Use db_student SELECT count(distinct 课程代号) from grade 2.3 嵌 套 查 询 嵌套查询是指在一个外层查询中包含有另一个内层查询,即一个 SELECT-FROM- WHERE 查询语句块可以嵌套在另一个查询块的 WHERE 子句中。其中外层查询称为父查 询、主查询。内层查询也称为子查询、从查询。 2.3.1 简单的嵌套查询 嵌套内层子查询通常作为搜索条件的一部分呈现在 WHERE 或 HAVING 子句中。例如 把一个表达式的值和一个由子查询生成的一个值相比较。这个测试类似于简单比较测试。 子查询比较测试用到的运算符包括=、<>、<、>、<=、>=。子查询比较测试把一个表 达式的值和由子查询产生的值进行比较,这时子查询只能返回一个值,否则错误。最后返 回比较结果为 TRUE 的记录。 示例 在 course 表和 grade 表中,查询课程成绩大于 93 分的课程信息。SQL 语句如下: Use db_student SELECT * from course WHERE 课程代号 IN(SELECT 课程代号 from grade WHERE 课程成绩>93) 实现的过程如图 2.21 所示。 图 2.21 课程成绩大于 93 分的课程信息 50 SQL Server 2005 数据库系统开发案例精选 子查询“SELECT 课程代号 from grade WHERE 课程成绩>93”的查询结果是“k01、 k05”两个值。 子查询具体操作过程如下。 (1)从 grade 表中查询出课程成绩>93 的课程代号为“k01、k05”。 (2)从 course 表中查询出课程代号是“k01、k05”的课程信息。 2.3.2 IN 的嵌套查询 带 IN 的嵌套查询语法格式为 WHERE 查询表达式 IN(子查询)。 一些嵌套内层的子查询会产生一个值,也有一些子查询会返回一列值。即子查询不能 返回带几行和几列数据的表。原因在于子查询的结果必须适合外层查询的语句。当子查询 产生一系列值时,适合用带 IN 的嵌套查询。 把查询表达式单个数据和由子查询产生的一系列的数值相比较,如果数值匹配一系列 值中的一个,则返回 TRUE。 示例 在 course 和 grade 表中,查询有同学参加考试的课程的信息。SQL 语句如下: Use db_student SELECT * from course WHERE 课程代号 IN (SELECT 课程代号from grade) 实现的过程如图 2.22 所示。 图 2.22 有同学参加考试课程的信息 子查询“SELECT 课程代号 from grade”的结果如图 2.23 所示。 子查询生成 grade 表中课程代号列的数值,WHERE 子句检查主 查询记录中的值是否与子查询结果中的数值匹配。匹配返回 TRUE 值。由于主查询记录的“k06、k07”的课程代号值与子查询结果的 数值不匹配,所以查询结果不显示课程代号为“k06、k07”的记录 信息。 带 IN 的内层嵌套还可以是多个值的列表。带 IN 的内层嵌套还 可以是多个值的列表。 图 2.23 子查询的结果 51 C H A P T E R 2 第 2 章 数据查询技术 例如查询年龄是“19、21、24”的学生信息。SQL 语句如下: Use db_student SELECT * from student WHERE 年龄 IN(19 , 22 , 24) NOT IN 和 IN 查询过程类似。 NOT IN 的嵌套查询语法格式为 WHERE 查询表达式 NOT IN(子查询)。 子查询存在 NULL 值时,避免使用 NOT IN。因为当子查询的结果包括了 NULL 值的 列表时,把 NULL 值当成一个未知数据,不会存在查询值不在列表中的记录。 示例 在 course 和 grade 表中,查询除了学分大于 7 的课程成绩信息。SQL 语句如下: Use db_student SELECT * from grade WHERE 课程代号NOT IN(SELECT 课程代号from course WHERE 学分>7) 实现的过程如图 2.24 所示。 图 2.24 查询除了学分大于 7 的课程成绩信息 子查询存在 NULL 值时,避免使用 not in。因为当子查询的结果包括了 NULL 值的列 表时,把 NULL 值当成一个未知数据,不会存在查询值不在列表中的记录。所以当使用 not in 时,如果子查询存在 NULL 值,就用条件语句筛选掉 NULL 值。 示例 在 course 和 grade 表中,查询没有学生参加考试的课程的信息。SQL 语句如下: Use db_student SELECT * from course WHERE 课程代号NOT IN(SELECT 课程代号from grade WHERE 课程代号is NOT NULL) 实现的过程如图 2.25 所示。 如果子查询语句中不用“where 课程代号 is not null”子句,那么查询结果没有任何一 条记录。错误的 SQL 语句如下: Use db_student 52 SQL Server 2005 数据库系统开发案例精选 SELECT * from course WHERE 课程代号 NOT IN(SELECT 课程代号from grade) 图 2.25 没有学生参加考试的课程的信息 由于子查询的结果包括了 NULL 值,NULL 是未知数据,与任何数据都匹配,所以最 终的查询结果只有空值。 2.3.3 some 和 any 的嵌套查询 SQL 支持 3 种定量比较谓词:som、any 和 all。都是判断是否任何或全部返回值都满 足搜索要求的。其中 some 和 any 谓词是存在量的,只注重是否有返回值满足搜索要求。这 两种谓词含义相同,可以替换使用。some 的语法如下: <表达式> {= 、<> 、!= 、> 、>= 、< 、<= 、!> 、!> 、!< } some (子查询) 示例 在 course 和 grade 表中,查询学分小于平均学分的课程信息。SQL 语句如下。 Use db_student SELECT * from course WHERE 学分” 号表示否定。 例如在 student 表中,查询年龄不小于平均年龄的所有学生信息。SQL 语句如下: Use db_student SELECT * from student WHERE 年龄 <> any (SELECT avg(年龄) from student) 2.3.4 all 的嵌套查询 all 谓词的使用方法和 any 或者 some 谓词一样,也是把列值与子查询结果进行比较,但是 它不要求任意结果值的列值为真,而是要求所有列的查询结果都为真。否则就不返回行。 示例 在 course 和 grade 表中,查询课程成绩不大于 90 分的课程信息。SQL 语句如下: Use db_student SELECT * from course WHERE 课程代号 <> all (SELECT 课程代号 from grade WHERE 课程成绩>90) 实现的过程如图 2.28 所示。 54 SQL Server 2005 数据库系统开发案例精选 图 2.28 查询课程成绩不大于 90 分的课程信息 2.3.5 exists 嵌套查询 exists 谓词只注重子查询是否返回行。如果子查询返回一个或多个行,谓词评价为值, 否则为假。exists 搜索条件并不真正地使用子查询的结果。它仅仅测试子查询是否产生任何 结果。 示例 在 course 和 grade 表中,查询有同学参加考试的课程的信息。SQL 语句如下: Use db_student SELECT * from course WHERE exists (SELECT 课程代号 from grade WHERE course.课程代号=grade.课程代号 ) 实现的过程如图 2.29 所示。 图 2.29 有同学参加考试课程的信息 exists 谓词子查询中的 SELECT 子句中可使用任何列名,也可使用任意多个列,这种 谓词只注重是否返回行,而不注重行的内容。用户可以规定任何列名或者只使用一个星号。 例如上述例子的 SQL 语句和下面的 SQL 语句完全等价。 Use db_student SELECT * from student WHERE exists (SELECT * from grade WHERE student.学号=grade.学号 ) 55 C H A P T E R 2 第 2 章 数据查询技术 NOT EXISTS 的作用与 EXISTS 正相反。如果子查询没有返回行,则满足 NOT EXISTS 中的 WHERE 子句。 示例 在 course 和 grade 表中,查询没有学生参加考试的课程的信息。SQL 语句如下: Use db_student SELECT * from course WHERE not exists (SELECT * from grade WHERE course.课程代号=grade.课程代号) 实现的过程如图 2.30 所示。 图 2.30 查询没有学生参加考试的课程信息 2.4 连 接 查 询 前面已经讲解过使用两个或两个以上的表进行查询。本节讲解的连接查询也是多个表 进行查询。只不过连接查询是由一个笛卡尔乘积运算再加一个选取运算构成的查询。首先 用笛卡尔乘积完成对两个数据集合的乘运算,然后对生成的结果集合进行选取运算,确保 只把分别来自两个数据集合并且具有重叠部分的行合并在一起。连接的全部意义在于水平 方向上合并两个数据集合,并产生一个新的结果集合。 SQL 提供了内连接、外连接、交叉连接、自身连接等多种连接方式,它们之间的区别 在于从相互交叠的不同数据集合中选择用于连接的行时所采用的方法不同。 2.4.1 内连接 内连接也叫连接,是最早的一种连接。还可以被称为普通连接或自然连接。内连接是 从结果中删除其他被连接表中没有匹配行的所有行,所以内连接可能会丢失信息。 内连接的语法如下: SELECT fieldlist from table1 [INNER] JOIN table2 ON table1.column=table2.column 一个表中的行与另外一个表中的行匹配连接。表中的数据决定了如何对这些行进行组 56 SQL Server 2005 数据库系统开发案例精选 合。从每一个表中选取一行。 示例 grade 和 course 表实现内连接。SQL 语句如下: Use db_student SELECT * from course join grade on course.课程代号=grade.课程代号 实现的过程如图 2.31 所示。 图 2.31 grade 和 course 表实现内连接 2.4.2 外连接 外连接则扩充了内连接的功能,会把内连接中删除原表中的一些保留下来,由于保留 下来的行不同,把外连接分为左外连接、右外连接和全外连接 3 种连接。 1.左外连接 左外连接保留了第一个表的所有行,但只包含第二个表与第一表匹配的行。第二个表 相应的空行被放入 NULL 值。 左外连接的语法如下: SELECT fieldlist from table1 left JOIN table2 ON table1.column= table2.column 示例 course 表和 grade 表实现左外连接。第一个表 course 有不满足条件的记录出现在结果 表中。SQL 语句如下: Use db_student SELECT * from course left join grade on course.课程代号=grade.课程代号 实现的过程如图 2.32 所示。 57 C H A P T E R 2 第 2 章 数据查询技术 图 2.32 course 表和 grade 表实现左外连接 2.右外连接 右外连接保留了第二个表的所有行,但只包含第一个表与第二个表匹配的行。第一个 表相应空行被入 NULL 值。 右外连接的语法如下。 SELECT fieldlist from table1 right JOIN table2 ON table1.column=table2.column 示例 course 表和 grade 表实现右外连接。第二个表 grade 有不满足条件的记录出现在结果表 中。SQL 语句如下: Use db_student SELECT * from course right join grade on course.课程代号=grade.课程代号 实现的过程如图 2.33 所示。 图 2.33 course 表和 grade 表实现右外连接 58 SQL Server 2005 数据库系统开发案例精选 3.全外连接 全外连接会把两个表所有的行都显示在结果表中。并尽可能多地匹配数据和连接条件。 全外连接的语法如下: SELECT fieldlist from table1 full JOIN table2 ON table1.column=table2.column 示例 course 表和 grade 表实现全外连接。两个表都有不满足条件的记录出现在结果表中。 SQL 语句如下: Use db_student SELECT * from course full join grade on course.课程代号=grade.课程代号 实现的过程如图 2.34 所示。 图 2.34 course 表和 grade 表实现全连接 2.4.3 交叉连接 交叉连接是两个表的笛卡尔积的另一个名称。 笛卡尔积就是两个表的交叉乘积,即两个表的记录进行交叉组合,如图 2.35 所示。 表 1 表 2 表 1 和表 2 有笛卡尔乘积 记录 11 记录 22 记录 1 记录 2 记录 11 记录 1 记录 2 记录 11 记录 22 记录 1 记录 22 记录 2 图 2.35 两个表的笛卡尔积示意图 59 C H A P T E R 2 第 2 章 数据查询技术 交叉连接的语法如下: SELECT fieldlist from table1 cross JOIN table2 其中忽略 on 条件的方法来创建交叉连接。 示例 course 表和 grade 表实现交叉连接。SQL 语句如下: Use db_student SELECT * from grade cross join course 实现的过程如图 2.36 所示。 图 2.36 grade 表和 course 表实现交叉连接 最后结果表的行数=grade 表的行数*course 表的行数 2.4.4 自身连接 自连接是指同一个表自身与自身进行连接。所有的数据库每次只处理表中一个行。用 户可以访问一个行中的所有列,但只能在一个行中。如果同一时间需要一个表中两个不同 行的信息,则需要将表与自身连接。 为了更好地理解自连接,用户可以把一个表想像成两个独立的表。而在 from 子句中表 被列出了两次,为了区别,必须给每个表提供一个别名来区别这两个副本。 下面用如图 2.37 所示的表来实现自身连接。 图 2.37 student1 表 60 SQL Server 2005 数据库系统开发案例精选 示例 student1 表实现自身连接,结果表中的同一行会显示学生和他的学习组长信息。SQL 语句如下: Use db_student SELECT a.学号, a.姓名, a.年龄, b.姓名 as 学习组长, b.年龄 as 组长年龄 from student1 a ,student1 b WHERE a.组长学号=b.学号 实现的过程如图 2.38 所示。 图 2.38 student1 表实现自身连接 实现自连接的条件是第一个表(a)的组长学号列值等于第二个表(b)的学号列值。a 和 b 分别是同一个 student1 表的两个副本。 2.4.5 多表连接 1.在 WHERE 子句中连接几个表 在 from 子句连接写多个表的名称,然后在任意两个表的连接条件分别写在 WHERE 子 句后。 在 WHERE 子句中连接几个表的语法如下: SELECT fieldlist from table1 , table2 , table3 ⋯ WHERE table1.column=table2.column and table2.column=table3.column and ⋯ 例如把 studnet 、grade 和 course 3 个表在 WHERE 子句中连接。SQL 语句如下: Use db_student SELECT * from course,grade,student WHERE grade.课程代号=course.课程代号 and student.学号 =grade.学号 2.在 from 子句中连接几个表 from 子句连接多个表就是内连接的扩展。在 from 子句中连接几个表的语法如下: SELECT fieldlist 61 C H A P T E R 2 第 2 章 数据查询技术 from table1 join table2 join table3 ⋯ on table1.column=table2.column and table2.column=table3.column 例如把 student、grade 和 course 3 个表用 from 子句连接。在查询分析器中输入 SQL 语 句如下: Use db_student SELECT * from course join grade join student on student.学号 = grade.学号 on grade.课程代号=course. 课程代号  注意 当在from子句中连接多表时,要书写多个用来定义其中两个表的公共部分的on语句, on 语句必须遵循 FROM 后面所列表的顺序,即 from 后面先写的表相应的 on 语句要后写。 上面的例子,如果把两个 on 的顺序写反,错误的 SQL 语句如下。 Use db_student SELECT * from course join grade join student on grade.课程代号 = course.课程代号 on student.学号 =grade.学号 2.5 使 用 空 值 空值从技术上来说就是“未知的值”。但空值并不包括零、一个或者多个空格组成的字 符串,以及零长度的字符串。 在实际应用中,空值说明还没有向数据库中输入相应的数据,或者某个特定的记录行 不需要使用该列。在实际的操作中有下列几种情况可使得一列成为 NULL。 (1)其值未知。如课程表中不明确具体的课程内容。 (2)其值不存在。如在学生表中某个学生由于没有参加考试,所以该学生的考试成绩 为空值。 (3)列对表行不可用。 2.5.1 检测空值 因为空值代表未知的值,所以并不是所有的空值都相等。例如 student 表中有两个学生 的年龄未知,但无法证明这两个学生的年龄相等。这样就不能用“=”运算符来检测空值。 所以 SQL 引入了一个特殊的操作符 IS 来检测特殊值之间的等价性。 语法: WHERE Expression IS NULL 示例 查询 grade 表中没有“课程成绩”的学生。SQL 语句如下: Use db_student SELECT * from grade WHERE 课程成绩 IS NULL 实现的过程如图 2.39 所示。 62 SQL Server 2005 数据库系统开发案例精选 图 2.39 在 grade 表中查询没有课程成绩的学生 上述程序改为用“=”运算符来查询空值,查询结果如图 2.40 所示。 IS 运算符可以与 NOT 配合使用以检查非空的值。 示例 在 grade 表中,查询课程成绩不为空的记录。SQL 语句如下: Use db_student SELECT * from grade WHERE 课程成绩 is NOT NULL 实现的过程如图 2.41 所示。 图 2.40 用等号查询空值 图 2.41 在 grade 表中查询课程成绩不为空的记录 2.5.2 处理空值 在实际使用数据表的数据时,空值是很不受欢迎的。通常需要将空值转换为一个有效 的值,以便对数据的理解,或者防止表达式出错。 SQL 为处理空值,提供了几个专门用来处理空值的函数。ISNULL()函数可以将空值转 换为有效的值;而 NULLIF()函数可以根据指定的条件来生成空值。 1.使用 ISNULL()函数来处理空值 ISNULL()函数的是用指定的值替换空值。 语法: ISNULL (check_expression , replacement_value ) 参数说明: check_expression:将被检查是否为 NULL 的表达式。check_expression 可以是任 何类型的。 replacement_value:在 check_expression 为 NULL 时,将用 replacement_value 值 替换 NULL 值。replacement_value 必须与 check_expresssion 具有相同的类型。 返回类型:返回与 check_expression 相同的类型。  说明 如果 check_expression 不为 NULL,那么返回该表达式的值;否则返回 replacement_value。 63 C H A P T E R 2 第 2 章 数据查询技术 示例 在 grade 表中,课程成绩为 NULL 值的,用数值 0 来替代。SQL 语句如下: Use db_student SELECT 学号, 课程代号 , ISNULL(课程成绩,0) as 课程成绩 , 学期 from grade 实现的过程如图 2.42 所示。 图 2.42 在 grade 表中课程成绩为空的用 0 替代 如果课程成绩不为空,ISNULL()函数将会返回原值。只有课程成绩为 NULL 值时, ISNULL()函数将会对其进行处理,用数值 0 替代。 2.使用 NULLIF()函数来处理空值 NULLIF()函数功能:如果一个数据表中应该使用 NULL 值的地方使用了其他数据,那 么就可以使用 NULLIF()函数将这些不正确的值替换为空值。 语法: NULLIF ( expression , expression ) 参数说明: expression:常量、列名、函数、子查询或算术运算符、按位运算符以及字符串运 算符的任意组合。 返回类型:返回类型与第一个 expression 相同。如果两个表达式不相等,NULLIF 返回第一个 expression 的值。如果相等,NULLIF 返回第一个 expression 类型的空值。  说明 如果两个表达式相等且结果表达式为 NULL,NULLIF 等价于 CASE 的搜索函数。 示例 在 grade 表中,“学期”值是 1 的替换成 NULL 值。SQL 语句如下: use db_student SELECT nullif(学期,’1’) as 学期 from grade 实现的过程如图 2.43 所示。 图 2.43 在 grade 表中,学期是 1 的替换成 NULL 值 64 SQL Server 2005 数据库系统开发案例精选 2.6 交叉表查询 使用交叉表查询可以直观、清晰地反映数据之间的关 系。其中交叉表查询不但使数据容易管理,又能够生成一种 方便阅读的表格数据。 本节讲解了用多种方法实现交叉表查询。其中包括 SQL Server 2000 以前就使用的 CASE 交叉表查询,以及 SQL Server 2005 新增加的用 pivot 和 unpivot 的实现交叉 表查询。 本节查询使用的 sp 数据表如图 2.44 所示。 2.6.1 CASE 实现交叉表查询 利用 CASE 语句可以返回多个可能结果的表达式。CASE 具有简单 CASE 和 CASE 查 询两种函数格式。下面介绍简单 CASE 语句的语法,即将某个表达式与一组简单表达式进 行比较以确定结果。 其语法形式如下: CASE input_expression WHEN when_expression THEN result_expression [ ...n ] [ ELSE else_result_expression END 参数说明: input_expression:是使用简单 CASE 格式时所计算的表达式。Input_expression 是 任何有效的 SQL Server 表达式。 WHEN when_expression:使用简单 CASE 格式时 input_expression 所比较的简单表 达式。when_expression 是任意有效的 SQL Server 表达式。Input_expression 和每个 when_expression 的数据类型必须相同,或者是隐性转换。 n:占位符,表明可以使用多个 WHEN when_expression THEN result_expression 子 句或 WHEN boolean_expression THEN result_expression 子句。 THEN result_expression:当 input_expression=when_expression 取值为 TRUE,或 者 boolean_expression 取值为 TRUE 时返回的表达式。result expression 是任意有效 的 SQL Server 表达式。 ELSE else_result_expression:当比较运算取值不为 TRUE 时返回的表达式。如果 省略此参数并且比较运算取值不为 TRUE,CASE 将返回 NULL 值。else_result_ expression 是任意有效的 SQL Server 表达式。else_result_expression 和所有 result_expression 的数据类型必须相同,或者必须是隐性转换。 WHEN boolean_expression:使用 CASE 搜索格式时所计算的布尔表达式。 boolean_expression 是任意有效的布尔表达式。 图 2.44 sp 表 65 C H A P T E R 2 第 2 章 数据查询技术 示例 在 sp 表中,按照“商品名称”进行交叉表查询。结果表显示各商品各月的销售情况。 SQL 语句如下: Use db_student SELECT 月份,SUM(CASE 商品名称 WHEN ’李小葱专辑’ THEN 销售数量 ELSE NULL END)AS [李小葱专辑],SUM(CASE 商品名称 WHEN ’周木人专辑’ THEN 销售数量 ELSE NULL END)as [周木人 专 辑 ] ,SUM(CASE 商 品 名 称 WHEN ’ 国 产 E601’ THEN 销 售 数 量 ELSE NULL END)AS [E601],SUM(CASE 商品名称 WHEN ’920演唱会DVD’ THEN 销售数量 ELSE NULL END)AS [920演唱会 DVD] FROM sp group by 月份 实现的过程如图 2.45 所示。 图 2.45 sp 表按照商品名称交叉表查询 下面的例子对 sp 表用 case 按“月份”逐项聚合查询。 示例 在 sp 表中,按照“月份”进行交叉表查询。SQL 语句如下: Use db_student SELECT 商品名称,SUM(CASE 月份 WHEN ’9’ THEN 销售数量 ELSE NULL END)AS [9月 份],SUM(CASE 月份 WHEN ’10’ THEN 销售数量 ELSE NULL END) as [10月份] ,SUM(CASE 月份 WHEN ’11’ THEN 销售数量 ELSE NULL END)AS [11月份],SUM(CASE 月份 WHEN ’12’ THEN 销售数 量 ELSE NULL END)AS [12月份] FROM sp GROUP BY 商品名称 实现的过程如图 2.46 所示。 图 2.46 sp 表按照月份交叉表查询 2.6.2 SQL Server 2005 新增加的 PIVOT 和 UNPIVOT 实现交叉表查询 PIVOT 和 UNPIVOT 运算符是 SQL Server 2005 新增的功能。PIVOT 和 UNPIVOT 就 完全可以实现交叉表的查询,用 PIVOT 和 UNPIVOT 编写更简单更易于理解。 在查询的 FROM 子句中使用 PIVOT 和 UNPIVOT,可以对一个输入表值表达式执行某 66 SQL Server 2005 数据库系统开发案例精选 种操作,以获得另一种形式的表。PIVOT 运算符将输入表的行旋转为列,并能同时对行执 行聚合运算。而 UNPIVOT 运算符则执行与 PIVOT 运算符相反的操作,它将输入表的列旋 转为行。PIVOT 和 UNPIVOT 的语法如下: [ FROM { = [ ,...n ] = ::= { table_or_view_name [ [ AS ] table_alias ] | } ::=table_source PIVOT table_alias ::=( aggregate_function ( value_column ) FOR pivot_column IN ( :: = table_source UNPIVOT table_alias :: = ( value_column FOR pivot_column IN ( :: = column_name [ , ... ] table_source PIVOT 参数说明如表 2.6 所示。 表 2.6 PIVOT 和 UNPIVOT 运算符的参数说明 参 数 描 述 指定要在 T-SQL 语句中使用的表、视图或派生表源(有无别名均可)。虽然语句 中可用的表源个数的限值根据可用内存和查询中其他表达式的复杂性而有所不 同,但一个语句中最多可使用 256 个表源。单个查询可能不支持最多有 256 个 表源。可将 table 变量指定为表源。表源在 FROM 关键字后的顺序不影响返回 的结果集。如果 from 子句中出现重复的名称,SQL Server 2005 会返回错误消息 table_or_view_name 表或视图的名称。如果表或视图位于正在运行 SQL Server 实例的同一计算机上 的另一个数据库中,请按照 database.schema.object_name 形式使用完全限定名。 如果表或视图不在链接服务器上的本地服务器中,请按照 linked_server.catalog.schema.object 形式使用四个部分的名称。如果由四部分组成 的表或视图名称的服务器部分使用的是 OPENDATASOURCE 函数,则该名称也 可用于指定表源。有关该函数的详细信息,请参阅 OPENDATASOURCE (Transact-SQL) [AS] table_alias table_source 的别名,别名可带来使用上的方便,也可用于区分自联接或子查询 中的表或视图。别名往往是一个缩短了的表名,用于在联接中引用表的特定列。 如果联接中的多个表中存在相同的列名,SQL Server 要求使用表名、视图名或别 名来限定列名。如果定义了别名则不能使用表名。如果使用派生表、行集或表值 函数或者运算符子句(如 PIVOT 或 UNPIVOT),则在子句结尾处必需的 table_alias 是所有返回列(包括组合列)的关联表名 table_source PIVOT 指定基于 table_source 对 pivot_column 进行透视。table_source 是表或表表达 式。输出是包含 table_source 中 pivot_column 和 value_column 列之外的所有 列的表。table_source 中 pivot_column 和 value_column 列之外的列被称为透视 运算符的组合列。PIVOT 对输入表执行组合列的分组操作,并为每个组返回一 行。此外,input_table 的 pivot_column 中显示的 column_list 中指定的每个值, 输出中都对应一列 aggregate_function 系统或用户定义的聚合函数。聚合函数应该对空值固定不变。对空值固定不变的 聚合函数在求聚合值时不考虑组中的空值。不允许使用 COUNT(*) 系统聚合函 数 value_column PIVOT 运算符的值列。与 UNPIVOT 一起使用时,value_column 不能是输入 table_source 中的现有列的名称 FOR pivot_column PIVOT 运算符的透视列。pivot_column 必须属于可隐式或显式转换为 nvarchar() 的类型。此列不能为 image 或 rowversion。使用 UNPIVOT 时,pivot_column 是 从 table_source 中提取的输出列的名称。table_source 中不能有该名称的现有列 67 C H A P T E R 2 第 2 章 数据查询技术 续表 参 数 描 述 IN ( column_list ) 在 PIVOT 子句中,列出 pivot_column 中将成为输出表的列名的值。该列表不 能指定被透视的输入 table_source 中已存在的任何列名。在 UNPIVOT 子句中, 列出 table_source 中将被提取到单个 pivot_column 中的列 table_alias 输出表的别名。必须指定 pivot_table_alias UNPIVOT 指定输入表从 column_list 中的多个列缩减为名为 pivot_column 的单个列 例如图 2.47 所示的商品表就是一个典型的交叉 表,其中“数量”和“月份”可以继续添加。但是, 这种格式在进行数据表存储的时候并不容易管理,要 存储图 2.48 这样的表格数据,通常需要设计成如图 2.49 所示的结构。 现设计如图 2.49 所示 sp(商品)表,其中有商品 名称、销售数量和月份列,并存储相应的数据。 图 2.48 商品表结构 图 2.49 sp 表 SQL 语句如下: Use db_student SELECT 商品名称,a.[9] as [九月],a.[10] as [十月],a.[11] as [十一月],a.[12] as [十二月] from sp pivot(sum(销售数量) for 月份 in([9],[10],[11],[12] )) as a 在上面的语句中,sp 是输入表,月份是透视列(pivot_column),销售数量是值列 (value_column)。上面的语句将按下面的步骤获得输出结果集。 (1)pivot 首先按值列之外的列(商品名称和月份)对输入表 sp 进行分组汇总,类似 执行下面的 SQL 语句: Use db_student SELECT 商品名称, 月份 , sum(销售数量) as total from sp group by 商品名称, 月份 执行上述 SQL 语句将得到一个如图 2.50 所示的中间结果集。 (2)pivot 根据 for 月份 in 指定的值 9、10、11,12 首先在结果集中建立名为 9、10、 11、12 的列,然后从图 10.3 所示的中间结果中从月份列中取出相符合的值,分别放置到 9、 10、11、12 的列中。此时得到的结果集的别名为 a(见语句中 AS a 的指定)。结果集的内 容如图 2.51 所示。 图 2.47 商品表 68 SQL Server 2005 数据库系统开发案例精选 图 2.50 sp 表经过分组汇总后的结果 图 2.51 使用 for 月份 in([9] , [10] , [11] , [12] )后得到的结果集 (3)最后根据 SELECT 商品名称,a.[9] AS [九月],a.[10] AS [十月],a.[11] AS [十一 月],a.[12] AS [十二月] from 的指定,从别名是 aa 的结果集中检索数据,并分别将名为 9, 10,11,12 的列在最终结果集中重新命名为九月、十月、十一月、十二月。这里需要注意 的是 FROM 的含义,其表示从经 PIVOT 关系运算符得到的 a 结果集中检索数据,而不是 从 sp 表中检索数据。最终得到的结果集如图 2.52 所示。 unpivot 与 pivot 执行几乎完全相反的操作,将列转换为行。假设图 2.52 所示的结果集 存储在一个名为 temp 的表中,现在需要将列标识符“九月”、“十月”、“十一月”和“十二 月”转换到对应于相应商品名称的行值中。这意味着必须另外标识两个列,一个用于存储 月份,一个用于存储销售数量。为了便于理解,仍旧分别将这两个列命名为月份和销售数 量。SQL 语句如下: Use db_student SELECT * from temp unpivot(销售数量 for 月份 in([九月],[十月],[十一月],[十二月])) as b 运行上述 SQL 语句结果集,如图 2.53 所示。 图 2.52 由图 2.68 所示的 sp 表经行转列 图 2.53 图 2.65 的表使用 unpivot 得到的最终结果集 得到的结果集 但是,unpivot 并不完全是 pivot 的逆操作,由于在执行 pivot 过程中,数据已经被进行 了分组汇总,所以使用 unpivot 有时并不会重现原始表值表达式的结果。 1.用 pivot 举例 示例 在 sp 表中,按“商品名称”实现交叉表查询。结果表显示各商品在各月的销售情况。 SQL 语句如下: 69 C H A P T E R 2 第 2 章 数据查询技术 Use db_student SELECT * from sp pivot(sum(销售数量) for 商品名称 IN([李小葱专辑],[周木人专辑],[国产 E601],[920演唱会DVD] )) AS 统计 实现的过程如图 2.54 所示。 图 2.54 sp 表按商品名称交叉查询 有时还需要根据表的其他字段进行交叉查询。 示例 在 sp 表中,按“月份”交叉查询。逐月进行聚合计算。SQL 语句如下: Use db_student SELECT 商品名称,a.[9] AS [九月],a.[10] AS [十月],a.[11] AS [十一月],a.[12] AS [十二月] from sp pivot(sum(销售数量) for 月份 in([9],[10],[11],[12] )) AS a 实现的过程如图 2.55 所示。 图 2.55 sp 表按月份交叉查询 2.用 unpivot 举例 unpivot 是 pivot 的逆操作。假设图 2.71 所示的结果集存储在结果表 temp1 中,图 2.72 所示的结果集存储在结果表 temp2 中。 示例 用 unpivot 实现把 temp1 表中的列标识李小葱专辑、周木人专辑、国产 E601 和 920 演 唱会 DVD 转换到商品名称的行值中。相当于示例 pivot 的逆操作。SQL 语句如下: Use db_student SELECT * from temp1 unpivot(销售数量 for 商品名称 in([李小葱专辑],[周木人专辑],[国产 E601],[920演唱会DVD] )) AS a 实现的过程如图 2.56 所示。 示例 用 unpivot 实现把 temp2 中的列标识 9 月份、10 月份、11 月份和 12 月份列标识名称的 70 SQL Server 2005 数据库系统开发案例精选 行值中。相当于把示例的 pivot 实现逆操作。SQL 语句如下。 Use db_student SELECT * from temp2 unpivot(销售数量 for 月份 in([九月],[十月],[十一月],[十二月] )) as a 图 2.56 unpivot 对 temp1 表实现逆操作 实现的操作如图 2.57 所示。 图 2.57 unpivot 对 temp2 实现逆操作 2.6.3 动态交叉表 动态交叉表就是列表根据表中数据的情况动态创建列。前面的讲解都是静态交叉表, 所谓的静态交叉表,就是列数在语句中需要一一指定,不能根据数据动态调整列数。动态 查询就不能使用 SELECT 实现了,可以利用存储过程来解决。 首先检索列头信息,形成一个游标,然后遍历游标,将 11.3.2 查询语句里 CASE 判断 的内容用游标里的值替代,形成一条新的 SQL 查询,然后执行,返回结果即可。下面是本 实例的存储过程 corss 的程序代码: CREATE procedure Corss @strTabName as varchar(50) , @strCol as varchar(50) , @strGroup as varchar(50) ,--分组字段 @strNumber as varchar(50), --被统计的字段 @strSum as varchar(10) = ’Sum’ --运算方式 AS DECLARE @strSql as varchar(1000), @strTmpCol as varchar(100) EXECUTE (’DECLARE corss_cursor CURSOR FOR SELECT DISTINCT ’ + @strCol + ’ from ’ + @ strTabName + ’ for read only ’) --生成游标 begin SET nocount ON 71 C H A P T E R 2 第 2 章 数据查询技术 SET @strsql =’select ’ + @strGroup + ’, ’ + @strSum + ’(’ + @strNumber + ’) AS [’ + @strNumber + ’]’ --查 询的前半段 OPEN corss_cursor while (0=0) BEGIN FETCH NEXT FROM corss_cursor --遍历游标,将列头信息放入变量@strTmpCol INTO @strTmpCol if (@@fetch_status<>0) break SET @strsql = @strsql + ’, ’ + @strSum + ’(CASE ’ + @strCol + ’ WHEN ’’’ + @strTmpCol + ’’’ THEN ’ + @strNumber + ’ ELSE Null END) AS [’ + @strTmpCol + ’]’ --构造查询 END SET @strsql = @strsql + ’ from ’ + @strTabname + ’ group by ’ + @strGroup --查询结尾 EXECUTE(@strsql) --执行 IF @@error <>0 RETURN @@error --如果出错,返回错误代码 CLOSE corss_cursor DEALLOCATE corss_cursor RETURN 0 --释放游标,返回0表示成功 end 示例 调用存储过程“corss”,同时为@strTabName、@strCol、@strGroup 和@strNumber 4 个变量分别赋值。执行存储过程 corss,对 sp 表实现交叉表查询。SQL 语句如下。 use db_student exec corss sp,商品名称, 月份,销售数量 实现的过程如图 2.58 所示。 图 2.58 对 sp 表按商品名称实现交叉表的查询  注意 这是一个通用存储过程,使用时@strTabName、@strCol、@strGroup、@strNumber 几个变量设置一下就可以用到其他表上,其中结果集的第二列在这里加了个合计列。 2.7 SQL Server 2005 新增加的 CTE CTE(Common Table Expression)是 SQL Server 2005 在查询方面新增的一项重要功能。 下面主要讲解使用 CTE 如何处理复杂的查询,如何用 CTE 实现递归查询。 2.7.1 Common Table Expression 通过 CTE 能把复杂的查询定义成一个临时的结果集。使用 CTE 可以获得提高可读性 72 SQL Server 2005 数据库系统开发案例精选 和轻松维护复杂查询的优点。查询可以分为单独块、简单块、逻辑生成块。之后,这些简 单块可用于生成更复杂的临时 CTE,直到生成最终结果集。 CET 能够用于创建递归查询,可以启用按从标量嵌套 SELECT 语句派生的列进行分组, 或者按不确定性函数或有外部访问的函数进行分组。在同一语句中多次引用生成的表。 CTE 的语法如下: [ WITH [ ,...n ] ] ::= expression_name [ ( column_name [ ,...n ] ) ] AS ( CTE_query_definition ) 参数说明: expression_name:公用表表达式的名称。 expression_name 必须与在同一 WITH 子句中定义的任何其他公用表表达式的名称不同,但 expression_name 可以与基表或基视图的名称相同。在查询中对 expression_name 的任何引用都会使用公用表表达式,而不使用基对象。 column_name:在公用表达式中指定字段名。在一个 CTE 定义中不允许出现重复 的名称。指定的列名数必须与 CTE_query_definition 结果集中列数匹配。只有当 在查询定义中为所有结果列都提供了不同的名称时,列名称列表才是可选的。 CTE_query_definition:一个 SELECT 语句。除了 CTE 不能定义另一个 CTE 以 外,CTE_query_definition 的 SELECT 语句必须满足与创建视图时相同的要求。 如果定义了多个 CTE_query_definition,则这些查询定义必须用下列一个集合运算 符连接起来:UNION ALL、UNION、EXCEPT 或 INTERSECT。 定义并使用 CTE(此处是指非递归 CTE)时,需要遵循下列准则。 (1)在定义的 CTE 的 WITH 表达式后,必须紧跟着引用 CTE 的 SELECT、INSERT、 UPDATE 或 DELETE 语句。在 CREATE VIEW 语句中,CTE 可以用于定义视图的 SELECT 表达式的一部分。 (2)可以在非递归 CTE 中,定义多个 CTE 查询定义。这些定义必须使用 UNION ALL、 UNION、INTERSECT 或 EXCEPT 运算符来合并。 (3)CTE 可以引用自身,以及在同一 WITH 表达式中已定义的 CTE。不允许前向 引用。 (4)不允许在一个 CTE 中指定多个 WITH 表达式。例如,如果 CTE_query_definition 包 含一个子查询,则该子查询不能包含定义另一个 CTE 的嵌套的 WITH 表达式。 (5)在 CTE_query_definition 中,用户不可以使用下列子句: COMPUTE 或 COMPUTE BY; ORDER BY(除非指定了 TOP 子句); INTO; 带有查询提示的 OPTION 子句; FOR XML; FOR BROWSE。 (6)当批处理的表达式使用 CTE 时,在 CTE 之前的表达式后面必须紧跟分号。 (7)可以使用引用 CTE 的查询来定义游标。 (8)可以在 CTE 中引用远程服务器中的表。 73 C H A P T E R 2 第 2 章 数据查询技术 示例 在 course 和 grade 表中,求课程成绩大于 90 分课程的平均学分,求出平均学分中的最 高值。SQL 语句如下: Use db_student; with love(课程代号,平均学分)as ( SELECT a.课程代号,avg(b.学分) as 平均学分 from grade a join course b on a.课程代号=b.课程代号 WHERE a.课程成绩>90 group by a.课程代号 ) SELECT max(平均学分) as 最高分 from love 运行的结果如图 2.59 所示。 图 2.59 用 cte 完成查询 例如在 humanresources 数据库中的 employee 表中,显示向经理报告的雇员的平均数。 SQL 语句如下: WITH DirReps (Manager, DirectReports) AS ( SELECT ManagerID, COUNT(*) AS DirectReports from humanResources.Employee GROUP BY ManagerID ) SELECT AVG(DirectReports) AS [Average Number of Direct Reports] from DirReps WHERE DirectReports>= 2 ; GO  说明 HumanResources 数据库是 SQL Server 2005 自带的示例数据库。 2.7.2 使用递归 CTE 查询 CTE 一个很重要的功能就是能够引用其自身,即创建递归 CTE。递归 CTE 是一个重 复执行初始 CTE 以返回数据子集直到获取完整结果集。 递归 CTE 结构必须至少包含一个定位点成员和一个递归成员。用以下代码显示包含一 个定位点成员和一个递归成员的简单递归 CTE 的组件。SQL 语句如下: 74 SQL Server 2005 数据库系统开发案例精选 WITH cte_name( column_name [,...n] ) AS ( CTE_query_definition –- 定位点成员 UNION ALL CTE_query_definition –- 递归成员 ) -- 使用CTE SELECT * from cte_name 其中递归执行的过程如下。 (1)将 CTE 表达式拆分为定位点成员和递归成员。 (2)运行定位点成员,创建第一个调用或基准结果集(T0)。 (3)运行递归成员,将 Ti 作为输入,将 Ti+1 作为输出。 (4)重复步骤 3,直到返回空集。 (5)返回结果集。这是对 T0~Tn 执行 UNION ALL 的结果。 例如通过返回 Adventure Works Cycles 公司的雇员的分层列表(从最高级雇员开始), 来显示递归 CTE 结构的语义。执行 CTE 的语句将结果集限制到研发组中的雇员。SQL 语 句如下: Use AdventureWorks; GO WITH DirectReports (ManagerID, EmployeeID, Title, DeptID, Level) AS ( -- Anchor member definition SELECT e.ManagerID, e.EmployeeID, e.Title, edh.DepartmentID, 0 AS Level from humanResources.Employee AS e INNER JOIN HumanResources.EmployeeDepartmentHistory AS edh ON e.EmployeeID = edh.EmployeeID AND edh.EndDate IS NULL WHERE ManagerID IS NULL UNION ALL -- Recursive member definition SELECT e.ManagerID, e.EmployeeID, e.Title, edh.DepartmentID, Level + 1 from humanResources.Employee AS e INNER JOIN HumanResources.EmployeeDepartmentHistory AS edh ON e.EmployeeID = edh.EmployeeID AND edh.EndDate IS NULL INNER JOIN DirectReports AS d ON e.ManagerID = d.EmployeeID ) -- Statement that executes the CTE SELECT ManagerID, EmployeeID, Title, Level from DirectReports INNER JOIN HumanResources.Department AS dp ON DirectReports.DeptID = dp.DepartmentID WHERE dp.GroupName = N’Research and Development’ OR Level = 0; GO 例子执行的过程如下。 75 C H A P T E R 2 第 2 章 数据查询技术 (1)递归 CTE DirectReports 定义了一个定位点成员和一个递归成员。 (2)定位点成员返回基准结果集 T0。这就是公司中的最高级雇员,即不向经理报告 的雇员。 以下是定位点成员返回的结果集: ManagerID EmployeeID Title Level --------- ---------- --------------------------------------- ------ NULL 109 Chief Executive Officer 0 (3)递归成员返回了定位点成员结果集中雇员的直接下属。这是通过在 Employee 表 和 DirectReports CTE 之间执行连接操作获得的。正是此次对 CTE 自身的引用建立了递归 调用。利用 CTE DirectReports 中的雇员作为输入(Ti),联接(Employee.ManagerID= DirectReports.EmployeeID)返回经理为 (Ti) 的雇员作为输出(Ti+1)。这样,递归成员的 第一次迭代返回了以下结果集: ManagerID EmployeeID Title Level --------- ---------- --------------------------------------- ------ 109 12 Vice President of Engineering 1 (4)重复激活递归成员。递归成员的第二次迭代使用步骤 3 中的单行结果集(包含 EmployeeID 12)作为输入值,并返回以下结果集: ManagerID EmployeeID Title Level --------- ---------- --------------------------------------- ------ 12 3 Engineering Manager 2 递归成员的第三次迭代使用上面的单行结果集(包含 EmployeeID 3))作为输入值, 并返回以下结果集: ManagerID EmployeeID Title Level --------- ---------- --------------------------------------- ------ 3 4 Senior Tool Designer 3 3 9 Design Engineer 3 3 11 Design Engineer 3 3 158 Research and Development Manager 3 3 263 Senior Tool Designer 3 3 267 Senior Design Engineer 3 3 270 Design Engineer 3 递归成员的第四次迭代使用 EmployeeID 值 4、9、11、158、263、267 和 270 的上 一个行集作为输入值。 重复此过程,直到递归成员返回一个空结果集。 (5)正在运行的查询返回的最终结果集是定位点成员和递归成员生成的所有结果集的并集。 以下是示例返回的完整结果集: ManagerID EmployeeID Title Level --------- ---------- --------------------------------------- ------ NULL 109 Chief Executive Officer 0 109 12 Vice President of Engineering 1 12 3 Engineering Manager 2 3 4 Senior Tool Designer 3 3 9 Design Engineer 3 3 11 Design Engineer 3 3 158 Research and Development Manager 3 3 263 Senior Tool Designer 3 3 267 Senior Design Engineer 3 76 SQL Server 2005 数据库系统开发案例精选 3 270 Design Engineer 3 263 5 Tool Designer 4 263 265 Tool Designer 4 158 79 Research and Development Engineer 4 158 114 Research and Development Engineer 4 158 217 Research and Development Manager 4 (15 row(s) affected) 2.8 插 入 数 据 使用 INSERT 语句对现有的表插入数据,下面是 INSERT 语句的语法: INSERT [ TOP ( expression ) [ PERCENT ] ] [ INTO] { | rowset_function_limited [ WITH ( [ ...n ] ) ] } { [ ( column_list ) ] [ ] { VALUES ( { DEFAULT | NULL | expression } [ ,...n ] ) | derived_table | execute_statement } } | DEFAULT VALUES [; ] 参数说明: TOP ( expression ) [ PERCENT ]:该参数一般与 SELECT 语句的组合使用,用于指 定将要插入的行数或百分比。expression 可以是行数或行的百分比。 [INTO]:一个可选的关键字,可以将它用在 INSERT 和目标表之间。 :该语法主要是指是要插入数据的表或视图。 rowset_function_limited:OPENQUERY 或 OPENROWSET 函数。 WITH ( [... n ] ):指定目标表所允许的一个或多个表提示。需 要有 WITH 关键字和括号。 (column_list ):要在其中插入数据的一列或多列的列表。必须用括号将 column_list 括起来,并且用逗号进行分隔。 OUTPUT:将插入行作为插入操作的一部分返回。 VALUES:引入要插入的数据值的列表。对于 column_list(如果已指定)或表中 的每个列,都必须有一个数据值。必须用圆括号将值列表括起来。 DEFAULT:插入为列定义的默认值。 NULL:插入为列定义的默认值。 expression:一个常量、变量或表达式。表达式不能包含 SELECT 或 EXECUTE 语句。 derived_table:任何有效的 SELECT 语句,它返回将加载到表中的数据行。 77 C H A P T E R 2 第 2 章 数据查询技术 execute_statement:任何有效的 EXECUTE 语句,它使用 SELECT 或 READTEXT 语句返回数据。 DEFAULT VALUES:强制新行包含为每个列定义的默认值。 一般的情况下,用户可以用一个 INSERT 语句一次将一个或多个值插入表中,表的名 字用 table_name 参数指定,而 column_list 列名表参数是可选的,它决定了要被插入行的值 被填充到的列的次序。允许跳过那些不给填充的列,那些列或者用 NULL 值,或者用默认 值来填充。 用户在使用 INSERT 语句插入数据时,必须注意以下几点。 插入项的顺序和数据类型必须与表或视图中列的顺序和数据类型相对应。 如果表中某列定义为不允许 NULL,插入数据时,该列必须存在合法值。 如果某列是字符型工日期型数据类型,插入的数据应该加上单引号。 2.8.1 为指定的列插入值 用户为一个表插入数据时,由于某些列值未知,只能为部分列插入值,这时表名后的 column_list 列名表参数一定不能省略,指出为哪些列插入值,并且和 values 后面列值的顺 序相对应。 为指定的列插入值,其余的列插入 NULL 值的情况也很常见。例如插入一个学生的自 然情况,由于某学生的年龄未知,所以只能插入 NULL 值。 示例 在 Student 表中,插入一条记录,但年龄和出生日期未知。SQL 语句如下: Use db_student insert into student (学号, 姓名, 性别 ) values (’88888’, ’小美葱’, ’女’) 运行的结果如图 2.60 所示。 图 2.60 给 student 表的部分字段插入值 78 SQL Server 2005 数据库系统开发案例精选 然后查看 student 数据表,插入的数值如图 2.61 所示。从中可以看出,“年龄”和“出 生日期”列为 NULL 值。 图 2.61 插入数据后的表 student 如果一个表的某些列不允许为空,插入数据时必须为这些列赋值,否则会导致错误。 示例: 在 student 表中,只为“学号”和“性别”列插入数据。SQL 语句如下: Use db_student insert into student (姓名, 性别 ) values (’小美葱’, ’女’) 运行的结果如图 2.62 所示。 图 2.62 给 student 表的部分字段插入数据 从上例子看出,插入数据没有成功,原因是没有给“学号”列插入数据,而“姓名” 列不允许为 NULL 值。 给一个数据表的部分列插入数据,如果没有插入值但允许为 NULL 值,那么就用 NULL 值或者它的默认值填充。下面的例子将使用默认值填充。 79 C H A P T E R 2 第 2 章 数据查询技术 示例 对 student 数据表,为“学号”和“性别”列插入数据,同时查看插入数据后的 student 学生表。SQL 语句如下: Use db_student insert into student (学号, 性别 ) values (’1111’, ’女’) SELECT * from student 运行结果如图 2.63 所示。 图 2.63 给 student 表的部分列添加数据 2.8.2 为所有列插入值 用户有时会给数据表的所有列都插入值,即 values 后要包含所有列的值。而表名后的 column_list 列名表参数有两种情况,一种是依然列出所有的列;另一种是省略列名表。尽 管第二种情况输入起来更快,但第一种更易理解和维护。 示例 在 student 数据库中,为 course 课程表插入一条完整记录。插入完数据后并查看。SQL 语句如下: Use db_student insert into course (课程代号, 课程名称, 课程类别, 课程内容, 学分 ) values 80 SQL Server 2005 数据库系统开发案例精选 (’k08’, ’不插电演唱会’, ’娱乐类’, ’李葱葱北京演唱会’, 10 ) SELECT * from course 运行的结果如图 2.64 所示。 图 2.64 为 course 表的所有列插入数据 上个例子插入数据时,把所有列的列名都列出来了,也完全可以省略,但必须保证 values 后的各数据项和数据表中定义的顺序一致。省略所有列名的 SQL 语句如下。 Use db_student insert into course values (’k08’, ’不插电演唱会’, ’娱乐类’, ’李葱葱北京演唱会’, 10 ) SELECT * from course 2.8.3 批量添加数据 INSERT 语句可以一次给数据表添加多条记录,这也是 INSERT 语句的第二种用法。 VALUES 子句指定的是一个 SELECT 子查询的结果集。使用 INSERT 语句批量添加数据的 语法如下: Insert Into table_name Select {* | fieldname1 [,fieldname2…]]} From table_source [Where search_condition ] 参数说明: Insert Into:是关键字。 table_name:是存储数据的数据表,该数据表必须已经存在。 Select:表示其后是一个查询语句。 示例 对 course 表,把自身的数据批量追加,并查看 course 表的信息。SQL 语句如下: Use db_student insert into course SELECT * 81 C H A P T E R 2 第 2 章 数据查询技术 from course SELECT * from course 运行的结果如图 2.65 所示。 图 2.65 给 course 表添加批量数据 上个例子在表名后没有指定列名表,即给表的所有列插入了值,下面指定列名表,为 表的部分列插入值。 示例 给 grade 课程表的“学号”和“课程代号”列添加批量数据,然后再查看 grade 表的内 容。SQL 语句如下: Use db_student insert into grade(学号,课程代号) SELECT 课程名称,课程内容 from course SELECT * from grade 运行的结果如图 2.66 所示。 图 2.66 给 grade 表指定列添加批量数据 VALUES 子句后指定的可以是带条件的 SELECT 子查询。 82 SQL Server 2005 数据库系统开发案例精选 示例 给 grade 课程表中的“学号”和“课程代号”列添加批量数据,数据是另一表进行筛 选后的数据,然后再查看 grade 表的内容。SQL 语句如下: Use db_student insert into grade(学号,课程代号) SELECT 课程类别,课程代号 from course where 课程类别=’歌曲类’ SELECT * from grade 运行的结果如图 2.67 所示。 (1)查询不能包含一个 ORDER BY 子句。 无论如何,排序查询结果是无用的,因为它们正 被插入一个像所有表一样的无序的表中。 (2)查询结果的列必须与 INSERT 语句中 列名表中的列一样多,并且对应的数据类型是 兼容的。 (3)查询不能是几个不同的 SELECT 语句的 UNION。只能指定一条 SELECT 语句。 2.9 修 改 数 据 UPDATE 语句用于修改现有数据库信息。可以修改一个列或者几个列中的值。但一次 只能修改一个表。 要被更新的表的名字在 table_or_view_name 子句中指定。在 SET 子句中,指定要更新 列的名字和要指派给它的新值。可以指定用逗号分隔的多个对应的列/值对。分配的值可以 与在 INSERT 语句中的 VALUES 子句中指定的一样,具有多种形式(可以是常量、表达式、 NULL、默认值等)。 WHERE 子句设置行限制,如果说在 SET 子句中指定了要更新的列,那么,现在必须 定义一个条件,基于这个条件,一些行将被更新。 UPDATE 语句的语法如下: UPDATE { table_name WITH ( < table_hint_limited > [ ...n ] ) | view_name | rowset_function_limited } SET { column_name = { expression | DEFAULT | NULL } | @variable = expression | @variable = column = expression } [ ,...n ] { { [ FROM { < table_source > } [ ,...n ] ] [ WHERE < search_condition > ] } | [ WHERE CURRENT OF 图 2.67 给 grade 表添加经过筛选的批量数据 83 C H A P T E R 2 第 2 章 数据查询技术 { { [ GLOBAL ] cursor_name } | cursor_variable_name } ] } [ OPTION ( < query_hint > [ ,...n ] ) ] 参数说明: table_name:需要更新的表的名称。如果该表不在当前服务器或数据库中,或不 为当前用户所有,这个名称可用链接服务器、数据库和所有者名称来限定。 WITH ( < table_hint_limited > [ ...n ] ):指定目标表所允许的一个或多个表提示。 需 要 有 WITH 关键字和圆括号。不允许有 READPAST 、 NOLOCK 和 READUNCOMMITTED。 view_name:要更新的视图的名称。通过 view_name 来引用的视图必须是可更新 的。用 UPDATE 语句进行的修改,至多只能影响 FROM 子句所引用的基表中的 一个。 rowset_function_limited:OPENQUERY 或 OPENROWSET 函数,视提供程序功 能而定。 SET:指定要更新的列或变量名称的列表。 column_name:含有要更改数据的列的名称。column_name 必须驻留于 UPDATE 子句中所指定的表或视图中。标识列不能进行更新。如果指定了限定的列名称, 限定符必须同 UPDATE 子句中的表或视图的名称相匹配。FROM 子句中指定的 表的别名不能作为 SET column_name 子句中的限定符使用。 expression:变量、字面值、表达式或加上括号的返回单个值的 subSELECT 语句。 expression 返回的值将替换 column_name 或 @variable 中的现有值。 DEFAULT:指定使用对列定义的默认值替换列中的现有值。如果该列没有默认值 并且定义为允许空值,这也可用来将列更改为 NULL。 @variable:已声明的变量,该变量将设置为 expression 所返回的值。SET @variable = column = expression 将变量设置为与列相同的值。这与 SET @variable = column, column = expression 不同,后者将变量设置为列更新前的值。 FROM < table_source >:指定用表来为更新操作提供准则。 table_name [[AS] table_alias ]:为更新操作提供准则的表的名称。如果所更新表与 FROM 子句中的表相同,并且在 FROM 子句中对该表只有一个引用,则指定或 不指定 table_alias 均可。如果所更新表在 FROM 子句中出现了不只一次,则对 该表的一个(且仅仅一个)引用不能指定表的别名。FROM 子句中对该表的所有 其他引用都必须包含表的别名。 view_name [ [ AS ] table_alias ]:为更新操作提供准则的视图的名称。带 INSTEAD OF UPDATE 触发器的视图不能是含有 FROM 子句的 UPDATE 的目标。 WITH ( < table_hint > [ ...n ] ):为源表指定一个或多个表提示。 rowset_function [ [AS] table_alias ]:任意行集函数的名称和可选别名。 derived_table:是从数据库中检索行的子查询。derived_table 用作对外部查询的输 入。 column_alias:替换结果集内列名的可选别名。在选择列表中放入每个列的一个别 名,并将整个列别名列表用圆括号括起来。 :由两个或更多表的积组成的结果集,对于多个 CROSS 连接,请 84 SQL Server 2005 数据库系统开发案例精选 使用圆括号来更改联接的自然顺序。 :指定联接操作的类型。 INNER:指定返回所有相匹配的行对。废弃两个表中不匹配的行。如果未指定联 接类型,则这是默认设置。 LEFT [OUTER]:指定除所有由内联接返回的行外,所有来自左表的不符合指定 条件的行也包含在结果集内。来自左表的输出列设置为 NULL。 RIGHT [OUTER]:指定除所有由内联接返回的行外,所有来自右表的不符合指定 条件的行也包含在结果集内。来自右表的输出列设置为 NULL。 FULL [OUTER]:如果来自左表或右表的某行与选择准则不匹配,则指定在结果 集内包含该行,并且将与另一个表对应的输出列设置为 NULL。除此之外,结果 集中还包含通常由内联接返回的所有行。 :指定联接提示或执行算法。如果指定了 ,也必须明确指 定 INNER、LEFT、RIGHT 或 FULL。 JOIN:表示联接所指定的表或视图。 ON :指定联接所基于的条件。尽管经常使用列和比较运算符, 但此条件可指定任何谓词,例如: FROM Suppliers JOIN Products ON (Suppliers.SupplierID = Products.SupplierID) 当条件指定列时,列不一定具有相同的名称或数据类型;但是,如果数据类型不一致, 则这些列要么必须相互兼容,要么是 Microsoft® SQL Server 能够隐性转换的类型。如果 数据类型不能隐式转换,则条件必须使用 CAST 函数显式转换数据类型。 CROSS JOIN:指定两个表的矢量积。返回同样的行,就像要连接的表只列于 FROM 子句中,并且未指定 WHERE 子句。 WHERE:指定条件来限定所更新的行。根据所使用的 WHERE 子句的形式,有 两种更新形式:搜索更新指定搜索条件来限定要删除的行。定位更新使用 CURRENT OF 子句指定游标。更新操作发生在游标的当前位置。 :为要更新行指定需满足的条件。搜索条件也可以是联接所基 于的条件。对搜索条件中可以包含的谓词数量没有限制。 CURRENT OF:指定更新在指定游标的当前位置进行。 GLOBAL:指定 cursor_name 指的是全局游标。 cursor_name:要从中进行提取的开放游标的名称。如果同时存在名为 cursor_name 的全局游标和局部游标,则在指定了 GLOBAL 时,cursor_name 指的是全局游 标。如果未指定 GLOBAL,则 cursor_name 指局部游标。游标必须允许更新。 cursor_variable_name:游标变量的名称。cursor_variable_name 必须引用允许更新 的游标。 OPTION ( < query_hint > [ ,...n ] ):指定优化程序提示用于自定义 SQL Server 的 语句处理。 2.9.1 修改个别行中的个别列 使用 UPDATE 语句修改数据表中某一行中的某一列数据时可以用 WHERE 子句限定某 一行。 85 C H A P T E R 2 第 2 章 数据查询技术 例如把 student 学生表中姓名是“李葱葱”的同学年龄加 1。SQL 语句如下: Use db_student UPDATE student set 年龄=年龄+1 WHERE 姓名=’李小葱’ 2.9.2 修改多个列 有时需要用一个 UPDATE 语句修改多个列的值。这种情况用 SET 子句后的多个赋值 列表指定,每个赋值标识要被更新的目标列并规定如何计算目标列的新值。每个目标列在 列表中仅应出现一次,对于同一个目标列,不能有两次赋值。 例如修改 grade 数据表的“课程成绩”和“学期”列。SQL 语句如下: Use db_student UPDATE grade set 课程成绩=课程成绩+1 ,学期=学期+1 WHERE 学号=’b003’ SET 子句计算列的表达式可以是常量。 示例 修改 grade 数据表的“学期”列值都是 1,“课程成绩”的值都是 98。SQL 语句如下: Use db_student UPDATE grade set 学期=1,课程成绩=99 WHERE 学号=’b003’ SELECT * from grade 运行的结果如图 2.68 所示。 图 2.68 修改 grade 表多个列的值 2.9.3 修改所有行中的某一列 UPDATE 语句中的 WHERE 子句是可选的。如果省略了 WHERE 子句,那么目标表的 所有列都被更新了。修改所有行中的某一列的值。 示例 把 grade 表中所有同学的课程成绩都加 3,并查看了修改数据后的 grade 表。 SQL 语 句如下: Use db_student UPDATE grade set 课程成绩=课程成绩+3 SELECT * from grade 运行的结果如图 2.69 所示。 86 SQL Server 2005 数据库系统开发案例精选 图 2.69 修改 grade 中所有课程成绩的值 同时也可以修改多列中所有行的数据。例如在 grade 表中,修改所有学生的“课程成 绩”和“学期”列。SQL 语句如下: Use db_student UPDATE grade set 课程成绩=课程成绩+3,学期=1 SELECT * from grade 2.10 删 除 数 据 数据表使用一段时间之后,会有大量冗余数据,给计算机数据的存储造成很大的麻烦。 例如一个员工辞职后,公司就不用再发工资单给这位员工了。 用 DELETE 语句删除数据。DELETE 只能一次从一个表中删除行。可以使用一个单一 的 DELETE 语句删除一行或多行;当表中没有行满足 WHERE 子句中指定的条件时,就没 有行会被删除,也没有错误产生。 DELETE 语句的语法如下: DELETE [ FROM ] { table_name WITH ( < table_hint_limited > [ ...n ] ) | view_name | rowset_function_limited } [ FROM { < table_source > } [ ,...n ] ] [ WHERE { < search_condition > | { [ CURRENT OF { { [ GLOBAL ] cursor_name } | cursor_variable_name } ] } } ] [ OPTION ( < query_hint > [ ,...n ] ) ] 参数说明: FROM:是可选的关键字,可用在 DELETE 关键字与目标 table_name、view_name 或 rowset_function_limited 之间。 table_name:是要从其中删除行的表的名称。在其作用域内的 table 变量、或是将 OPENDATASOURCE 函数作为服务器名称的由四部分组成的表名(或视图名称) 87 C H A P T E R 2 第 2 章 数据查询技术 还可以在 DELETE 语句中作为表源使用。 WITH ( [...n]):指定目标表所允许的一个或多个表提示。需要 有 WITH 关键字和圆括号。不允许有 READPAST 、 NOLOCK 和 READUNCOMMITTED。 view_name:是视图名称。在视图的 FROM 子句中,view_name 引用的视图必须 可更新且正确引用一个基表。 rowset_function_limited:OPENQUERY 或 OPENROWSET 函数,视提供程序功 能而定。 FROM < table_source >: 指 定 附 加 的 FROM 子 句 。 这 个 对 DELETE 的 Transact-SQL 扩展使您得以从 指定数据,并从第一个 FROM 子 句内的表中删除相应的行。这个扩展指定联接,可在 WHERE 子句中取代子查询 来标识要删除的行。 table_name [[AS] table_alias ]:是为删除操作提供标准值的表名。 view_name [ [ AS ] table_alias ]:是为删除操作提供标准值的视图名称。带 INSTEAD OF UPDATE 触发器的视图不能是含有 FROM 子句的 UPDATE 的 目标。 WITH (:指定一个或更多表提示。 rowset_function [ [AS] table_alias ]:是行集函数名和可选别名。 derived_table [AS] table_alias:是从数据库中检索行的子查询。derived_table 是用 作对外部查询的输入。 column_alias:替换结果集内列名的可选别名。在选择列表中放入每个列的一个别 名,并将整个列别名列表用圆括号括起来。 :由两个或更多表的积组成的结果集,对于多个 CROSS 联接,请 使用圆括号来更改联接的自然顺序。 :指定连接操作的类型。 INNER:指定返回每对匹配的行。废弃两个表中不匹配的行。如果未指定连接类 型,则这是默认设置。 LEFT [OUTER]:指定在结果集内包含左表中所有不满足指定条件的行,并将右 表中的输出列设置为 NULL 以作为对内连接所返回的所有行的补充。 RIGHT [OUTER]:指定在结果集内包含右表中所有不满足指定条件的行,并将左 表中的输出列设置为 NULL 以作为对内连接所返回的所有行的补充。 FULL [OUTER]:如果来自左表或右表的某行与选择准则不匹配,则指定在结果 集内包含该行,并且将与另一个表对应的输出列设置为 NULL。除此之外,结果 集中还包含通常由内联接返回的所有行。 JOIN:是表示在删除操作中使用 SQL-92 式联接的关键字。 ON :指定联接所基于的条件。尽管经常使用列和比较运算符, 但此条件可指定任何谓词,当条件指定列时,列不必具有相同的名称或数据类型; 但是,如果数据类型不一致,则这些列必须相互兼容或是 Microsoft® SQL Server 能够隐性转换的类型。如果数据类型不能隐性转换,则条件必须使用 CAST 函数 显式转换数据类型。 CROSS JOIN:指定两个表的矢量积。这将返回相同的行,就好像在旧式的非 88 SQL Server 2005 数据库系统开发案例精选 SQL-92 式联接中并没有指定 WHERE 子句。 WHERE:指定用于限制删除行数的条件。如果没有提供 WHERE 子句,则 DELETE 删除表中的所有行。基于 WHERE 子句中所指定的条件,有两种形式的 删除操作。搜索删除指定搜索条件限定删除的行。定位删除使用 CURRENT OF 子句指定游标。删除操作在游标的当前位置发生。这比使用 WHERE search_ condition 子句限定删除的行的搜索 DELETE 精确。如果搜索条件不惟一标识单行,则搜索 DELETE 删除多行。 :指定删除行的限定条件。对搜索条件中可以包含的谓词数量 没有限制。 CURRENT OF:指定在指定游标的当前位置完成 DELETE。 GLOBAL:指定 cursor_name 指的是全局游标。 cursor_name:是从其中进行提取的打开游标的名称。当全局和局部游标都以 cursor_name 作为它们的名称存在时,如果指定 GLOBAL,则 cursor_name 引用 全局游标,如果未指定 GLOBAL,则 cursor_name 引用局部游标。游标必须允许 更新。 cursor_variable_name:是游标变量的名称。游标变量必须引用允许更新的游标。 OPTION ( [,...n] ):是表示使用优化程序提示自定义 SQL Server 的语 句处理的关键字。 2.10.1 用 WHERE 子句删除部分数据 DELETE 语句用于从一个表中删除选定的数据记录。其中 FROM 子句指定了包含记录 的目标表,WHERE 子句指定了表中的哪些记录要被删除。 示例 在 student 数据库中,删除 studet 表中所有女生的记录。SQL 语句如下: Use db_student delete from student WHERE 性别= ’女’ SELECT * from student 运行的结果如图 2.70 所示。 图 2.70 用 where 子句删除 student 表中部分数据 在这个示例中,WHERE 子句选择了 student 表中满足条件的记录,SQL 把 WHERE 子 句应用到 student 表中的每一条记录上,删除其搜索条件为 TRUE 的记录,保留其搜索条件 为 FALSE 或 NULL 的记录。 例如在 grade 成绩表中,删除课程成绩大于 95 并且学期是 1 的记录。SQL 语句如下: 89 C H A P T E R 2 第 2 章 数据查询技术 Use student delete from grade WHERE 课程成绩>95 AND 学期=1 2.10.2 删除表中所有数据 DELETE 语句中的 WHERE 子句是可选的,如果在 DELETE 语句中省略了 WHERE 子 句,目标表中的所有记录都被删除。 例如在 student 表中,删除表中所有记录。SQL 语句如下: Use db_student delete from student student 表中的所有记录都被删除。但 student 表的定义和它的字段存储在数据库中。用 INSERT 语句可以为这个表添加新的记录,要想彻底删除这个表的定义,必须使用 DROP TABLE 语句。 例如彻底删除 student 表的所有记录和这个表的定义,必须使用 DROP TABLE 语句。 Use db_student drop student 2.10.3 删除表中多余的重复行数据 在关系数据库中,允许创建包含重复行的表。这表示在每一列中可以有相同数值的 两个或更多的行。为了避免在表中出现重复行,通常给表添加一个主键,就不允许出现 重复行。 SQL Server 不允许直接用手动方式删除重复数据,下面介绍如何通过代码删除表中的 重复数据。 示例 删除如图 2.71 所示的 student1 表中多余的重复行的数据,即保留有重复行数据其中的 一行。最后查看表 student1 的信息。 图 2.71 student1 表 SQL 语句如下: Use db_student --打开数据库 SELECT distinct * into #temp from student1 --把student1表中没有重复行的数据存储到临时表 temp delete from student1 --删除数据表student1 insert into student1 SELECT * from #temp --把临时表的数据插入到数据表student1中 SELECT * from student1 运行的结果如图 2.72 所示。 90 SQL Server 2005 数据库系统开发案例精选 图 2.72 对 student1 表删除重复行数 3 天下鲜美食网 开发导读 实例说明  实例名称:天下鲜美食网。  实例路径:光盘\mingrisoft\ 天下鲜美食网。  实例运行文件:光盘\mingrisoft\ 天下鲜美食网\index.asp。  用户名:mr。  密码:mrsoft。  用户在使用本实例前,请仔细 阅读光盘中的光盘使用说明、 程序界面修改配置说明书、安 装说明书、使用说明书,这样 可以使您更好地学习和使用本 实例。 在计算机中使用本章实例的源程序时,用户需安 装 DreamWeaver MX 或其他网页开发工具。 本实例数据库为 SQL Server 2005,使用本实例 前,请安装 SQL Server 2005。安装时,验证模式为 混合模式,用户名为 sa,密码为空。 本实例提供了 5 套程序背景和素材,有些格式需 要使用特殊软件处理。 JPG/GIF 文件,如要修改其文件,需要安装 Photoshop 图像编辑软件。 92 SQL Server 2005 数据库系统开发案例精选 本案例由多个程序界面组成,下面仅列出几个典型界面,其他界面请参见光盘中的源 程序。 首页 后台登录页面 名店介绍页面 名店信息添加页面 管理用户页面 美食教程页面 美食教程管理页面 美食留言管理页面 93 C H A P T E R 3 第 3 章 天下鲜美食网 3.1 概 述 随着经济的发展,人们生活水平不断提高。餐饮业面临着日趋激烈的竞争环境和不断 攀升的顾客期望,迫使餐饮业内人士不断寻求扩大市场销售、改进服务质量、降低管理成 本和提升顾客满意度来增强酒店的核心竞争力。其中最有效的手段之一就是应用先进的信 息化技术,为餐饮业信息化发展注入新的生机和活力。天下鲜美食网的开发既增强了酒店 的知名度,同时也方便了消费者查询相关信息。 3.2 系 统 分 析 3.2.1 需求分析 通过调查,要求系统具有以下功能。  由于操作人员的计算机水平有限,要求有良好的人机界面。  管理名店信息的添加、修改、删除。  提供用户留言功能,可以向网站发表个人留言信息。  特色美食查询功能。  对留言信息进行管理。  修改用户权限。  对用户信息进行管理。  提供推荐名店功能。 3.2.2 可行性分析 俗话说得好,民以食为天。随着人们生活水平的不断提高,很多人对饮食有着更高层 的追求。同时,现代生活节奏越来越快,人们忙于工作,几乎没有时间用在选择菜色上, 但是,对于健康,人们也是越来越重视,希望不浪费时间的同时又能吃出健康。网上订购 恰好解决了这一问题。打开计算机,网上订购,既节约时间,又吃出健康美味。 在天下鲜美食网中,提供了大量的名家名店的美食信息,缩短了美食家寻找美食的途 径,又为商家提供了一个展示特色美食的平台。 3.3 总 体 设 计 3.3.1 项目规划 天下鲜美食网是一个典型的数据库开发应用程序,由客户前台浏览和企业后台管理两 大部分组成。  前台功能模块 前台功能模块主要包括名店介绍、特色美食展示、名店加盟、美食教程、美食留言、 留言板登录、网站公告栏、友情链接、后台登录入口。  后台功能模块 后台管理模块主要包括管理用户模块、管理公告栏模块、管理名店模块、管理美食模 94 SQL Server 2005 数据库系统开发案例精选 块、管理教程模块、管理留言模块、管理加盟模块、退出后台模块。 3.3.2 系统功能结构图 根据天下鲜美食网的特点,可分为前台和后台两个部分设计。前台主要用于用户浏览、 查找美食信息、名店信息、用户留言等;后台主要用于管理员对美食信息、名店信息及其 他信息进行管理。天下鲜美食网前台系统功能结构如图 3.1 所示。 图 3.1 天下鲜美食网前台系统功能结构 天下鲜美食网后台系统功能结构如图 3.2 所示。 图 3.2 天下鲜美食网后台系统功能结构 3.4 系 统 设 计 3.4.1 设计目标 本系统是针对中小型酒店的管理要求进行设计的,主要实现如下目标。  系统采用人机对话方式,界面清晰、信息查询灵活、方便、快捷、准确、数据存 储安全可靠。  快速查询特色美食信息,并对特色美食查询结果进行详细信息展示。  实现了名店介绍、名店详细信息展示功能。 95 C H A P T E R 3 第 3 章 天下鲜美食网  进行名店加盟,对名店信息进行管理。  发布留言信息,并对留言信息进行管理。  对系统用户进行管理。  为了加强数据保密性,为每个用户设置权限级别。  系统运行稳定、安全可靠。 3.4.2 开发及运行环境 硬件平台:  CPU:Pentium Ⅲ及其兼容处理器,建议主频为 600MHz 或更高。  内存:512MB 以上。 软件平台:  操作系统:Windows 2000 Server SP4、Windows 2000 Advanced Server SP4、Windows 2000 Data Center Server SP4、Windows Server 2003 SP1、Windows 2003 企业版 SP1、Windows 2003 数据中心版 SP1。  数据库:SQL Server 2005。  浏览器:IE5.0,推荐使用 IE 6.0。  Web 服务器:IIS 5.0。  分辨率:最佳效果 1024×768 像素。 3.4.3 Windows XP 系统中的 IIS 配置 1.安装 IIS 插入 Windows XP 光盘,单击“安装可选的 Windows 组件”,选中“Internet 信息服务 (IIS)”选项后,单击【下一步】按钮完成安装。 2.配置 IIS 可以通过两种方法实现 IIS 的配置:配置 Web 站点和创建虚拟目录。 1.配置 Web 站点 具体方法如下。 (1)单击“开始”按钮,选择“控制面板”命令,打开“控制面板”窗口,在该窗口 中双击“管理工具”图标,将进入到“管理工具”窗口,在该窗口中双击“Internet 信息服 务”图标,运行“Internet 信息服务”。 (2)在“Internet 信息服务”窗口中,展开“网站”节点,如图 3.3 所示。 图 3.3 “Internet 信息服务”窗口 96 SQL Server 2005 数据库系统开发案例精选 (3)在图 3.3 中的“默认网站”节点上单击鼠标右键,在弹出的快捷菜单中选择“属 性”命令,打开“默认网站属性”对话框,在“IP 地址”下拉列表中选择本机的 IP 地址, TCP 端口号采用默认值 80,如图 3.4 所示。 (4)在“默认网站”属性对话框中,选择“主目录”选项卡,单击“本地路径”文本 框后的“浏览”按钮,在打开的对话框中选择网站的主目录。这里为 E:\Catecity1,因为在 此之前已经将实例文件拷贝到该目录下了。其他选项采用默认设置即可,如图 3.5 所示。 图 3.4 “默认网站”属性对话框 图 3.5 “主目录”选项卡 (5)单击【应用】按钮后,再单击【确定】按钮即可。 2.创建虚拟目录 具体方法如下。 (1)在图 3.3 所示的“默认网站”节点上单击鼠标右键,在弹出的快捷菜单中选择“新 建”→“虚拟目录”命令,如图 3.6 所示,打开“虚拟目录创建向导”对话框。 图 3.6 新建虚拟目录对话框 97 C H A P T E R 3 第 3 章 天下鲜美食网 (2)在“虚拟目录创建向导”对话框中,单击【下一步】按钮,打开“虚拟目录别名” 对话框,如图 3.7 所示。在“别名”文本框中输入 Catecity1,然后单击【下一步】按钮, 打开“网站内容目录”对话框,如图 3.8 所示。 图 3.7 设置虚拟目录别名 图 3.8 设置网站内容目录 (3)在“网站内容目录”对话框中,单击“目录”文本框后的【浏览】按钮,在打开 的对话框中选择网站的目录。这里为 E:\Catecity1,因为已经将实例文件拷贝到该目录下。 (4)单击【下一步】按钮,进入“访问权限”设置对话框,这里采用默认设置即可, 再单【完成】按钮。 (5)选中创建的虚拟目录 Catecity1,在想要查看的文件名(例如:index.asp)上单击 鼠标右键,在弹出的快捷菜单中选择“浏览”命令即可浏览该网页。 3.5 数据库设计 本系统数据库采用 SQL Server 2005 数据库,系统数据库名称为 db_Catecity1。数据库 db_Catecity1 中包含 9 张表。下面分别给出数据表的实体 E-R 图、主要数据表结构及数据 表概要说明。 3.5.1 数据表的实体 E-R 图 根据数据表结构的设计,规划出相应的实体 E-R 图,这些实体中包含各种具体信息, 并通过相互之间的作用形成数据的流动。具体数据表的实 体 E-R 图描述如下。 图 3.9 为公告信息实体 E-R 图。 图 3.10 为网站计数器实体 E-R 图。 图 3.11 为默认头像信息实体 E-R 图。 计数 网站计数器实体 访问时间 IP地址 默认头像编号 默认头像信息实体 默认头像名称 头像的URL地址 图 3.10 网站计数器实体 E-R 图 图 3.11 默认头像信息实体 E-R 图 公告编号 公告信息实体 公告标题 公告内容 发布时间 图 3.9 公告信息实体 E-R 图 公告主题 发表主题 98 SQL Server 2005 数据库系统开发案例精选 图 3.12 为美食教程信息实体 E-R 图。 教程名称 美食教程信息实体 教程内容 教程作者 教程图片名称教程编号 教程加入时间 图 3.12 美食教程信息实体 E-R 图 图 3.13 为特色美食信息实体 E-R 图。 所属名店编号 特色美食信息实体 备注信息 图片名称 加班时间特色美食编号 特色名称 图 3.13 特色美食信息实体 E-R 图 图 3.14 为留言板信息实体 E-R 图。 用户编号 留言板信息实体 留言内容 发表时间 标记ImageData是否为空留言板主题编号 上传图片的数据 图 3.14 留言板信息实体 E-R 图 3.5.2 主要数据表的结构 由于文章的篇幅所限,在此只给出较为重要的数据表,其他数据表请参见本书附带的 光盘。  tb_Board(留言板信息表) 留言板信息表主要用于保存留言信息,该表的结构如表 3.1 所示。 表 3.1 tb_Board 表的结构 字 段 名 数 据 类 型 长 度 主 键 否 描 述 Topic_id bigint 8 是 留言板主题编号 User_id bigint 8 用户编号 Content varchar 255 留言内容 ImageData image 16 上传图片的数据 Datetime datetime 8 发表时间 ImageTag2 char 10 标记 ImageData 是否为空 加入时间 99 C H A P T E R 3 第 3 章 天下鲜美食网  tb_DefHead(默认头像信息表) 默认头像信息表主要用于保存默认头像信息。该表的结构如表 3.2 所示。 表 3.2 tb_DefHead 表的结构 列 名 数 据 类 型 长 度 主 键 否 描 述 Img_Id bigint 8 是 默认头像编号 Img_Name char 20 头像名称 Img_URL varchar 50 头像的 URL 地址  tb_Famous(名店信息表) 名店信息表主要用于保存名店信息。该表的结构如表 3.3 所示。 表 3.3 tb_Famous 表的结构 列 名 数 据 类 型 长 度 主 键 否 描 述 Id bigint 8 是 名店编号 Famous_Name varchar 50 名店名称 Address varchar 100 名店地址 LinkMan char 10 联系人 Telephone varchar 50 联系电话 Email char 30 E-mail WebAddress char 30 Web 地址 JoinTime datetime 8 加入时间 Introduce varchar 500 名店介绍 AreaName char 10 区域名称 Img_Name varchar 50 名店图片名称  tb_League(名店加盟信息表) 名店加盟信息表主要用于保存名店加盟信息。该表的结构如表 3.4 所示。 表 3.4 tb_League 表的结构 列 名 数 据 类 型 长 度 主 键 否 描 述 Com_Id bigint 8 是 加盟名店的编号 Com_Name varchar 50 加盟店名称 Com_Address varchar 255 加盟地址 LinkMan char 20 联系人 Com_Tel char 20 联系电话 Com_Email char 20 E-mail Com_Web varchar 50 网址 TraitFood varchar 255 特色食物 Com_Introduce varchar 255 公司简介 Com_JoinTime datetime 8 公司加入时间 Com_Flag char 10 加盟公司是否被修改过  tb_Teach(美食教程信息表) 100 SQL Server 2005 数据库系统开发案例精选 美食教程信息表主要用于保存美食教程信息。该表的结构如表 3.5 所示。 表 3.5 tb_Teach 表的结构 列 名 数 据 类 型 长 度 主 键 否 描 述 Teach_Id bigint 8 是 教程编号 Teach_Name varchar 50 教程名称 Teach_Content varchar 8000 教程内容 Teach_JoinTime datetime 8 教程加入时间 Teach_Author char 10 教程作者 Img_Name varchar 50 教程图片名称  tb_Trait(特色美食信息表) 特色美食信息表主要用于保存特色美食信息。该表的结构如表 3.6 所示。 表 3.6 tb_Trait 表的结构 列 名 数 据 类 型 长 度 主 键 否 描 述 Id bigint 8 是 特色美食编号 Famous_Id bigint 8 所属名店的编号 Remark varchar 100 备注信息 Trait_Name char 30 特色名称 Img_Name char 30 图片名称 JoinTime datetime 8 加入时间 3.5.3 数据表概要说明 从读者角度出发,为了使读者对本系统后台数据库中数据表有一个清晰的认识,笔者 在此特设计一个数据表树型结构图,该数据表树型结构图包含了系统中所有的数据表,如 图 3.15 所示。 图 3.15 数据表树型结构图 101 C H A P T E R 3 第 3 章 天下鲜美食网 3.6 技 术 准 备 3.6.1 读者知识要求 要很好地学习本案例,读者需要熟悉 SQL Server 2005 数据库的基本操作及 SQL 查询 语句的应用格式,还需要掌握 IIS 的相关配置。 3.6.2 命名规则  数据库 数据库名称以数据库的相关英文单词或拼音缩写命名,如表 3.7 所示。 表 3.7 数据库命名规则描述 数据库名称 描 述 db_Catecity1 天下鲜美食系统数据库  数据表 数据表以字母“tb”+下划线“_”+“数据表相关的英文单词或拼音缩写”命名,如表 3.8 所示。 表 3.8 数据表命名规则描述 数据表名称 描 述 tb_Board 留言板信息表 tb_DefHead 默认头像信息表 tb_Famous 名店信息表 tb_League 名店加盟信息表 tb_Trait 特色美食信息表  注意 在设计数据表时,当数据表名必须由两个单词组成时,通常将后面单词的首字母大写;对 于同一个数据库中的主表和明细表,可以在明细表的后面加入下划线和单词 detail 加以区分。  字段 字段采用英文单词或拼音缩写,如表 3.9 所示。 表 3.9 字段命名规则描述 数据表名称 描 述 User_Id 用户 ID 号 User_Name 用户名 User_Pass 用户密码 由于字段是英文或拼音缩写,需要在“描述”中填写中文说明;字段大小应该根据实 际情况进行设置。 3.6.3 文件管理规划 在置身于编码设计前,可先将网站中可能应用到的文件夹创建出来。例如创建一个 102 SQL Server 2005 数据库系统开发案例精选 名为 Conn 的文件夹,该文件夹主要用于保存网站中数据库的连接文件,既方便以后的 开发工作,又可规范网站整体结构,可谓一举两得。在开发天下鲜美食网时,首先设计 了图 3.16 所示的文件夹结构图,在开发时只需将文件保存在相应的文件夹中即可,非 常方便。 图 3.16 文件管理规划 3.7 前台主要功能模块详细设计 3.7.1 前台文件总体架构 前台页面主要包括以下功能模块。  网站导航:主要包括网站的旗帜广告条、功能分类导航和显示时间 3 部分。  名店介绍:主要用于名店查询、名店信息展示和推荐名店 3 部分。  特色美食:主要用于特色美食查询、特色美食展示两部分。  名店加盟:主要用于名店信息添加和名店信息展示两部分。  公告栏:主要用于展示最新加盟的名店名称。  美食教程:主要包括美食教程信息展示、美食教程查询两部分。  美食留言:主要用于显示会员的留言信息。  友情链接:主要用于显示友情链接的相关信息。  计数器:主要用于记录网站的访问流量。 3.7.2 文件架构 天下鲜美食网的前台文件架构如图 3.17 所示。 103 C H A P T E R 3 第 3 章 天下鲜美食网 图 3.17 文件架构图 3.7.3 前台页面的运行结果 前台页面的运行结果如图 3.18 所示。 1 2 3 4 5 6 图 3.18 前台页面运行结果 104 SQL Server 2005 数据库系统开发案例精选 为了方便读者阅读和有效利用本书附赠光盘的实例,笔者将网站页面的各部分说明以 列表形式给出,如表 3.10 所示。 表 3.10 网站首页解析 区 域 名 称 说 明 对 应 文 件 1 网站导航 主要用于显示当前网站的访问流量及网 站的功能导航 Index.asp 2 留言板登录 用于用户注册、找回密码和用户留言 Index.asp 3 公告栏 主要用于展示最新加盟的名店名称 Index.asp 4 友情链接 主要用于提供加盟网站的链接 Index.asp 5 特色美食 主要用于展示最新的特色美食信息 Index.asp 6 网站基本信息展示区 主要用于展示网站的基本信息 CopyRight.asp 3.7.4 创建数据库连接 在进行动态网站开发时,一个很重要的步骤就是建立数据库的连接,即访问数据库。 访问数据库可以用 DSN 和非 DSN 两种方法。应用 DSN 访问数据库需要配置 ODBC 数据 源(即系统 DSN),该方法的优点是比较安全;而应用非 DSN 访问数据库不需要配置 ODBC 数据源,比较方便。笔者经常使用后者。 创建数据库连接主要分两步进行:一是创建数据库连接文件 Conn.asp,二是在需要与数据 库连接的页面包含该文件(例如:)。下面进行详细介绍。 技巧 本书将数据库连接文件命名为 Conn.asp,为了方便以后维护网站,将其存放在站点根 目录的 Conn 文件夹下。读者在程序开发时,也应养成良好的命名规则,方便操作和维护 网站。 本案例的数据库配置文件为 Conn.asp,下面代码在所有对数据库的操作中都是必不可 少的。由于这段代码几乎在后面的每个对数据库操作页面都要使用,所以笔者将其保存在 一个单独的文件夹中,文件名为 Conn.asp,在所有与数据库连接的页面中只要包含该文件, 就可以连接和打开数据库。其数据库连接代码如下: <% Dim Conn Set Conn = Server.CreateObject("ADODB.Connection") sql="Driver={Sql Server};Server=(local);UID=sa;PWD=;Database=db_Catecity1" conn.open(sql) %> 3.8 特色美食模块设计 特色美食模块主要包括特色美食展示、特色美食查询、详细信息展示 3 个部分。在特 色美食展示页面中,用户单击任意一张美食的图片时,将会打开美食详细信息页。特色美 食管理页面的文件架构如图 3.19 所示。 105 C H A P T E R 3 第 3 章 天下鲜美食网 图 3.19 特色美食管理页面文件架构图 3.8.1 特色美食展示 特色美食展示管理模块主要对特色美食进行分栏显示,同时将查询到的结果也进行分 栏显示。特色美食展示页面的设计效果如图 3.20 所示。 图 3.20 特色美食页面设计效果 在本案例中,特色美食展示部分是作为一个单独的文件存在的,在使用过程中,被其 他文件包含使用,包含文件的代码如下: 通过如下代码将特色美食记录集输出到浏览器中,代码如下: <% Response. Write(TransImg("5", rs("Img_Name"), "Images/TraitImg/", rs("Trait_Name"), "Detail.asp?id=", rs("id"))) %>
在上述程序代码中,TransImg()函数是自定义的函数,主要用于将记录集横向输出到浏 览器中,并不是一般情况下的纵向输出。该函数的完整代码如下: <% Function TransImg(Cols,ImgName,ImgPath,RelName,HrefURL,Para) Dim NumTr,NumTd Dim J,K,Repeat_Cols Dim Temp NumTr = 0 NumTd = CInt(Cols) NumTr = rs.PageSize mod NumTd If(NumTr <> 0)Then NumTr = rs.PageSize\NumTd + 1 Else NumTr = rs.PageSize\NumTd 106 SQL Server 2005 数据库系统开发案例精选 End If J = 0 For K = 1 To NumTr Temp = Temp&"" Repeat_Cols = 0 While((J < rs.PageSize) and (Repeat_Cols < NumTd) and (Not rs.Eof)) Temp = Temp&"" Temp = Temp&"" Temp = Temp&"" Temp = Temp&"
" Temp = Temp&"" Temp = Temp&"
" Temp = Temp&RelName Temp = Temp&"
J = J + 1 Repeat_Cols = Repeat_Cols + 1 rs.MoveNext Wend Temp = Temp&"" Next TransImg = Temp End Function %> 函数中 Cols 参数表示一行要显示的列数;ImgName 参数表示循环显示的图片名称; ImgPath 参数表示循环显示的图片路径;RelName 参数表示循环显示的图片的真实名称; hrefURL+Para 参数表示图片超链接的路径。  注意 在该函数中不可以将表示图片超链接的路径用一个参数传递,而必须将超链接中的参 数 id 的值(rs("ID"))用另外一个参数传递,否则语句“rs("ID")”会被解释为相应的值, 并作为参数传递到函数中。 3.8.2 特色美食查询 特色美食查询可按条件对特色美食信息进行模糊查询,例如选择“所属名店”作为查 询条件,在“关键字”下拉列表中会自动列出所有已注册名店的名称,选择所要查询的名 店后,单击【查询】按钮。特色美食查询页面的设计效果如图 3.21 所示。 图 3.21 美食查询页面设计效果 动态构成页面的输出内容 107 C H A P T E R 3 第 3 章 天下鲜美食网 特色美食查询页面所涉及的 HTML 表单元素如表 3.11 所示。 表 3.11 特色美食页面所涉及的 HTML 表单元素 名 称 类 型 含 义 重 要 属 性 Query_Trait Form 表单 method="post" action="Default.asp" Condition select 条件 name="Condition"class="text" onChange= "Inner (options [selectedIndex].value)" 0)Then%>selected<%End If%>>美食名称 0)Then%>selected<%End If%>> 所属名店 )Then%> selected<%End If%>>加入时间 key1 text 关键字 class="text" style="width:100" value="<%=Server.HTMLEncode (Request("key1"))%>" 查询 submit 【查询】按钮 type="submit" class="button" value="查询" 重置 button 【重置】按钮 class="button" value="重置" onClick="Javascript:window.location.reload();" 在进行特色美食查询时,应用下拉列表动态显示的原理实现,根据下拉列表值的不同, 显示出不同控件。相关代码如下:
条 件 ">
关键字 从数据库中取出名店记录 108 SQL Server 2005 数据库系统开发案例精选
控制下拉列表内容动态显示的 JavaScript 脚本的代码如下: Inner()函数在网页中有两次被调用。一次是在网页下载时被调用。关键代码如下: 另一次是在选择查询条件时被调用。关键代码如下: <%While(Not rs.Eof)%> <%rs.MoveNext Wendrs Close Set rs = Nothing %> Head file 上传头像 class="file" id="Head" Telephone text 联系电话 class="text" id="Telephone" 提交 button 【提交】按钮 onClick="return Check(Register)" class="button" value="提交" 重置 submit 【重置】按钮 type="reset" class="button" value="重置" 在进行数据提交前,需要将 Form 表单的 enctype 属性设为 multipart/form-data,表示以 二进制的形式传送数据,代码如下:
118 SQL Server 2005 数据库系统开发案例精选 通过以下代码将表单中的文本信息添加到指定的数据表中,代码如下: <% Dim Conn Set Conn = Server.CreateObject("ADODB.Connection") sql="Driver={Sql Server};Server=(local);UID=sa;PWD=;Database=db_Catecity1" conn.open(sql) %> <% Response.Buffer=true formsize=Request.TotalBytes formdata=Request.BinaryRead(formsize) crlf=chrB(13)&chrB(10) strflag=leftb(formdata,clng(instrb(formdata,crlf))-1) ’注册信息添加到数据库 Sql_2 = "Select * from tb_User" Set rs_2 = Server.CreateObject("ADODB.Recordset") rs_2.open Sql_2,conn,0,3 rs_2.AddNew ’获得表单所有元素的值 k = 1 While instrb(k,formdata,strflag) < instrb((instrb(k,formdata,strflag)+lenb(strflag)),formdata,strflag) start = instrb(k,formdata,strflag) + lenb(strflag) + 2 endsize = instrb((instrb(k,formdata,strflag)+lenb(strflag)),formdata,strflag) - start - 2 bin_content = midb(formdata,start,endsize) pos1_name = instrb(bin_content,toByte("name=""")) pos2_name = instrb(pos1_name+6,bin_content,toByte("""")) nametag = midb(bin_content,pos1_name+6,pos2_name-pos1_name-6) If(InStr(toStr(nametag),"用户名") > 0)Then Sql = "Select * from tb_User" Set rs = conn.Execute(Sql) If(Not rs.eof)Then namevalue = midb(bin_content,pos2_name+5,lenb(bin_content)-pos2_name-4) If(InStr(toStr(namevalue),"’") > 0)Then %> <% Response.End() End If Sql_1 = "Select * from tb_User Where User_Name = ’"&toStr(namevalue)&"’" Set rs_1 = conn.Execute(Sql_1) If(Not rs_1.Eof)Then %> <% rs_1.Close() Set rs_1 = Nothing rs.Close() Set rs = Nothing 获得注册信息 检索用户名是否重复 119 C H A P T E R 3 第 3 章 天下鲜美食网 Response.End() End If End If End If response.write(toStr(nametag)&"
") pos1_filename = instrb(pos2_name,bin_content,toByte("filename=""")) If(pos1_filename = 0)Then namevalue = toStr(midb(bin_content,pos2_name+5,lenb(bin_content)-pos2_name-4)) If(InStr(toStr(nametag),"用户名") > 0)Then rs_2("User_Name") = namevalue Session("UserName") = namevalue End If If(InStr(toStr(nametag),"确认密码") > 0)Then rs_2("User_Pass") = namevalue End If If(InStr(toStr(nametag),"Sex") > 0)Then rs_2("User_Sex") = namevalue End If If(InStr(toStr(nametag),"Email") > 0)Then rs_2("User_Email") = namevalue End If If(InStr(toStr(nametag),"密码提示问题") > 0)Then rs_2("Question") = namevalue End If If(InStr(toStr(nametag),"密码提示答案") > 0)Then rs_2("Answer") = namevalue End If If(InStr(toStr(nametag),"OICQ") > 0)Then If(namevalue = "")Then rs_2("OICQ") = "空" Else rs_2("OICQ") = namevalue End IF End If If(InStr(toStr(nametag),"MSN") > 0)Then If(namevalue = "")Then rs_2("MSN") = "空" Else rs_2("MSN") = namevalue End IF End If If(InStr(toStr(nametag),"SelHead") > 0)Then rs_2("ImageURL") = namevalue End If If(InStr(toStr(nametag),"Telephone") > 0)Then If(namevalue = "")Then rs_2("TelePhone") = "空" Else rs_2("TelePhone") = namevalue End IF End If If(InStr(toStr(nametag),"Homepage") > 0)Then If(namevalue = "")Then rs_2("HomePage") = "空" Else rs_2("HomePage") = namevalue 120 SQL Server 2005 数据库系统开发案例精选 End IF End If response.write(namevalue&"
") Else ’取filename的值 pos2_filename = instrb(pos1_filename+10,bin_content,toByte("""")) fullpath = midb(bin_content,pos1_filename+10,pos2_filename-pos1_filename-10) If(fullpath <> "")Then filename = GetFileName(toStr(fullpath)) expandname = Mid(filename,InStrRev(filename,".")+1) imgarray = Array("gif","jpg","jpeg","jpe") imgflag = false For q=0 To Ubound(imgarray) If(InStr(Lcase(expandname),imgarray(q)) > 0)Then imgflag = true End If Next If(imgflag = false)Then %> <% Response.End() End If ’获得上传图片的二进制数据 bin_start = instrb(bin_content,crlf&crlf) + 4 filedata=midb(bin_content,bin_start) If(filedata = "")Then rs_2("ImageTag") = "空" Else rs_2("ImageData").Appendchunk filedata End If Else rs_2("ImageTag") = "空" End If End If k = instrb((instrb(k,formdata,strflag)+lenb(strflag)),formdata,strflag) Wend rs_2("IPAddress") = Request.ServerVariables("REMOTE_ADDR") rs_2.Update Response.Redirect("../../Board/Default.asp") Response.End() ’字符串转换成二进制数 Private function toByte(Str) dim i,iCode,c,iLow,iHigh toByte="" For i=1 To Len(Str) c=mid(Str,i,1) iCode =Asc(c) If iCode<0 Then iCode = iCode + 65535 If iCode>255 Then iLow = Left(Hex(Asc(c)),2) iHigh =Right(Hex(Asc(c)),2) toByte = toByte & chrB("&H"&iLow) & chrB("&H"&iHigh) 叛断上传的格式 121 C H A P T E R 3 第 3 章 天下鲜美食网 Else toByte = toByte & chrB(AscB(c)) End If Next End function Private function toStr(Byt) toStr="" for i=1 to lenb(byt) blow = midb(byt,i,1) if ascb(blow)>127 then toStr = toStr&chr(ascw(midb(byt,i+1,1)&blow)) i = i+1 else toStr = toStr&chr(ascb(blow)) end if Next End function ’获得上传文件的路径 Private function GetFilePath(FullPath) If FullPath <> "" Then GetFilePath = left(FullPath,InStrRev(FullPath, "\")) Else GetFilePath = "" End If End function ’获得上传文件的名称 Private function GetFileName(FullPath) If FullPath <> "" Then GetFileName = mid(FullPath,InStrRev(FullPath, "\")+1) Else GetFileName = "" End If End function %> 3.11.2 发表留言模块 当用户成功登录后,可以通过发表留言页面进行留言信息的发布。发表留言页面的页 面设计效果如图 3.26 所示。 图 3.26 发表留言的页面设计效果 发布留言页面所涉及的 HTML 表单元素如表 3.14 所示。 二进制转换成字符串 122 SQL Server 2005 数据库系统开发案例精选 表 3.14 发布留言页面所涉及的 HTML 表单元素 名 称 类 型 含 义 重 要 属 性 Board form 表单 enctype="multipart/form-data" action="tre_/tre_ Default.asp"onSubmit="return Check()" Board_Content textarea 发表留言 style="width:600;height:127;border:1px solid" Board_Image file 上传图片 style="border:1px solid;width:300;" UserID hidden 隐藏域 value="<%=rs_2("User_id")%>" 发表留言 submit 【发表留言】按钮 class="button" style="width:60" 重置 reset 【重置】按钮 value="重置" class="button" 将发表的留言信息添加到数据表中的代码如下。 <%@LANGUAGE="VBSCRIPT" CODEPAGE="936"%> <% ’获取留言信息 Response.Buffer=true formsize=Request.TotalBytes formdata=Request.BinaryRead(formsize) ’Response.BinaryWrite(Formdata) crlf=chrB(13)&chrB(10) strflag=leftb(formdata,clng(instrb(formdata,crlf))-1) ’留言信息添加到数据库 Sql_2 = "Select * from tb_Board" Set rs_2 = Server.CreateObject("ADODB.Recordset") rs_2.open Sql_2,conn,0,3 rs_2.AddNew ’获得表单所有元素的值 k = 1 While instrb(k,formdata,strflag) < instrb((instrb(k,formdata,strflag)+lenb(strflag)),formdata,strflag) start = instrb(k,formdata,strflag) + lenb(strflag) + 2 endsize = instrb((instrb(k,formdata,strflag)+lenb(strflag)),formdata,strflag) - start - 2 bin_content = midb(formdata,start,endsize) pos1_name = instrb(bin_content,toByte("name=""")) pos2_name = instrb(pos1_name+6,bin_content,toByte("""")) nametag = midb(bin_content,pos1_name+6,pos2_name-pos1_name-6) response.write(toStr(nametag)&"
") pos1_filename = instrb(pos2_name,bin_content,toByte("filename=""")) If(pos1_filename = 0)Then namevalue = toStr(midb(bin_content,pos2_name+5,lenb(bin_content)-pos2_name-4)) If(InStr(toStr(nametag),"Board_Content") > 0)Then rs_2("Content") = namevalue ’Session("UserName") = namevalue End If If(InStr(toStr(nametag),"UserID") > 0)Then rs_2("User_id") = namevalue End If response.write(namevalue&"
") Else ’取filename的值 pos2_filename = instrb(pos1_filename+10,bin_content,toByte("""")) fullpath = midb(bin_content,pos1_filename+10,pos2_filename-pos1_filename-10) If(fullpath <> "")Then 123 C H A P T E R 3 第 3 章 天下鲜美食网 ’判断上传的格式 filename = GetFileName(toStr(fullpath)) expandname = Mid(filename,InStrRev(filename,".")+1) imgarray = Array("gif","jpg","jpeg","jpe","bmp") imgflag = false For q=0 To Ubound(imgarray) If(InStr(Lcase(expandname),imgarray(q)) > 0)Then imgflag = true End If Next If(imgflag = false)Then %> <% Response.End() End If ’获得上传图片的二进制数据 bin_start = instrb(bin_content,crlf&crlf) + 4 filedata=midb(bin_content,bin_start) If(filedata = "")Then rs_2("ImageTag2") = "空" Else rs_2("ImageData").Appendchunk filedata End If Else rs_2("ImageTag2") = "空" End If End If k = instrb((instrb(k,formdata,strflag)+lenb(strflag)),formdata,strflag) Wend rs_2.Update Response.Redirect("../Default.asp") Response.End() ’字符串转换成二进制数 Private function toByte(Str) dim i,iCode,c,iLow,iHigh toByte="" For i=1 To Len(Str) c=mid(Str,i,1) iCode =Asc(c) If iCode<0 Then iCode = iCode + 65535 If iCode>255 Then iLow = Left(Hex(Asc(c)),2) iHigh =Right(Hex(Asc(c)),2) toByte = toByte & chrB("&H"&iLow) & chrB("&H"&iHigh) Else toByte = toByte & chrB(AscB(c)) End If Next End function ’二进制转换成字符串 Private function toStr(Byt) toStr="" for i=1 to lenb(byt) 124 SQL Server 2005 数据库系统开发案例精选 blow = midb(byt,i,1) if ascb(blow)>127 then toStr = toStr&chr(ascw(midb(byt,i+1,1)&blow)) i = i+1 else toStr = toStr&chr(ascb(blow)) end if Next End function ’获得上传文件的路径 Private function GetFilePath(FullPath) If FullPath <> "" Then GetFilePath = left(FullPath,InStrRev(FullPath, "\")) Else GetFilePath = "" End If End function ’获得上传文件的名称 Private function GetFileName(FullPath) If FullPath <> "" Then GetFileName = mid(FullPath,InStrRev(FullPath, "\")+1) Else GetFileName = "" End If End function %> 3.12 后台主要功能模块详细设计 3.12.1 后台总体架构 天下鲜美食网的后台主要由 8 个模块组成,分别是用户管理、公告栏管理、名店介绍 管理、特色美食管理、美食教程管理、美食留言管理、名店加盟管理、后台管理退出。后 台管理页面的设计架构如图 3.27 所示。 图 3.27 后台设计架构 125 C H A P T E R 3 第 3 章 天下鲜美食网 3.12.2 后台管理页面的实现过程 在首页中提供了后台登录入口,管理员可以通过此入口登录到系统后台。如果管理员 在登录时,忘记了密码,可以通过单击【忘记密码】按钮对密码进行找回。通过后台管理 页面可以对天下鲜美食网相关模块中的数据进行添加、删除、修改、查询等操作。后台管 理页面的运行结果如图 3.28 所示。 图 3.28 后台运行结果 3.13 用户管理模块设计 用户管理模块主要包括用户信息查询、用户权限修改和用户信息删除 3 部分。管理员 可以通过后台管理功能导航进入到用户信息管理页面。 3.13.1 用户信息查询 在用户信息查询页面,管理员可在“查询”文本框中输入并选择查询条件,单击“查 询”按钮,即可查询到指定条件的用户信息。当管理员输入查询条件后,单击【查询】按 钮,此时添加的查询条件将被提交到当前页,当前页则会根据用户提交的表单信息对数据 库进行检索,并将结果集通过信息展示部分(默认情况下,显示数据库中所有用户的信息,) 输出到浏览器中,程序代码如下。 <% getcondition = Replace(trim(request("condition")),"’","’’") getkey = Replace(trim(request("key")),"’","’’") if(getcondition = "" or getkey = "")then Sql = "Select * from tb_User order by JoinTime Desc" else If(InStr(getcondition,"JoinTime") > 0)Then If(InStr(getkey,"-") > 0)Then darray = Split(getkey,"-") getkey = "" 默认情况下检索数据库中的全部数据 126 SQL Server 2005 数据库系统开发案例精选 For a=0 To Ubound(darray) If(len(darray(a)) = 1 )Then darray(a) = "0"&darray(a) End If getkey = getkey&darray(a)&"-" Next getkey = Mid(getkey,1,len(getkey)-1) End If Sql = "Select * from tb_User where convert(varchar(10),"&getcondition&",121) like ’%" &ge tkey&"%’ order by JoinTime Desc" Else Sql = "Select * from tb_User where "&getcondition&" like ’%"&getkey&"%’ order by Join Time Desc" End If end if Set rs = Server.CreateObject("ADODB.Recordset") rs.Open Sql,conn,1,3 rs.PageSize = 4 ’实现分页 if rs.Eof then rs_total = 0 else rs_total = rs.RecordCount end if dim pageno getpageno = Switch(Request("pageno")) if(getpageno = "")then pageno = 1 ’默认情况下,当前页的页码为1 else pageno = getpageno ’提取传递参数中的页码数据 End if if(not rs.Eof)then rs.AbsolutePage = pageno ’指定当前显示页的页码 end if If(rs.Eof)Then response.write("没有用户记录!”) Response.End() End If repeat_rows = 0 While(repeat_rows < rs.PageSize and Not rs.Eof) %> "> <%=Server.HtmlenCode(rs("User_Name"))%> <%=Server.HtmlenCode(rs("User_Sex"))%> <%=Mid(rs("JoinTime"),1,InStr(rs("JoinTime")," "))%> <%=Server.HtmlenCode(rs("IPAddress"))%> 127 C H A P T E R 3 第 3 章 天下鲜美食网 <%=Server.HtmlenCode(rs("Grade"))%> [" target="adm_Main">修 改] <% repeat_rows = repeat_rows + 1 rs.MoveNext Wend %> 3.13.2 用户信息修改 在用户信息修改页面,管理员可以浏览用户详细信息,并可以修改用户的权限。当管 理员在修改页面修改了用户的权限,并单击【修改】按钮确认修改操作后,修改的数据将 被提交到数据处理页,而数据处理页则将根据管理员提交的表单数据对指定的用户信息进 行相应的更新操作,数据处理页面的相关代码如下: <% getid = Switch(Request("id")) getgrade = Trim(Request("权限")) Sql = "Update tb_User Set Grade = ’"&getgrade&"’ Where User_Id = "&getid conn.Execute(Sql) Response.Redirect("../adm_User.asp") %>  注意 在进行单条或多条数据(全部除外)更新时,千万不要忘记加入条件语句,否则会将 数据表中的全部数据统一更新。 修改用户权限页面的运行结果如图 3.29 所示。 图 3.29 修改用户权限页面的运行结果 128 SQL Server 2005 数据库系统开发案例精选 3.13.3 用户信息删除 在用户信息管理页面,管理员可以选择任意一条用户信息前面的复选框,并单击【删 除】按钮,将选中的用户信息删除。如果想删除所有用户信息,可以选择【全选/反选】复 选框;反之,则表明取消所有用户信息的选择。 用户信息删除主要通过参数传递,此时的参数为用户信息的 ID 号。程序代码如下: <% getChkBox = request("BoxUser") getcondition = replace(trim(request("condition")),"’","’’") getkey = replace(trim(request("key")),"’","’’") getpageno = replace(trim(request("pageno")),"’","") rssql = "delete from tb_User where User_Id in ("&getChkBox&")" conn.Execute(rssql) response.Redirect("../adm_User.asp?condition="&getcondition&"&key="&getkey) %>  注意 在删除记录后,将页面重定向至信息列表页面时,不要忘记将原来的查询参数传递 回去。 3.14 名店介绍管理模块设计 名店介绍管理模块用于对名店信息进行管理,主要包括名店查询、名店添加、名店修 改、名店删除 4 部分。 3.14.1 名店信息查询 在名店介绍管理页面可按指定条件查询名店信息。在设置查询条件后,单击“查询” 按钮,即可将满足查询条件的名店信息查询出来。名店查询页面的设计效果如图 3.30 所示。 图 3.30 名店查询页面的设计效果 名店查询页面所涉及的 HTML 表单元素如表 3.15 所示。 129 C H A P T E R 3 第 3 章 天下鲜美食网 表 3.15 名店查询页面所涉及的 HTML 表单元素 名 称 类 型 含 义 重 要 属 性 Que_Famous Form 表单 method="post" action="adm_Famous.asp" condition select 查询条件 class="text"style="width:150;border:1pxsolid;" onChange="Inner (options[selectedIndex].value)" 0)Then%>selected<%End If%>>名店 名 称 0)Then%>selected<%End If%>>区 域 0)Then%>selected<%End If%>>加入时间 key select 关键字 key text 关键字 tyle="height:20;border:1px solid;" value="<%=Server.Htm lencode(Replace(getkey,"’’","’"))%>" size="30" submit submit 【查询】按钮 class="button" value="查询" 设置查询条件后,单击【查询】按钮将填写的数据信息提交给数据处理页面,此时该 数据处理页面将根据相关数据信息到指定的数据表中进行数据检索,再将查询结果输出到 浏览器中。程序代码如下: <% getcondition = Replace(trim(request("condition")),"’","’’") getkey = Replace(trim(request("key")),"’","’’") if(getcondition = "" or getkey = "" )then Sql = "select * from tb_Famous order by JoinTime Desc" else If(InStr(getcondition,"JoinTime") > 0)Then If(InStr(getkey,"-") > 0)Then darray = Split(getkey,"-") getkey = "" For a=0 To Ubound(darray) If(len(darray(a)) = 1 )Then darray(a) = "0"&darray(a) End If getkey = getkey&darray(a)&"-" Next 130 SQL Server 2005 数据库系统开发案例精选 getkey = Mid(getkey,1,len(getkey)-1) End If Sql = "select * from tb_Famous where convert(varchar(10),"&getcondition&",121) like ’%"& getkey&"%’ order by JoinTime Desc" Else Sql = "select * from tb_Famous where "&getcondition&" like ’%"&getkey&"%’ order by Join Time Desc" End If end if Set rs = Server.CreateObject("ADODB.Recordset") rs.Open Sql,conn,1,3 rs.PageSize = 6 ’实现分页 if rs.Eof then rs_total = 0 else rs_total = rs.RecordCount end if dim pageno getpageno = Switch(Request("pageno")) if(getpageno = "")then pageno = 1 else pageno = getpageno End if if(not rs.Eof)then rs.AbsolutePage = pageno end if %> 技术细节 在实现名店信息模糊查询时,主要应用到 LIKE 运算符。下面介绍一下 LIKE 运算符 的使用方法。 LIKE 运算符用于确定给定的字符串是否与指定的模式相匹配。模式可以包括常规字 符和通配符。在模式匹配过程中,常规字符必须与字符串指定的字符完全匹配。但是,通 配符可以与字符串的任意部分相匹配。与使用=和!=字符串比较运算符相比,使用通配符 可使 LIKE 运算符更加灵活。如果某些参数不是字符串数据类型,Microsoft SQL Server 2005 Mobile Edition (SQL Server Mobile)会将它们转换成字符串类型。 语法格式如下。 match_expression [ NOT ] LIKE ’pattern’ [ ESCAPE escape_character ] 参数说明: match_expression 任何字符串数据类型的有效 SQL 表达式。 Pattern match_expression 中的搜索模式,可以包含%、—、[] 、[^]通配符。 escape_character 字符串数据类型分类中的所有数据类型的任何有效 SQL 表达式。 escape_character 没有默认值,且必须仅包含一个字符。 3.14.2 名店信息添加 通过名店信息添加页面可以向网站中添加一些新的名店信息,在名店添加页面中,浏 览者可以上传与该名店相关的图片,并对上传的图片进行了格式限定。相关代码如下: 此处主要应用 Like 运算符 实现名店信息的查询功能 131 C H A P T E R 3 第 3 章 天下鲜美食网 <% Response.Buffer=true formsize=Request.TotalBytes  formdata=Request.BinaryRead(formsize) crlf=chrB(13)&chrB(10) strflag=leftb(formdata,clng(instrb(formdata,crlf))-1) ’名店信息添加到数据库 Sql_2 = "Select * from tb_Famous"  Set rs_2 = Server.CreateObject("ADODB.Recordset") rs_2.open Sql_2,conn,0,3 rs_2.AddNew ’获得表单所有元素的值 k = 1 ’注意不要用i了 While instrb(k,formdata,strflag) < instrb((instrb(k,formdata,strflag)+lenb(strflag)),formdata,strflag) start = instrb(k,formdata,strflag) + lenb(strflag) + 2 endsize = instrb((instrb(k,formdata,strflag)+lenb(strflag)),formdata,strflag) - start - 2 bin_content = midb(formdata,start,endsize) pos1_name = instrb(bin_content,toByte("name=""")) pos2_name = instrb(pos1_name+6,bin_content,toByte("""")) nametag = midb(bin_content,pos1_name+6,pos2_name-pos1_name-6) pos1_filename = instrb(pos2_name,bin_content,toByte("filename=""")) If(pos1_filename = 0)Then namevalue = toStr(midb(bin_content,pos2_name+5,lenb(bin_content)-pos2_name-4)) If(InStr(toStr(nametag),"名店名称") > 0)Then rs_2("Famous_Name") = namevalue End If If(InStr(toStr(nametag),"地址") > 0)Then rs_2("Address") = namevalue End If  If(InStr(toStr(nametag),"联系人") > 0)Then rs_2("LinkMan") = namevalue End If If(InStr(toStr(nametag),"联系电话") > 0)Then rs_2("Telephone") = namevalue End If If(InStr(toStr(nametag),"Email") > 0)Then If(namevalue = "")Then rs_2("Email") = "空" Else rs_2("Email") = namevalue End If End If If(InStr(toStr(nametag),"网址") > 0)Then If(namevalue = "")Then rs_2("WebAddress") = "空" Else rs_2("WebAddress") = namevalue End If End If If(InStr(toStr(nametag),"区域") > 0)Then rs_2("AreaName") = namevalue 获得添加信息 132 SQL Server 2005 数据库系统开发案例精选 End If If(InStr(toStr(nametag),"名店介绍") > 0)Then If(namevalue = "")Then rs_2("Introduce") = "空" Else rs_2("Introduce") = namevalue End If End If Else ’取filename的值 pos2_filename = instrb(pos1_filename+10,bin_content,toByte("""")) fullpath = midb(bin_content,pos1_filename+10,pos2_filename-pos1_filename-10) If(fullpath <> "")Then ’filepath = GetFilePath(toStr(fullpath)) ’叛断上传的格式 filename = GetFileName(toStr(fullpath)) expandname = Mid(filename,InStrRev(filename,".")+1) imgarray = Array("gif","jpg","jpeg","jpe","bmp") imgflag = false For q=0 To Ubound(imgarray) If(InStr(Lcase(expandname),imgarray(q)) > 0)Then imgflag = true End If Next If(imgflag = false)Then %> <% Response.End() End If realname = Mid(filename,InStrRev(filename,"/")+1)  If(realname <> "")Then rs_2("Img_Name") = realname Else rs_2("Img_Name") = "空" End If bin_start = instrb(bin_content,crlf&crlf) + 4 filedata=midb(bin_content,bin_start) ’把图片数据上传到文件夹 Set objstream = CreateObject("ADODB.Stream") objstream.mode = 3 objstream.type = 1 objstream.open objstream.write formdata objstream.position = instrb (instrb (formdata, toByte("filename= """)), formdata, crlf&crlf)+ 3 ’是加3不是4 set guyu = server.CreateObject("adodb.stream") guyu.mode = 3 guyu.type = 1 guyu.open objstream.copyto guyu,lenb(filedata) guyu.savetofile Server.MapPath("../Images/UpImg/"&realname),2 获得上传图片的二 进制数据 133 C H A P T E R 3 第 3 章 天下鲜美食网 guyu.close Set guyu = nothing objstream.close Set objstream = nothing Else rs_2("Img_Name") = "空" End If End If k = instrb((instrb(k,formdata,strflag)+lenb(strflag)),formdata,strflag) Wend rs_2.Update Response.Redirect("../adm_Famous.asp") Response.End() ’字符串转换成二进制数 Private function toByte(Str) dim i,iCode,c,iLow,iHigh toByte=""  For i=1 To Len(Str)  c=mid(Str,i,1) iCode =Asc(c) If iCode<0 Then iCode = iCode + 65535 If iCode>255 Then iLow = Left(Hex(Asc(c)),2) iHigh =Right(Hex(Asc(c)),2) toByte = toByte & chrB("&H"&iLow) & chrB("&H"&iHigh) Else toByte = toByte & chrB(AscB(c)) End If Next End function Private function toStr(Byt) toStr="" for i=1 to lenb(byt) blow = midb(byt,i,1) if ascb(blow)>127 then toStr = toStr&chr(ascw(midb(byt,i+1,1)&blow)) i = i+1 else toStr = toStr&chr(ascb(blow)) end if Next End function ’获得上传文件的路径 Private function GetFilePath(FullPath) If FullPath <> "" Then GetFilePath = left(FullPath,InStrRev(FullPath, "\")) Else GetFilePath = "" End If End function ’获得上传文件的名称 Private function GetFileName(FullPath) If FullPath <> "" Then GetFileName = mid(FullPath,InStrRev(FullPath, "\")+1) Else GetFileName = "" 将二进制转换成字符串 134 SQL Server 2005 数据库系统开发案例精选 End If End function %>  代码导读  request:request 对象被用于读取客户端传送给服务器的值,通常由客户端向 Web 服务器提出请求,Web 服务器才会响应信息。  CreateObject:在 ASP 程序中,如果需要进行数据库访问或者磁盘文件操作,仅靠 脚本语言是无法实现的。ActiveX 提供了一系列的对象模型来实现例如数据库连接、文件 访问、广告显示和 VBScript 不能提供或不能简单地依靠单独使用 ActiveX 所能完成的功 能。使用 CreateObject 方法来创建服务器组件的对象模型,语法格式如下。 Server. CreateObject("对象模型名称") Server.CreateObject 是通过 MTS(Microsoft Transaction Server)创建并管理对象,当 对象发生错误时,Server.CreateObject 不但返回一个错误而且还将错误信息记录在日志中, 具有较好的安全性。  InStr():用于返回指定字符在字符串中首次出现的位置。  If...Then...Else 语句:根据表达式的值有条件地执行一组语句。  len 函数:返回字符串内字符的数目,或是存储一变量所需的字节数。  mid 函数:从字符串中返回指定数目的字符。 名店信息添加页面的运行结果如图 3.31 所示。 图 3.31 名店信息修改页面的运行结果 3.14.3 名店信息修改 在名店信息修改页面,管理员可以通过单击【修改】按钮对名店信息进行修改,修改 的数据将被提交到数据处理页,数据处理页将根据管理员提交的表单数据对指定的名店信 息进行相应的更新操作,数据处理页面的相关代码如下。 <% getid = Switch(Request("id")) 135 C H A P T E R 3 第 3 章 天下鲜美食网 getname = Trim(Request("名店名称")) getaddress = Trim(Request("地址")) getlinkman = Trim(Request("联系人")) gettelephone = Trim(Request("联系电话")) getemail = Trim(Request("Email")) getweb = Trim(Request("网址")) getareaname = Trim(Request("区域")) getintroduce = Request("名店介绍") If(getemail = "")Then getemail = "空" End If If(getweb = "")Then getweb = "空" End If If(getintroduce = "")Then getintroduce = "空" End If Sql = "Update tb_Famous Set Famous_Name = ’"&getname&"’,Address = ’"&getaddress&"’,LinkMan = ’"&getlinkman&"’,Telephone = ’"&gettelephone&"’,Email = ’"&getemail&"’,WebAddress = ’"&getweb&"’,AreaName = ’"&getareaname&"’,Introduce = ’"&getintroduce&"’ Where Id = "&getid conn.Execute(Sql) Response.Redirect("../adm_Famous.asp") %> 技术细节 主要应用 Update 语句实现名店信息修改操作。下面介绍 Update 语句。 Update 语句用来改变单行上的一列或多列的值,或是改变单个表中选定的一些行上 的多个列值。当然,为了在 Update 语句中修改指定表中的数据,必须有对表的 Update 访 问权限。 语法格式如下: Update SET = [….,=] [WHERE] 参数说明 table_name:需要更新的表的名称。如果该表不在当前服务器或数据库中,或不为当 前用户所有,这个名称可用链接服务器、数据库和所有者名称来限定。 view_name:要更新的视图的名称。通过 view_name 来引用的视图必须是可更新的。 用 Update 语句进行的修改,至多只能影响视图的 FROM 子句所引用的基表中的一个。 SET:指定要更新的列或变量名称的列表。 column_name:含有要更改数据的列的名称。column_name 必须驻留于 Update 子句中 所指定的表或视图中。标识列不能进行更新。如果指定了限定的列名称,限定符必须同 Update 子句中的表或视图的名称相匹配。 expression:变量、表达式或加上括号返回单个值的 subSELECT 语句。expression 返 回的值将替换 column_name 或@variable 中的现有值。 WHERE:指定条件来限定所更新的行。 名店信息修改页面的运行结果如图 3.32 所示。 通过 Update 语句实现名店信息修改操作 136 SQL Server 2005 数据库系统开发案例精选 图 3.32 名店信息修改页面的运行结果 3.14.4 名店信息删除 在名店信息删除页面中可以删除指定的一条名店信息。如果想删除所有名店信息时, 可以选择“全选/反选”复选框;反之,则表明取消所有名店信息的选择。其程序代码如下。 <% getChkBox = request("BoxFamous") getcondition = replace(trim(request("condition")),"’","’’") getkey = replace(trim(request("key")),"’","’’") getpageno = replace(trim(request("pageno")),"’","") rssql = "delete from tb_Famous where Id in ("&getChkBox&")" conn.Execute(rssql) response.Redirect("../adm_Famous.asp?condition="&getcondition&"&key="&getkey) %> 3.15 疑难问题分析解决 3.15.1 日期时间的显示 在网页中实现日期时间的动态显示,可以增加网页的动感效果,同时可以方便浏览者 掌握时间。笔者主要应用 JavaScript 脚本编写了两个自定义函数,ShowDate()函数主要用来 显示日期;ShowTime 函数主要用来显示时间。读者也可以在自己开发的网站中直接调用 这两个函数实现日期时间的显示。 在天下鲜美食网中动态显示日期时间的效果如图 3.33 所示。 图 3.33 动态显示日期时间 显示日期的关键代码如下。 function ShowDate(Elements) { 137 C H A P T E R 3 第 3 章 天下鲜美食网 var temp; var datetime = new Date(); var year = datetime.getYear(); var month = datetime.getMonth() + 1; var date = datetime.getDate(); var day = datetime.getDay(); temp = year+"年"+month+"月"+date+"日 "; switch (day) { case 0: temp = temp+"星期日"; break; case 1: temp = temp+"星期一"; break; case 2: temp = temp+"星期二"; break; case 3: temp = temp+"星期三"; break; case 4: temp = temp+"星期四"; break; case 5: temp = temp+"星期五"; break; case 6: temp = temp+"星期六"; break; } Elements.innerHTML = temp; } 在网页中引用 ShowTime 函数时要设置的 id 属性值。关键代码如下。 显示时间的关键代码如下。 function ShowTime(Elements) { var temp = ""; var datetime = new Date(); var hour = datetime.getHours(); var minu = datetime.getMinutes(); var seco = datetime.getSeconds(); if(hour < 10) hour ="0" + hour; if(minu < 10) minu ="0" + minu; if(seco < 10) seco ="0" + seco; temp = temp+" "+hour+":"+minu+":"+seco+" "; if(hour >= 0 && hour < 5) temp = temp + "凌晨好" if(hour >= 5 && hour < 8) temp = temp + "早上好" 138 SQL Server 2005 数据库系统开发案例精选 if(hour >= 8 && hour < 11) temp = temp + "上午好" if(hour >= 11 && hour < 13) temp = temp + "中午好" if(hour >= 13 && hour < 17) temp = temp + "下午好" if(hour >= 17 && hour < 23) temp = temp + "晚上好" Elements.innerHTML = temp; //这个Elements代表(表格)的id window.setTimeout("ShowTime(" + Elements.id + ")",1000) } 在网页中也使用上面的方法设置的 id 属性值。关键代码如下。  注意 在调用函数之前要先导入包含它的 JavaScript 文件或直接把函数写在网页中。 3.15.2 如何根据下拉列表的值显示不同控件 在开发天下鲜美食网时,涉及到多条件查询的问题。为了方便用户,需要根据用户选 择的条件,来设置不同的控件用于收集查询的关键字。在“条件”下拉列表中选择“特色 名称”时,在下方将显示“关键字”文本框,如图 3.34 所示;在“条件”下拉列表中选择 “所属名店”时,查询关键字将以下拉列表给出,供用户选择。如图 3.35 所示。 图 3.34 选择“特色名称“时 图 3.35 选择“所属名店”时 根据下拉列表的值显示不同控件,主要应用 JavaScript 脚本控制下拉列表中的内容动 态显示实现,根据下拉列表值的不同,显示出不同控件。在 JavaScript 脚本中应用 document.all.GY 可以获得一个对象,此处的 GY 是存放关键字输入框的单元格的 id 值,此时可以任意修改这个值。应用下拉列表的 onChange 事件,来调用自定义函数。  注意 如果在 JavaScript 脚本中出现长语句,可以在 JavaScript 语句的最后加上字符“\”, 使一条长语句分多行编写。 控制下拉列表内容动态显示的 JavaScript 脚本的完整代码如下: 当查询页面被加载时,先将下拉列表需要的数据从数据库中检索出来,并传递给一个 JavaScript 脚本对象,然后再由 JavaScript 脚本来控制下拉列表内容的显示。实现下拉列表 相关属性设置的程序代码如下: ⋯⋯ ⋯⋯ 3.16 程序调试及错误处理 笔者在开发动态网站时,经常会遇到这样的问题:在对数据库进行添加时,例如在天 下鲜美食网中进行名店加盟信息添加时,会出现图 3.36 所示的错误提示信息。 图 3.36 名店加盟信息添加时出现的错误 140 SQL Server 2005 数据库系统开发案例精选 看到类似的问题,读者可能会无从下手。要解决问题就要先找到出现问题的代码,从 上面的错误提示中可以看出,问题出现在 modify\League\tre_tre_Default.asp 文件的第 36 行, 程序代码如下: <% Sql = "Insert Into tb_League(Com_Name,Com_Address,Linkman,Com_Tel,TraitFood,Com_Email,Com_Web, Com_Introduce)"_ &" Values(’"&getcomname&"’,’"&getcomaddr&",’"&getlinkman&"’,’"&gettelepho&"’,’"&gettrait&"’, ’"&getemail&"’"_ &",’"&getwebaddr&"’,’"&getintroduce&"’)" %> 从上面的代码中要真正找到问题所在,有一些困难。此时,读者可以在代码 rs.open sql,conn 的上面插入如下代码,将字符串 sql 输出。 <% Response.Write(sql) Response.End() %> 此时再运行程序,将显示图 2.37 所示的 SQL 语句。 此处少一个单引号 图 3.37 调试时输出的 SQL 语句 从图 3.37 所示的 SQL 语句中,可以看出字符串“吉林长春”后面少一个单引号,只 要在代码中将其加入即可。修改后的代码如下。 <% Sql = "Insert Into tb_League(Com_Name,Com_Address,Linkman,Com_Tel,TraitFood,Com_Email,Com_ Web,Com_Introduce)"_ &" Values(’"&getcomname&"’,’"&getcomaddr&"’,’"&getlinkman&"’,’"&gettelepho&"’,’"&gettrait&"’, ’"&getemail&"’"_ &",’"&getwebaddr&"’,’"&getintroduce&"’)" %>  注意 最后,不要忘记将刚刚加入的调试代码删除。 4 电子商城 开发导读 实例说明  实例名称:电子商城。  实例路径:光盘\mingrisoft\ 电子商城。  实例运行文件:光盘\mingr- isoft\电子商城\index.asp。  用户名:mr。  密码:mrsoft。  用户在使用本实例前,请仔细 阅读光盘中的光盘使用说明、 程序界面修改配置说明书、安 装说明书、使用说明书,这样 可以使您更好地学习和使用本 实例。 在计算机中使用本章实例的源程序时,用户需安 装 Dreamweaver MX 或其他网页开发工具。 本实例数据库为 SQL Server 2005,使用本实例 前,请安装 SQL Server 2005。安装时,验证模式为 混合模式,用户名为 sa,密码为空。 本实例提供了 5 套程序背景和素材,有些格式需 要使用特殊软件处理。 JPG/GIF 文件,如要修改其文件,需要安装 Photoshop 编辑软件。 142 SQL Server 2005 数据库系统开发案例精选 本案例由多个界面组成,下面仅列出几个典型界面,其他界面请参见光盘中的源程序。 首页 排行榜商品详细页面 商品详细信息页面 投票结果显示页面 商城公告详细信息页面 会员资料管理页面 购物车管理页面 商品信息管理页面 143 C H A P T E R 4 第 4 章 电子商城 4.1 概 述 电子商务是在互联网开放的网络环境下,基于浏览器/服务器应用方式,实现消费者网 上购物、商户之间网上交易和在线电子支付的一种新型的商业运营模式,给人们的生活带 来了巨大的影响。对一个运营商业网站的企业来说,电子商务网站是其生存的理由和基础, 同时也是企业对外展示信息、从事商务活动的窗口。如何设计、建立一个经济、实用、安 全、高效、稳定的网站是每个商业网站必须考虑的问题。 本章中的电子商城系统在提高企业内部管理效率、充分利用企业内部资源的基础上, 从整体上降低了成本,加快了对市场的反应速度,提高了服务质量和企业的竞争力。 4.2 系 统 分 析 4.2.1 需求分析 通过对一些典型电子商城网站的考察、分析以及实际的市场调查,要求本系统具有以 下功能。  统一友好的操作界面,能保证系统的易用性。  规范、完善的基础信息设置。  实现相关商品信息的添加、删除、查询。  按商品分类及商品名称进行模糊查询。  实现网上购物功能。  新商品及特价商品展示。  商品销售排行榜。  网站商城动态公告。 4.2.2 可行性分析 商业企业在运营过程中,经常会受到以下一些条件的限制。  产品的宣传受到限制,采购商或顾客只能通过上门咨询、电话沟通等方式进行各 种信息的获取,受一定的时间与物理空间的局限并且成本较高。  庞大的商业经济周转。  复杂的产品周转渠道。从看样品、谈价格到支付货款等一系列的产品周转渠道过 于复杂,企业与顾客之间缺乏全面的沟通与快捷运营的平台。  商业企业中根据季节的变化,热销商品在销售高峰到来时货源紧张,企业需要实 时了解商品的销售情况,保证热销商品的要货满足率。 因此,企业需要重新认识市场、消费者以及自身市场定位,正确认识电子商城技 术在企业中的重要地位,以少量的时间和资金建立企业信息门户网站并架设一定范围 的商务网络,以此来制定长远发展战略,使企业与顾客间的经济活动变得更灵活、更 主动。 144 SQL Server 2005 数据库系统开发案例精选 4.3 总 体 设 计 4.3.1 项目规划 电子商城系统是一个典型的 ASP 数据库开发应用程序,主要由前台商品展示与后台管 理两部分组成。  前台商品展示 主要包括新品上架、特价商品、销售排行、购物车、用户注册、商品动态公告及订单 查询、商品分类查询等。  后台管理 主要对商城内的一些基础数据进行有效管理,包括商品信息管理、订单管理、商城信 息管理、用户失信及定单管理、会员资料管理。 4.3.2 系统功能结构图 电子商城系统前台功能结构如图 4.1 所示。 图 4.1 系统前台功能结构图 电子商城系统后台功能结构如图 4.2 所示。 图 4.2 系统后台功能结构图 145 C H A P T E R 4 第 4 章 电子商城 4.4 系 统 设 计 4.4.1 设计目标 对于典型的数据库管理系统,尤其是像电子商城这样的数据流量特别大的网络管理系 统,必须要满足使用方便、操作灵活等设计需求。本系统在设计时应该满足以下几个目标。  采用人机对话的操作方式,界面设计美观友好、信息查询灵活、方便、快捷、准 确、数据存储安全可靠。  全面展示商城内所有商品,并可展示最新商品及特价商品。  为顾客提供一个方便、快捷的商品信息查询功能模块。采用模糊查询方式查询数据。  实现网上购物。  商品销售排行,以方便顾客了解本商城内的热销商品。  查看商城内的公告信息。  系统最大限度地实现了易操作性和易维护性。  系统运行稳定、安全可靠。 4.4.2 开发及运行环境 硬件平台:  CPU:Pentium Ⅲ及其兼容处理器,建议主频 600MHz 或更高。  内存:512MB 以上。 软件平台:  操作系统:Windows 2000 Server SP4、Windows 2000 Advanced Server SP4、Windows 2000 Data Center Server SP4、Windows Server 2003 SP1、Windows 2003 企业版 SP1、Windows 2003 数据中心版 SP1。  数据库:SQL Server 2005。  浏览器:IE 5.0,推荐使用 IE 6.0。  Web 服务器:IIS 5.0。  分辨率:最佳效果 1024×768 像素。 4.4.3 Windows 2000 的 IIS 配置 1.安装 IIS 进入“控制面板”,依次选择“添加/删除程序”→“添加/删除 Windows 组件”,勾选 “Internet 信息服务(IIS)”项,单击【下一步】按钮,即可完成 IIS 组件的添加。用这种方 法添加的 IIS 组件中将包括 Web、FTP、NNTP 和 SMTP 等服务。 2.IIS 的配置 如本机的 IP 地址为 192.168.0.1,自己的网页存储在 E:\mingrisoft 路径下,网站的首页 文件名为 index.asp,则配置 IIS 的步骤如下。 (1)进入设置:首先在“默认 Web 站点”上单击鼠标右键,选择“属性”选项,进入 146 SQL Server 2005 数据库系统开发案例精选 “默认 Web 站点属性”设置窗口,如图 4.3 所示。 (2)修改 IP 地址:单击“Web 站点”选项 卡,在“IP 地址”后的下拉列表中选择本机 IP 地址“192.168.0.1”。 (3)修改主目录:单击“主目录”选项卡, 在“本地路径”文本框中输入或单击【浏览】 按钮选择网页所在的路径 E:\mingrisoft,如图 4.4 所示。 (4)设置默认文档:单击“文档”选项卡 中的【添加】按钮,根据提示在“默认文档名” 文本框中输入网页的首页文件名 index.asp,如 图 4.5 所示。 (5)效果的测试:打开 IE 浏览器,在地址 栏中输入 192.168.0.1 之后,按〈Enter〉键,此 时就能够打开个人网页的首页,说明 IIS 配置成功! 图 4.4 “主目录”选项卡 图 4.5 “文档”选项卡 4.5 数据库设计 本系统数据库采用 SQL Server 2005 数据库,系统数据库名称为 db_shop。数据库 db_shop 中包含 10 张表。下面分别给出主要数据表的实体 E-R 图、主要数据表结构及数据 表概要说明。 4.5.1 数据表的实体 E-R 图 根据数据表结构的设计,规划出相应的实体 E-R 图,这些实体中包含各种具体信息, 并通过相互之间的作用形成数据的流动。具体数据表的实体 E-R 图描述如下。 图 4.3 “Web 站点”选项卡 147 C H A P T E R 4 第 4 章 电子商城 图 4.6 为投票信息实体 E-R 图。 投票结果1 投票信息实体 投票结果2 投票结果3 投票结果4 图 4.6 投票信息实体 E-R 图 图 4.7 为消费积分信息实体 E-R 图。 消费积分计算参数 消费积分信息实体 消费积分对应折扣比率计算参数 消费积分对应会员等级计算参数 会员的失信上限 图 4.7 消费积分信息实体 E-R 图 图 4.8 为商品类型信息实体 E-R 图。 图 4.9 为商品等级信息实体 E-R 图。 商品类型名称 商品类型信息实体 所属类型商品类型编号 等级名称 商品等级信息实体 等级条件商品等级编号 图 4.8 商品类型信息实体 E-R 图 图 4.9 商品等级信息实体 E-R 图 4.5.2 主要数据表的结构 由于文章的篇幅所限,在此只给出较为重要的数据表,其他数据表请参见本书附带的光盘。  tb_Member(会员注册信息表) 会员注册信息表主要用来保存会员注册信息,生成订单内的收货人信息时,也应用该 表。该表的结构如表 4.1 所示。 表 4.1 tb_Member 表的结构 字 段 名 数 据 类 型 长 度 主 键 否 描 述 ID int 4 是 惟一标识 Name varchar 30 否 账户名称 Sex varchar 10 否 性别 Password varchar 30 否 登录密码 Question varchar 200 否 密码提示问题 Email varchar 200 否 邮箱地址 RealName varchar 50 否 用户真实姓名 Country varchar 50 否 年龄 148 SQL Server 2005 数据库系统开发案例精选 续表 字 段 名 数 据 类 型 长 度 主 键 否 描 述 Phone varchar 30 否 联系电话 Address varchar 150 否 联系地址 LicenceNumber varchar 30 否 证件号码 Whether varchar 50 否 账户状态  tb_Account(会员账户信息表) 会员账户信息表主要用于保存会员在商城内的消费信息。该表的结构如表 4.2 所示。 表 4.2 tb_Account 表的结构 列 名 数 据 类 型 长 度 主 键 否 描 述 ID int 4 是 惟一标识 Name varchar 30 否 账户名称 Password varchar 30 否 登录密码 Amount float 8 否 消费总额 Degree int 4 否 消费次数 Agio float 8 否 打折比率 Integral float 8 否 消费积分 FeelBack int 4 否 失信次数 Step varchar 50 否 会员等级 Whether varchar 50 否 账户状态  tb_Goods(商品信息表) 商品信息表主要用于保存商品信息。该表的结构如表 4.3 所示。 表 4.3 tb_Goods 表的结构 列 名 数 据 类 型 长 度 主 键 否 描 述 ID int 4 是 惟一标识 Name varchar 100 否 商品名称 Vendibility float 8 否 市场价 Memberprice float 8 否 会员价 Picture varchar 100 否 图片信息地址 Reside varchar 100 否 所属分类 Remark varchar 200 否 备注信息 Sell int 4 否 销售量 Style varchar 20 否 销售类型 Groom varchar 10 否 推荐参数  tb_OrderForm(订单信息表) 订单信息表主要用于保存订单信息。该表的结构如表 4.4 所示。 表 4.4 tb_OrderForm 表的结构 列 名 数 据 类 型 长 度 主 键 否 描 述 ID int 4 是 惟一标识 Number Varchar 30 否 订单号码 GoodsName Varchar 1000 否 商品名称 149 C H A P T E R 4 第 4 章 电子商城 续表 列 名 数 据 类 型 长 度 主 键 否 描 述 GoodsNumber Varchar 800 否 商品数量 Memberprice Varchar 1000 否 会员价格 Agio Varchar 500 否 打折比率 Amount float 8 否 收款总额 SendStyle Varchar 100 否 运输类型 UserName Varchar 50 否 接收人姓名 UserPhone Varchar 50 否 接收人电话 UserEmail Varchar 150 否 接收人邮箱地址 UserAddress Varchar 300 否 接收人地址 Remark Varchar 1000 否 备注 SendMoney Varchar 100 否 付款方式 Status Varchar 100 否 订单状态 Reason Varchar 500 否 作废原因 IssueDate datetime 8 否 发布时间 4.5.3 数据表概要说明 从读者角度出发,为了使读者对本系统后台数据库中数据表有一个清晰的认识,笔者 在此特设计一个数据表树型结构图,该数据表树型结构图包含系统中所有数据表,如图 4.10 所示。 图 4.10 数据表树型结构图 4.6 技 术 准 备 4.6.1 读者知识要求 要很好地学习本案例,读者需要熟悉 SQL Server 2005 数据库的基本操作及 SQL 查询 语句的应用格式,还需要掌握 IIS 的相关配置。 150 SQL Server 2005 数据库系统开发案例精选 4.6.2 命名规则 1.VBScript 编码约定 编码约定是帮助开发者使用 Microsoft Visual Basic Scripting Edition 编写代码的一些建 议,编码约定包含以下内容。  对象、变量和过程的命名约定。  注释约定。  文本格式和缩进指南。 使用一致的编码约定的主要原因是使 Script 或 Script 集的结构和编码样式标准化,可 以使源代码易读、准确、更加直观且与其他语言约定保持一致,便于代码的阅读、理解和 分析。 2.描述性变量名和过程名 变量名或过程名的主体应使用大小写混合格式,并且尽量完整地描述其目的。另外, 过程名应以动词开始,例如 ShowFolderList。 对于经常使用的或较长的名称,推荐使用标准缩写以使名称保持在适当的长度内,通 常多于 32 个字符的变量会变得难以阅读。使用缩写时,应确保在整个 Script 中保持一致。 例如,在一个 Script 或 Script 集中随意切换 Cnt 和 Count 将造成混乱。 3.对象命名约定 表 4.5 中列出 VBScript 中常用的对象命名约定。 表 4.5 象名约定 对 象 类 型 前 缀 示 例 复选框 Chk ChkReadOnly 下拉列表框 Cbo CboEnglish 命令按钮 Cmd CmdExit 框架 Fra Fraleft 图像 Img ImgIcon 标签 Lbl LblHelpMessage 列表框 Lst LstPolicyCodes 文本框 Txt Txtusername 4.代码注释约定 所有过程的开始部分都应有描述其功能的简要注释。这些注释并不描述细节信息(如 何实现功能),这是因为细节有时频繁更改。这样可以避免产生不必要的注释维护工作以及 错误的注释。细节信息由代码本身及必要的内部注释来描述。 当传递给过程的参数的用途不明显,或过程参数的取值范围有要求时,应加以说明。 如果过程改变了函数和变量的返回值(此时通过参数引用来改变),也应在过程的开始部分 描述该返回值。 151 C H A P T E R 4 第 4 章 电子商城 过程开始部分注释应包含以下区段标题,如表 4.6 所示。 表 4.6 代码注释约定 区 段 标 题 注 释 内 容 目的 过程的功能(不是实现功能的方法) 假设 其状态影响此过程的外部变量、控件或其他元素的列表 效果 过程对每个外部变量、控件或其他元素的影响效果的列表 输入 每个目的不明显的参数的解释,每个参数都应占据单独一行有其内部注释 返回 注释内容  注意  每个重要的变量声明都应有内部注释,描述变量的用途。  应正确地对变量、控件和过程命名。  应在 Script 的开始部分包含描述该 Script 的概述,列举对象、过程、运算法则、 对话框和其他系统从属物。  格式化代码。  应尽可能多地保留屏幕空间,但仍允许用代码格式反映逻辑结构和嵌套。 4.6.3 文件管理规划 在置身于编码设计前,可先将网站中可能应用到的文件夹创建出来。例如创建一个 名为 Conn 的文件夹,该文件夹主要用于保存网站中数据库的连接文件。既方便以后的 开发工作,又可规范网站整体结构,可谓一举两得。笔者在开发电子商城时,首先设计 了图 4.11 所示的文件夹结构图,在开发时只需将文件保存在相应的文件夹中即可,非 常方便。 图 4.11 文件管理规划 152 SQL Server 2005 数据库系统开发案例精选 4.7 前台主要功能模块详细设计 4.7.1 前台文件总体架构 前台页面主要包括以下功能模块。  网站导航:主要包括网站的旗帜广告条、功能分类导航和下列菜单导航 3 部分。  新品上架:主要用于显示新商品。  购物车:主要包括添加购物车、修改购物车中商品的数量、从购物车中移除商品、 清空购物车、收银台付款 5 部分。  账户管理:主要用于查看会员的相关信息。  订单查询:主要用于查询指定编号的订单信息。  销售排行:主要用于对商城中销售的商品进行排行,以方便用户查看商城中的热 销商品。  退出:主要用于退出会员登录、购买商品两部分。  商城调查:主要用于统计浏览者对电子商城网站的满意程度。  后台登录入口:主要为管理员进入后台管理提供一个入口。 4.7.2 文件架构 电子商城管理系统的前台文件架构如图 4.12 所示。 图 4.12 文件架构图 4.7.3 前台页面的运行结果 前台页面的运行结果如图 4.13 所示。 153 C H A P T E R 4 第 4 章 电子商城 1 2 3 4 6 5 7 8 图 4.13 前台页面运行结果 为了方便读者阅读和有效利用本书附赠光盘的实例,笔者将网站页面的各部分说明以 列表形式给出,如表 4.7 所示。 表 4.7 网站前台首页解析 区 域 名 称 说 明 对 应 文 件 1 网站导航 主要用于显示当前网站的旗帜广告条以及为浏 览者提供网站的功能导航 Index.asp 2 会员登录 主要用于会员登录、注册 Login.asp Online.asp Unonline.asp 3 商城公告 主要用于展示商城内最新公告信息 Index.asp 4 销售排行 主要用于展示商城中销售最高的 6 种商品名称 Index.asp 5 商城调查 主要用于调查浏览者对网站的信誉度 Left.asp 6 商品查询 主要用于对商品进行分类查询 Search/index.asp 7 商品展示 主要用于展示商城最新上市的商品 New_Ware/Index.asp 8 版权信息区 主要用于展示网站的版权信息及为后台登录提 供入口 Bottom.asp 154 SQL Server 2005 数据库系统开发案例精选 4.8 会员管理模块设计 会员管理模块主要包括会员登录、会员注册两 个部分。在会员登录页面中,当用户正确输入用户 名、密码后,按〈Enter〉键可直接以会员身份登录 该网站。在会员管理模块中,单击【注册】按钮进 入会员注册页面。在本案例中主要通过分步式会员 注册的方法完成会员注册操作。会员登录管理页面 的文件架构如图 4.14 所示。 4.8.1 会员注册模块 在电子商城中,只有成为了会员才可以购物,当没有注册的用户单击【购买】按钮或 单击“购物推车”超链接时,将提示错误信息。为方便用户注册,在首页中提供了用户注 册按钮。用户单击【注册】按钮,首先进入到服务条款页,避免以后发生经济及服务纠纷。 当用户阅读完服务条款,单击【我同意】按钮时,此时才真正进入到注册页面。注册页面 主要实现以下功能。  检查用户输入信息的正确性。  提示注册是否成功的信息。  保存会员信息。  根据会员注册的用户名自动生成会员账户信息并初始化。  返回首页并自动登录。 会员注册页面的设计效果如图 4.15 所示。 图 4.15 会员注册页面设计效果 会员注册页面所涉及的 HTML 表单元素如表 4.8 所示。 当用户提交注册信息后,首先检查用户输入的信息是否正确,如果用户信息正确,此 时将进入 Data.asp 页,该页主要将用户的注册信息存入到数据库中。在存入信息时,首先 判断该用户名是否已存在,如果已存在,系统将给予相关提示信息,否则将用户信息存入 到指定的数据表中。其相关程序代码如下: 图 4.14 会员登录文件架构图 155 C H A P T E R 4 第 4 章 电子商城 表 4.8 会员注册页面所涉及的 HTML 表单元素 名 称 类 型 含 义 重 要 属 性 form1 Form 表单 action="Reg/Data.asp" method="post" id="form1" name text 用户名 sex radio 男 sex radio 女 psw password 密码(至少 6 位) pswc password 确认密码(至少 6 位) quesion text 密码问题 answer text 问题答案 e_mail text E-mail 地址 realname text 真实姓名 number text 身份证号码 address text 通信地址 userphone text 联系电话 Submit button 【注册】按钮 Submit2 reset 【重置】按钮 <%  names=request.form("name") sql="select * from tb_Member where Name=’"&names&"’" rs.open sql,conn if not rs.eof or not rs.bof then %> <% else %> <% set rs=nothing conn.close set conn=nothing %> <% 156 SQL Server 2005 数据库系统开发案例精选 sex=request.form("sex") pwd=request.form("psw") wenti=request.form("quesion") da_an=request.form("answer") email=request.form("e_mail") realname=request.form("realname") country=request.form("country") phone=request.form("userphone") numbers=request.form("number") add=request.form("address") sql="insert into tb_Member values(’"&names&"’,’"&sex&"’,’"&pwd&"’,’"&wenti&"’,’"&da_an&"’,’"&email&"’,’"&realname&"’,’"&country&" ’,’"&phone&"’,’"&add&"’,’"&numbers&"’,’未冻结’)" rs.open sql,conn  sql="insert into tb_Account(Name,Password) values(’"&names&"’,’"&pwd&"’)" rs.open sql,conn %> <% set rs=nothing conn.close set conn=nothing ’登录用户的用户名参数  session("name")=names ’登录用户的账户中的积分参数 session("Integral")="0" session("jifen")=0 session("step")="普通会员" ’代表用户第一次登录的参数 session("first")="ok" ’代表登录是否成功的参数 session("meg")="ok" %> <% end if %>  代码导读  request 对象: request 对象主要用于读取客户端传送给服务器的值,通常由客户端向 Web 服务器提出请求,Web 服务器才会响应信息。  insert into…values…:主要应用 insert 语句将记录添加到指定的数据表中。  Session 变量:在 ASP 中使用 Session 是十分方便的,可以利用 Session 对象对某一 个 Session 实例进行全面的控制。如果需要在一个用户的 Session 中存储信息,直接调用 Session 对象就可以了。语法格式如下。 <% Session(变量名称)=变量值 ’创建 Session 变量 Sessiion(变量名称字符串) ’取得 Session 变量值 %> 会员注册页面的运行结果如图 4.16 所示。 通过 Insert 语句向指定 的数据表中插入记录 157 C H A P T E R 4 第 4 章 电子商城 图 4.16 会员注册页面的运行结果 4.8.2 会员登录模块 当会员注册成功后,需要会员登录才可以进行购物。 在会员登录模块中输入正确的用户名、密码后,单击【登 录】按钮,即可成功登录。会员登录页面的设计效果如图 4.17 所示。 会员登录页面所涉及的 HTML 表单元素如表 4.9 所示。 表 4.9 会员登录页面所涉及的 HTML 表单元素 名 称 类 型 含 义 重 要 属 性 userlogin Form 表单 username text 用户名 userpassword password 密  码 Submit1 submit 【登录】按钮 Submit2 button 【注册】按钮 在输入正确的用户名、密码后,将进入 Check.asp 页,该页主要用于判断输入的用户 名、密码是否正确,同时判断该用户是否被冻结。程序代码如下。 图 4.17 会员登录模块设计效果 158 SQL Server 2005 数据库系统开发案例精选 <% if request.Form("username")<>"" then if request.Form("userpassword")<>"" then names=request.Form("username") pwd=request.Form("userpassword") sql="select * from tb_Account where Name=’"+names+"’" rs.open sql,conn if rs.bof or rs.eof then session("meg")="namewrong" response.redirect("../index.asp") else  while not rs.eof password=rs("Password")  if pwd<>password then session("meg")="pwdwrong" response.redirect("../index.asp") else if rs("Whether")="已冻结" then session("meg")="shixin" response.redirect("../index.asp") else if rs("FellBack")>=session("fellback") then session("meg")="shixin1" response.redirect("../index.asp") else session("name")=names session("jifen")=rs("Integral") session("step")=rs("Step") session("meg")="ok"  response.redirect("../index.asp") end if end if end if wend end if else session("meg")="kong" response.Redirect("../index.asp") end if else session("meg")="namekong" response.Redirect("../index.asp") end if %>  代码导读  While...Wend 语句:当指定的条件为 True 时,执行一系列的语句。  If...Then...Else 语句:根据表达式的值有条件地执行一组语句。  Redirect 方法:Redirect 方法也是 Response 的常用方法。Redirect 方法使浏览器立 即重定向到程序指定的 URL。如果需要把网页转移到一个新的 URL,但又不想麻烦用户 去点击或搜索该 URL,此时可以使用该方法使用户浏览器直接重定向到新的 URL。 主要用于判断用户 名、密码是否为空 159 C H A P T E R 4 第 4 章 电子商城 4.9 商城调查模块设计 在商城的首页,设有商城可信度调查的投票系统。无论是不是会员,都可以通过单击 【投票】按钮参与投票,也可以直接单击【投票结 果】按钮查看投票统计结果。投票系统主要实现 以下功能。  收集用户的投票信息。  用户查看投票统计结果。  投票结果以图形方式显示。 用户投票页面的设计效果如图 4.18 所示。 用户投票页面所涉及的 HTML 表单元素如表 4.10 所示。 表 4.10 用户投票页面所涉及的 HTML 表单元素 名 称 类 型 含 义 重 要 属 性 research from 表单 research2 from 表单 Options radio 1.非常值得信赖 Options radio 2.比较可信 Options radio 3.没什么感觉 Options radio 4.完全不可信 Submit42 Submit 【投票】按钮 Submit33 Submit 【投票结果】按钮 用户投票结果页面的设计效果如图 4.19 所示。 图 4.19 用户投票结果页面的设计效果 在制作显示投票结果页面时,首先根据传递的参数判断用户执行的是投票操作,还是 查看投票结果操作,如果传递的参数不为空,则说明查看投票结果操作,只需以图片的形 式显示投票结果,否则执行投票操作。 图 4.18 用户投票页面的设计效果 160 SQL Server 2005 数据库系统开发案例精选 在执行投票操作时,有一点必须考虑,那就是避免重复投票的问题,在本例中是这样 解决的:在每个投票者进行投票时,首先判断 Cookies 中是否有该投票者的 IP 地址,如果 有则给予提示并禁止其投票,否则将保存投票信息并将其 IP 地址导入客户端的 Cookies 中, 最后以图片的形式显示投票结果。程序代码如下: <%  if request.QueryString("stype")="" then  if Request.ServerVariables("REMOTE_ADDR")=request.cookies("IPAddress") then response.write"" else options=request.form("Options")  response.cookies("IPAddress")=Request.ServerVariables("REMOTE_ADDR") conn.execute("update tb_Vote set Option"&options&"=Option"&options&"+1") conn.close set conn=nothing end if end if select1="1.非常值得信赖" select2="2.比较可信" select3="3.没什么感觉" select4="4.完全不可信" %> 162 SQL Server 2005 数据库系统开发案例精选
 
<% sql="select * from tb_Vote" rs.open sql,conn while not rs.eof %> <% an1=int(rs("Option1")) an2=int(rs("Option2")) an3=int(rs("Option3")) an4=int(rs("Option4")) 将网站信任度投票 结果输出到浏览器 161 C H A P T E R 4 第 4 章 电子商城 answer=an1+an2+an3+an4 rs.movenext wend %>
  网站信任度 投票结果
序号 百比分 人数
<%=select1%>: % height=20>
<%=round(an1*100/answer,2)%>%
<%=an1%>人
<%=select2%>: % height=20> 
<%=round(an2*100/answer,2)%>%
<%=an2%>人
<%=select3%>: % height=20>
<%=round(an3*100/answer,2)%>%
<%=an3%>人
<%=select4%>: % height=20>
<%=round(an4*100/answer,2)%>%
<%=an4%>人
共有【<%=answer%>】人参加投票

返回首页】 <% set rs=nothing conn.close set conn=nothing %>

 
 代码导读  QueryString 集合:QueryString 集合获取作为跟在请求的 URL 的问号后面的文本传 递给 Web 服务器的值。  ServerVariables 集合:使用 ServerVariables 集合的成员,可以获取有关发出请求的 浏览器的类型的信息、请求者的 IP 地址、构成请求的 HTTP 方法以及 ASP 脚本参与的 HTTP 事务的其他重要数据。  Cookies 集合:Cookies 不仅是 Response 的一个集合,也是 Request 的一个集合。 主要应用 Cookies 集合取得在 HTTP 请求中发送的 Cookie 的值。这项功能经常在客户身 份认证、电子公告板、聊天室等 Web 应用程序中使用。  /运算符:主要用于对两个数值相除并返回以浮点数表示的结果。  Round 函数:主要用于返回按指定位数进行四舍五入的数值。  Int 函数:主要用于返回数字的整数部分。 用户投票结果页面的运行结果如图 4.20 所示。 图 4.20 用户投票结果页面的运行结果 4.10 购物车模块设计 购物车主要包括所选商品的添加、查看购物车、单件商品购买数量的修改、从购物车 移去指定商品、清空购物车 5 部分。用户登录后,单击商品展示区内的“购买”按钮,可 以将对应的商品添加至购物车,购物车中将保存商品的 ID 号、商品名称、单价、购买数量、 单种商品的金额以及购物车内全部商品的合计金额。在查看购物车页面中,单击“删除” 按钮可以从购物车中移去指定商品;单击“修改”按钮即可修改指定商品的购买数量;单 击“清空购物车”超链接,将退回购物车中的全部商品;如果用户确认购买当前购物车中 的全部商品,可以单击“收银台付款”超链接,进行订单处理。购物车页面的文件架构如 163 C H A P T E R 4 第 4 章 电子商城 图 4.21 所示。 图 4.21 购物车页面文件架构图 4.10.1 添加商品至购物车 添加商品至购物车页面主要用于将商品信息暂时保存到购物车中,主要用来帮助用户 完成商品的选购。单击【购买】按钮,即可将商品添加到购物车中。相关程序代码如下。 <% if session("name")="" then %> <% else %> <% if request.QueryString("chakan")<>"" then shuzu=session("array")  if not isarray(shuzu) then response.Write("") else response.redirect("../index.asp?action=trade") end if else id=request.Form("id") sql="select * from tb_Goods where ID="&id rs.open sql,conn if not rs.eof then names=rs("Name") price=rs("MemberPrice") 164 SQL Server 2005 数据库系统开发案例精选 end if  dim ary() dim ary2() dim ary3() shuzu=session("array") if isarray(shuzu) then ry=session("array") ry2=session("array2") ry3=session("array3") leng=ubound(ry) for i=0 to leng-1 if ry(i)=names then oknum=1 end if next if oknum<>1 then redim ary(leng+1) redim ary2(leng+1) redim ary3(leng+1) ary(leng)=names ary2(leng)=int(price) ary3(leng)=1  for i=0 to leng-1 ary(i)=ry(i) ary2(i)=ry2(i) ary3(i)=ry3(i) next else redim ary(leng) redim ary2(leng) redim ary3(leng) names=names for i=0 to leng-1 if ry(i)=names then ry3(i)=ry3(i)+1 end if next for i=0 to leng-1 ary(i)=ry(i) ary2(i)=ry2(i) ary3(i)=ry3(i) next end if else redim ary(1) redim ary2(1) redim ary3(1) ary(0)=names ary2(0)=int(price) ary3(0)=1 end if session("array")=ary session("array2")=ary2 session("array3")=ary3 response.Redirect("../index.asp?action=trade") end if %> <% 判断同种商品 是否已经购买 判断同种商品已经存在,则将商品的购买 数量加 1,而不添加新的商品购买信息 进入购物车查看页面 165 C H A P T E R 4 第 4 章 电子商城 end if %> 技术细节 ReDim 语句用于过程级声明动态数组变量并分配或重新分配存储空间。语法如下。 ReDim [Preserve] varname(subscripts) [, varname(subscripts)] . . . 其中,Preserve 表示当更改现有数组最后一维的大小时保留数据;varname 变量名遵 循标准变量命名约定;subscripts 表示数组变量的维数,最多可以声明 60 维数组。可以重 复使用 ReDim 语句更改数组维数和元素数目。 如果使用了 Preserve 关键字,就只能调整数组最后维的大小,并且不能改变数组的维 数。例如,如果数组只有一维,就可以修改该数组的大小,因为该维是最后的也是仅有的 一维。但是,如果数组有两个或更多维,就只能改变末维的大小并保留数组内容。 下面的样例示范了如何不删除动态数组的原有内容而又增加末维的大小。 ReDim X(10, 10, 10) ReDim Preserve X(10, 10, 15) 注意:如果减小数组的大小,则将丢失被排除的元素中的数据。变量初始化时,数值 变量初始化为 0,字符串变量初始化为零长度字符串 ("")。在使用引用对象的变量前,必 须使用 Set 语句将某个现有对象赋予该变量。在进行对象赋值以前,已声明的对象变量有 特定值 Nothing。  代码导读  IsArray 函数:主要用于返回 Boolean 值指明某变量是否为数组。  Dim 语句:主要用于声明变量并分配存储空间。  For...Next 语句:主要用于以指定次数重复执行一组语句。 4.10.2 查看购物车 为了方便用户随时查看购物车情况,在添加至购物车页面中单击“购买”按钮,即可 打开“查看购物车”页面。该页面可以查看已经放入购物车内的所有商品信息。 在实现查看购物车时,首先需要判断购物车是否为空,如果为空,需要将页面重定向 到购物车首页面;否则显示购物车信息,主要是将保存在 session 中的购物信息利用 For 循 环语句输出到浏览器中。主要程序代码如下。 166 SQL Server 2005 数据库系统开发案例精选 <% ary=session("array") ary2=session("array2") ary3=session("array3") if isarray(ary) then leng=ubound(ary) for i=0 to leng-1 %> <% sum=sum+ary2(i)*ary3(i)%> <% next %> <% select case session("step") case "普通会员" agio=100 case "三级会员" agio=95 case "二级会员" agio=90 case "一级会员" agio=80 case "VIP会员" agio=65 case "终身会员" agio=50 end select %> <% else %> 根据会员等级折算 商品的打折比率 167 C H A P T E R 4 第 4 章 电子商城 <% end if %> 技术细节 UBound 函数用于返回指定数组维数的最大可用下标。语法如下。 UBound(arrayname[, dimension]) 其中 Arrayname 为必选项,数组变量名遵循标准变量命名约定;dimension 为可选项, 指定返回哪一维上界的整数。1 表示第一维,2 表示第二维,以此类推。如果省略 dimension 参数,则默认值为 1。 UBound 函数与 LBound 函数一起使用,用于确定数组的大小。使用 LBound 函数可 以确定数组某一维的下界。 例如: Dim A(100,5,2) ’定义数组 A 则利用 UBound 函数返回数组 A 最大可用下标如下。 UBound(A, 1) ’返回值为 100 UBound(A, 2) ’返回值为 5 UBound(A, 3) ’返回值为 2 查看购物车页面的运行结果如图 4.22 所示。 图 4.22 查看购物车页面的运行结果 168 SQL Server 2005 数据库系统开发案例精选 4.10.3 从购物车中移去指定商品及清空购物车 在购物过程中,顾客经常需要将已经选择的商品退回到货物架上。在开发一个电子商 城网站时,首先必须要考虑到这一点,做好需求分析,从而使自己的网站更加完善。本实 例在设计购物车时,在查看购物车页面中添加一个将指定商品退回的功能,即从购物车中 移去指定商品。 通过在“删除”图片上添加超链接文件,传递商品的 ID 号作为参数。相关代码如下: 通过以下程序代码实现从购物车中移去指定商品及清空购物车,程序相关代码如下: <%@LANGUAGE="VBSCRIPT" CODEPAGE="936"%> <% if request.QueryString("id")="" then session("array")="" session("array2")="" session("array3")="" response.redirect("../index.asp?action=trade") else id=int(request.QueryString("id")) ary=session("array") ary2=session("array2") ary3=session("array3") leng=ubound(ary) if leng=1 then session("array")="" session("array2")="" session("array3")="" response.redirect("../index.asp?action=trade") else redim ry(leng-1) redim ry2(leng-1) redim ry3(leng-1) ary(id)=ary(leng-1) ary2(id)=ary2(leng-1) ary3(id)=ary3(leng-1) for i=0 to leng-2 ry(i)=ary(i) ry2(i)=ary2(i) ry3(i)=ary3(i) next session("array")=ry session("array2")=ry2 session("array3")=ry3 response.redirect("../index.asp?action=trade") end if end if %> 4.10.4 修改购物车中指定商品的购买数量 为了满足用户的不同需求,购物车中还需加入修改指定商品购买数量的功能。在购物 车中,由于商品的数量被存放在文本框里,用户只需在某种商品后面的文本框中输入相应 判断原有商品的数量,如果只有一 件商品,则直接将购物车清空,如 果有多件商品,则删除对应的商品 169 C H A P T E R 4 第 4 章 电子商城 的数量,然后单击【确认】按钮即可提交表单修改购买商品数量。修改购物车中指定商品 的购买数量页面的设计 效果如图 4.23 所示。 图 4.23 修改购物车中指定商品的购买数量 修改购物车中指定商品的购买数量页面所涉及的 HTML 表单元素如表 4.11 所示。 表 4.11 修改页面所涉及的 HTML 表单元素 名 称 类 型 含 义 重 要 属 性 form1 Form 表单 name2 text 商品名称 name hidden 隐藏域 jiage text 单件商品价格 number text 您的购物数量 id hidden 隐藏域 Submit button 【确认】按钮 Submit2 button 【返回】按钮 在查看购物信息页面中,单击【修改】按钮进入购物信息修改页面。在该页面中可以 对指定商品的购买数量进行修改,在“购买数量”文本框中输入所需的数量后,单击【确 认】按钮即可完成数量修改操作。相关程序代码如下: <% if request.Form("name")<>"" then id=request.Form("id") num=request.Form("number") ary=session("array3") ary(id)=num session("array3")=ary %> <% 170 SQL Server 2005 数据库系统开发案例精选 else %> 购物信息修改
您购买的商品清单
商品名称
会员价
数量
总金额
操作
<%=ary(i)%>
<%=ary2(i)%>
<%=ary3(i)%>
<%=ary2(i)*ary3(i)%>
   
   您的应付总金额为<%=sum*agio/100%>(总金额*打折比率)元
您 的 购 物 车 中 没 有 任 何 商 品 !

购物信息修改
 
商品名称:
<% id=request.QueryString("id") ary=session("array") ary2=session("array2") %>
单件商品价格:
您的购物数量:
   
<% end if %> 修改购物车中指定商品的购买数量的运行结果如图 4.24 所示。 图 4.24 修改购物车中指定商品的购买数量 4.11 收银台模块设计 4.11.1 填写订单信息 在查看购物车页面中,单击【收银台付款】按钮,将进入到收银台的订单填写页面。 填写订单信息页面主要实现以下功能。  自动调取用户的注册信息完成订单的初始化。  由用户选择送货方式及付款方式。  显示购物列表。  为用户提供多种付款方式。  用户确认订单信息后,将订单存入数据库,再由管理员执行订单。  自动生成订单号。 一张订单,首先显示的就是用户的购物信息,因为本案例使用 Session 对象存储购物信 息,所以当进入订单页面时,只需调用 Session 对象,并把其中存储的商品信息输入到浏览 器中。关键程序代码如下: <% zu=session("array") zu2=session("array2") zu3=session("array3") if isarray(zu) then lens=ubound(zu) 172 SQL Server 2005 数据库系统开发案例精选 %> <% select case session("step") case "普通会员" agio=100 case "三级会员" agio=95 case "二级会员" agio=90 case "一级会员" agio=80 case "VIP会员" agio=65 case "终身会员" agio=50 end select %> <% for i=0 to lens-1 %> <% sum=sum+int(zu2(i)*zu3(i)) %> <% next %>
您的购物清单
商品名
会员价格
数量
乘以折扣
应付
<%=zu(i)%>
<%=zu2(i)%>元
<%=zu3(i)%>
<%=agio%>%
<%=(zu2(i)*zu3(i)*agio/100)%>
订单页面除了包含用户的购物信息之外,还包含了用户的收货地址、电话、邮箱等信 息,这些信息在用户注册时就已经填写,这里只需调用这些信息。调用方法是:当用户进 行登录之后(本例只有注册用户才可以进行购物),将该用户名赋值给一个 Session 对象, 在订单页面中通过将 Session 对象作为查询条件来检索数据,最后将检索到的数据以表单的 形式输出到浏览器上。填写订单信息的关键代码如下: <% num=request.QueryString("number") sql="select * from tb_OrderForm where Number=’"&num&"’" rs.open sql,conn  if not rs.eof then 173 C H A P T E R 4 第 4 章 电子商城 mingcheng=rs("GoodsName") shuliang=rs("GoodsNumber") danjia=rs("MemberPrice") zhekou=rs("Agio") ming=split(mingcheng,",")  shu=split(shuliang,",") daj=split(danjia,",") %>
<%  for i=0 to ubound(ming)-1 %>  代码导读  EOF 属性:主要用于返回一个布尔型值,用来表示 RecordSet 对象是否到了结果集 的首记录之前,如果当前记录位于 RecordSet 对象首记录之前,则 EOF 返回 True;否则 返回 False。  Split 函数:主要用于返回基于 0 的一维数组,其中包含指定数目的子字符串。 UBound 函数:主要用于返回指定数组维数的最大可用下标。 <% sum=sum+daj(i)*shu(i)*zhekou/100 %> <% next%>
您的购物清单
商品名
会员价格
数量
乘以折扣
应付
<%=ming(i)%>
<%=daj(i)%>
<%=shu(i)%>
<%=zhekou%>%
<%=daj(i)*shu(i)*zhekou/100%>
174 SQL Server 2005 数据库系统开发案例精选

 
购物金额:
<%=sum%>元
 
运费:
<% if rs("SendStyle")="无" then yunshufangshi=0 else yunshufangshi=rs("SendStyle") end if %> <%=yunshufangshi%> 元
 
共计:
<%=rs("Amount")%> 元人民币
 
4.11.2 处理订单信息 当用户填写订单信息并确认订单信息无误之后,单击收银台订单填写页面中的“确定” 按钮,将进入处理订单信息页面。该页面主要实现以下功能。  保存结账信息。  清空购物车。  信息处理完毕后,返回到首页方便用户继续购物。 处理订单页面是 ASP 页,没有浏览器运行效果。 订单信息处理页面将 Session 对象中存放的购物信息转化为字符串,为将其存入数据库 以提供方便。关键代码如下: <% ’获取存放商品名称的数组信息 arys_1=session("array") ’获取存放对应商品价格的数组信息 ary2=session("array2") ’获取对应商品的购买数量的数组信息 ary=session("array3") ’判断用户是否已经购买商品 if isarray(arys_1) then for i=0 to ubound(arys_1)-1 str=str+arys_1(i)+"," str2=str2+cstr(ary(i))+"," str3=str3+cstr(ary2(i))+"," next %> 获取订单填写页面的表单信息的关键代码如下: <% ’提取订单中的参数 yonghu=session("name") jine=request.form("jine") names=request.form("name") addre=request.Form("address") email=request.Form("email") phone=request.Form("phone") meg=request.Form("memo") dingdan=request.Form("hidennumber") fangshi=request.Form("select") yunshu=request.Form("typ") agio=request.Form("agio") %> 将购物信息及表单中的信息存入数据库,因为这是用户刚刚填写的表单,所以表单类 型字段的值为“新订单”。关键代码如下: 177 C H A P T E R 4 第 4 章 电子商城 <% sql="insert into tb_OrderForm values(’"&dingdan&"’,’"&str&"’,’"&str2&"’,’"&str3&"’,’"&agio&"’,"&jine&", ’"&yunshu&"’,’"&names&"’,’"&phone&"’,’"&email&"’,’"&addre&"’,’"&meg&"’,’"&fangshi&"’,’新订单’,’无’, ’"&date()&"’)" rs.open sql,conn set rs=nothing conn.close set conn=nothing %> <% sql="update tb_Account set Amount=Amount+"&jine&",Degree=Degree+1 where Name=’"&yonghu& "’" rs.open sql,conn set rs=nothing conn.close set conn=nothing %> 将订单信息保存到数据库后,还需要对用户的消费总额以及消费次数进行更新,因为 数据库中的积分及打折比率、会员级别等字段记录的是用户的最新信息,所以,当用户的 消费总额更新后,就需要将数据检索出来,并调用首页中的初始化参数,计算出用户的消 费积分以及打折比率,同时还要评定用户的会员级别,最后用最新的计算结果更新数据库。 关键代码如下: <% sql="select * from tb_Account where Name=’"&yonghu&"’" rs.open sql,conn if not rs.eof then amount=rs("Amount") end if ’变量存储用户积分计算参数 variable=int(session("Integral")) ’计算用户的积分 公式为"消费总额/积分计算参数" integral=int(amount/variable) session("jifen")=integral ’计算会员的等级 if integral<5 then step="普通会员" agio=100 else if integral<10 then step="三级会员" agio=95 else if integral<30 then step="二级会员" agio=90 else if integral<50 then step="一级会员" agio=80 else if integral<100 then step="VIP会员" agio=65 else 根据用户的消费积分,计算用户的 会员等级及购买商品的打折比率 获取用户的消费总额 将订单中的参数存放到数据库 178 SQL Server 2005 数据库系统开发案例精选 step="终身会员" agio=50 end if end if end if end if end if <% sql="update tb_Account set Integral="&integral&",Agio="&agio&",Step=’"&step&"’ where Name=’" &yonghu&"’" rs.open sql,conn set rs=nothing conn.close set conn=nothing %> 对用户的账户进行更新之后,还要对商品信息表中的商品销售量进行更新,最后清除 储存在 Session 对象中的用户购物信息。关键代码如下: <% for i=0 to ubound(arys_1)-1 sql="update tb_Goods set Sell=Sell+"&ary(i)&" where Name=’"&arys_1(i)&"’" rs.open sql,conn next set rs=nothing conn.close set conn=nothing session("array")="" session("array2")="" session("array3")="" %> 4.12 后台主要功能模块详细设计 4.12.1 后台总体架构 电子商城管理系统的后台主要包括后台登录、商品管理、商城信息管理、用户失信及 订单管理、会员资料管理、退出后台管理。后台管理的设计架构如图 4.25 所示。 图 4.25 后台设计架构 179 C H A P T E R 4 第 4 章 电子商城 4.12.2 后台管理页面的实现过程 在主页面中提供了后台登录入口,管理人员可通过输入用户名及密码进入后台管理页 面。通过后台管理页面将完成对电子商城相关功能模块中的数据进行添加、删除、修改、 显示等操作。后台管理页面的运行结果如图 4.26 所示。 1 2 图 4.26 后台运行结果 为了方便读者阅读和有效利用本书附赠光盘的实例,笔者将网站后台页面的各部分说 明以列表形式给出,如表 4.12 所示。 表 4.12 网站后台首页解析 区 域 名 称 说 明 对 应 文 件 1 网站后台功能导航区 主要用于显示当前网站后台相关功能导航 Manage\top.asp 2 相关功能展示区 主要用于展示相关功能模块的操作 Login.asp Online.asp Unonline.asp 4.13 商品信息管理模块设计 商品信息管理模块主要包括商品信息的添加、修改和删除 3 个部分。管理员可通过后 台功能导航区进入到商品信息管理页面。 4.13.1 商品信息添加 在商品信息管理页中,单击【商品信息添加】按钮进入商品信息添加页面。管理员可 以在商品信息添加页面中添加商品信息,将商品的相关信息添加完毕后,单击【添加】按 钮保存所添加的商品信息。商品信息添加页面的设计效果如图 4.27 所示。 180 SQL Server 2005 数据库系统开发案例精选 图 4.27 商品信息添加页面 商品信息添加页面所涉及的 HTML 表单元素如表 4.13 所示。 表 4.13 商品信息添加页面所涉及的 HTML 表单元素 名 称 类 型 含 义 重 要 属 性 form1 Form 表单 name text 商品名称 reside select 商品类别 vendibility text 市场价 memberpri ce text 会员价 picture text 图片信息名称 style select 商品类型 groom radio 推荐 groom radio 不推荐 meg textarea 商品信息 Submit4 submit 【添 加】按钮 Submit3 button 【返回】按钮 当管理员将商品信息填写完毕后,单击【添加】按钮,系统将表单数据提交到数据处 理页。数据处理页的代码如下: 181 C H A P T E R 4 第 4 章 电子商城 <% str=request.Form("name") sql="select * from tb_Goods where Name=’"&str&"’" rs.open sql,conn if not rs.bof and not rs.eof then %> <% set rs=nothing conn.close set conn=nothing else %> <% reside=request.Form("reside") vendibility=Cdbl(request.Form("vendibility")) memberprice=cdbl(request.Form("memberprice")) if request.Form("picture")="" then picture="no.gif" else picture=request.Form("picture") end if groom=request.form("groom") if request.Form("meg")="" then meg="暂时没有该商品的任何相关信息" else meg=request.Form("meg") end if style=request.Form("style") sell=0 sql="insert into tb_Goods values(’"&str&"’,"&vendibility&","&memberprice&",’"&_ picture&"’,’"&reside&"’,’"&meg&"’,"&sell&",’"&style&",’"&groom&"’)" rs.open sql,conn,1,3 set rs=nothing conn.close set conn=nothing %> <% sql="select * from tb_Goods where Name=’"&str&"’ and Vendibility="&vendibility&" and MemberPrice="&memberprice&" and Picture=’"&picture&"’ and Reside=’"&reside&"’ and Remark=’"&meg&"’ and Sell=0 and Style=’"&style&"’ and Groom=’"&groom&"’" rs.open sql,conn if rs.eof or rs.bof then %> <% else %> <% end if end if %> 商品信息添加页面的运行结果如图 4.28 所示。 图 4.28 商品信息添加页面运行结果 4.13.2 商品信息修改 在商品信息管理页面,管理员可以单击任意一条商品信息后面的【管理】按钮,打开 商品信息的修改页面,在该页面中主要完成对商品信息的修改操作。相关程序代码如下。 <% id=request.Form("id") style=request.Form("style") vendibility=request.form("vendibility") memberprice=request.form("memberprice") if request.Form("picture")="" then picture="no.gif" else picture=request.Form("picture") end if groom=request.form("groom") if request.form("meg")="" then meg="暂无该类商品的具体信息" else meg=request.form("meg") 183 C H A P T E R 4 第 4 章 电子商城 end if sql="update tb_Goods set Style=’"&style&"’,Vendibility="&vendibility&",MemberPrice="&memberprice&", Picture=’"&picture&"’,Remark=’"&meg&"’,Groom=’"&groom&"’ where ID="&id rs.open sql,conn set rs=nothing conn.close set conn=nothing %> <% sql="select * from tb_Goods where Style=’"&style&"’ and Vendibility="&vendibility&" and Member Price="&memberprice&" and Picture=’"&picture&"’ and Remark=’"&meg&"’ and Groom=’"&groom&"’ and ID="&id rs.open sql,conn if not rs.eof or not rs.bof then %> <% else %> <% end if %> <% set rs=nothing conn.close set conn=nothing %> 4.13.3 商品信息删除 在商品信息管理页面,管理员可以单击任意一条商品信息后面的【管理】按钮,进入 商品信息管理页面,在该页面中单击【删除】按钮完成对指定商品信息的删除操作,相关 程序代码如下: <% id=request.Form("id") sql="delete tb_Goods where ID="&id rs.open sql,conn,1,1 set rs=nothing conn.close set conn=nothing %> 应用 Update 语句对指 定的商品信息进行更新 关闭并释放记录集 184 SQL Server 2005 数据库系统开发案例精选 4.14 会员资料管理模块设计 会员资料管理模块主要包括会员资料查询、会员资料删除、会员资料冻结 3 部分。在 会员资料管理页面中,用户可以通过会员资料查询区进行会员信息的查询;同时管理员还 可以对指定的会员进行冻结(解结);也可以通过单击【删除】按钮将指定的会员资料删除。 下面分别对这 3 部分进行介绍。 4.14.1 会员资料查询 为了方便管理员管理会员,系统提供了会员资料查询功能。通过输入关键字以及选择 关键字类型,进行指定会员资料的查询。会员资料查询页面的设计效果如图 4.29 所示。 图 4.29 会员资料查询页面 会员资料查询页面所涉及的 HTML 表单元素如表 4.14 所示。 表 4.14 会员资料查询页面所涉及的 HTML 表单元素 名 称 类 型 含 义 重 要 属 性 form1 Form 表单 keyword text 关键字 style select 关键字类型 submit submit 【确认查询】按钮 在设计页面中将所涉及到的表单元素添加完毕后,通过以下代码实现会员资料查询功 能。关键代码如下: <% rs.pagesize=18 pages=request.QueryString("page") if pages="" then pages=1 end if if request.form("keyword")="" then sql="select * from tb_Member order by ID desc" 主要应用 like 运算符实现 信息的模糊查询 185 C H A P T E R 4 第 4 章 电子商城 else sql="select * from tb_Member where "&request.form("style")&" like ’%"&request.form ("keyword")&"%’" end if rs.open sql,conn,1,3 row=0 if not rs.eof and not rs.bof then rs.absolutepage=cint(pages) i=1 while not rs.eof %> <% rs.movenext wend %> <% if pages=1 then %> <% if pages<>rs.pagecount then %> <% end if %> <% else %> <% if page <% 对会员资料信息 进行分页显示 186 SQL Server 2005 数据库系统开发案例精选 else %> <% end if end if set rs=nothing conn.close set conn=nothing end if %> 会员资料查询页面的运行结果如图 4.30 所示。 图 4.30 会员资料查询页面的运行结果 4.14.2 会员资料删除 当管理员确定注册的会员已经不再使用该账号进行系统登录,此时就可以对其进行删 除。会员资料的删除,主要根据传递的 ID 值,使用 SQL 语句从数据库中删除指定的记录。 关键代码如下: <% id=request.Form("ID") sql="delete tb_Member where ID="&id rs.open sql,conn set rs=nothing conn.close set conn=nothing %> <% sql="delete tb_Account where ID="&id rs.open sql,conn set rs=nothing conn.close set conn=nothing %> 4.15 疑难问题分析解决 4.15.1 实现销售排行 实现销售排行,只需在读取数据时,将单个商品销售的数量按照从高到低的顺序取出 来即可,主要通过 SQL 中的 order by 语句实现排序,代码如下: <% sql="select top 6 * from tb_Goods order by Sell desc" %> 取出前 6 位商品,并将商品信息输出到浏览器中,程序代码如下:
送货地 址及其他资料
收货人:
<%=rs("UserName")%>
收货地址:
175 C H A P T E R 4 第 4 章 电子商城 <%=rs("UserAddress")%>
电话:
<%=rs("UserPhone")%>
Email:
<%=rs("UserEmail")%>
备注:
<%=rs("Remark")%>
订单号:
<%=rs("Number")%>
付款方式:
<%=rs("SendMoney")%>
订单状态:
<%=rs("Status")%>

 

付款方式:
176 SQL Server 2005 数据库系统开发案例精选
<%=rs("Name")%>
<%=rs("RealName")%>
<%=rs("Sex")%>
<%=rs("Phone")%>
<%=rs("Email")%>
’,’’,’width=530, height=450,toolbar=no,location=no,status=no,menubar=no,scrollbars=yes’)">
第一页 上一页 下一页 最后一页
第一页 上一页
<% set conn=server.CreateObject("ADODB.Connection") sql="Driver={Microsoft Access Driver (*.mdb)};DBQ= "&Server.MapPath("db_database.mdb") conn.open(sql) set rs=server.CreateObject("ADODB.Recordset") sql="select top 6 * from tb_00 order by name2 desc" rs.open sql,conn,1,3 i=1 while not rs.eof %> <% rs.movenext i=i+1 wend set rs=nothing conn.close set conn=nothing %>
   第<%=i%>位. <%=rs("Name2")%>
4.15.2 应用 Cookie 防止在线调查中的作弊行为 在网站中实现在线调查功能时,首先要考虑的就是防止虚假调查结果的产生。例如, 在电子商城的用户信任度调查模块中,就对用户反复投票的现象加以制止。使用的方法是 向 Cookie 中写记录,当用户进行投票时,首先要读取 Cookie 中的内容,如果 Cookie 中的 内容不包含特定的数据,则接受用户的投票数据,并向 Cookie 中写入特定的内容;反之, 如果 Cookie 中包含特定的内容,则拒收用户的投票信息。其相关程序代码如下: <% if request.QueryString("stype")="" then if Request.ServerVariables("REMOTE_ADDR")=request.cookies("IPAddress") then response.write"" else options=request.form("Options") response.cookies("IPAddress")=Request.ServerVariables("REMOTE_ADDR") conn.execute("update tb_Vote set Option"&options&"=Option"&options&"+1") conn.close set conn=nothing end if end if %> 技巧 可以通过设置 Cookie 的时效,来实现在指定时间内防止反复投票。例如:设置 Cookie 的时效为 1 天,则代表用户只可以 1 天投 1 票。 4.15.3 实现图片与下拉列表的关联 关联列表框就是当一个列表框发生变化时,网页中与其关联的某些部分也随之变化来 与列表框的内容对应。例如:在多数 BBS 中,用户进行注册时,都为用户提供了个性化头 像的选择功能,当用户选择类别框中的头像名称后,与之对应的图像域将显示对应名称的 图片,具体的实现代码如下:      " name="img">  注意 logo 图片应放在 images 目录下。 4.15.4 Insert Into 和 AddNew 的区别 总体来说,Insert Into 和 AddNew 都能实现向当前数据库中插入新数据,ADO 的 AddNew 方法只是将 Insert Into 语句封装起来,当对少量数据进行操作时,两者几乎没什么 区别;而对大量的数据进行操作时,直接使用 Insert Into 语句就会加快存取速度,因为它 省去了 ADO“封装”的过程。该方法虽然快,但也存在弊端,那就是不能传递太长的字段 内容,而且在字段比较多的情况下不容易检查错误,例如: 189 C H A P T E R 4 第 4 章 电子商城 <% SQL="insert into usertable (UserName,UserPwd,Age,Sex) values (’"&Username&_ "’,’"&Userpwd&"’,"&age&",’"&sex&"’)" set rs=conn.execute(SQL) %> 在上述代码中,如果 Username 的值含有“’”时,操作就会出错,所以必须要先把字 符串用函数处理一下才可以,处理代码如下: <% function fieldsencode(str) fieldsencode="’"&replace(str,"’",""")&"’" end function %> 将上面的 SQL 语句调整为: <% sql="insert into usertable (UserName,UserPwd,Age,Sex) values ("&fieldsencode(Username)&","&_ fieldsencode(Userpwd)&","&age&",’"& fieldsencode(sex)&"’) " %> AddNew()方法比起 Insert Into 方法更容易阅读,查找错误也简单一些,只是比较消耗 系统资源。 4.16 程序调试及错误处理 在调试程序时,由于程序出错,显示的页面不显示错误信息,只提示该页无法显示。 如图 4.31 所示。这是在开发 ASP 程序时经常会遇到的问题。 图 4.31 无法显示网页 该如何解决这种问题呢?方法其实很简单,只需在 IE 的 Internet 选项中进行相应设置, 具体方法如下。 在 IE 浏览器的菜单中选择“工具”→“Internet 选项”命令,在打开的“Internet 选项” 对话框中选择“高级”选项卡,在“设置”列表中取消“显示友好 HTTP 错误消息”列表 190 SQL Server 2005 数据库系统开发案例精选 项的选择,如图 4.32 所示。 图 4.32 Internet 选项 此时再运行有错误的程序时,将显示图 4.33 所示的错误页面。读者可以很方便地找到 出错原因和出现问题的代码。 图 4.33 程序出现的错误 5 物流信息网 开发导读 实例说明  实例名称:物流信息网。  实例路径:光盘\mingrisoft\ 物流信息网。  实例运行文件:光盘\ mingrisoft\ 物流信息网\index.asp。  用户名:mr。  密码:mrsoft。  用户在使用本实例前,请仔细 阅读光盘中的光盘使用说明、 程序界面修改配置说明书、安 装说明书、使用说明书,这样 可以使您更好地学习和使用 本实例。 在计算机中使用本章实例的源程序时,用户需安 装 Dreamweaver MX 或其他网页开发工具。 本实例数据库为 SQL Server 2005,使用本实例 前,请安装 SQL Server 2005。安装时,验证模式为 混合模式,用户名为 sa,密码为空。 本实例提供了 5 套程序背景和素材,有些格式需 要使用特殊软件处理。 JPG/GIF 文件,如要修改其文件,需要安装 Photoshop 图像编辑软件。 192 SQL Server 2005 数据库系统开发案例精选 本案例由多个程序界面组成,下面仅列出几个典型界面,其他界面请参见光盘中的源 程序。 首页 后台管理页面 企业信息展示页面 车辆信息展示页面 信息分类查询页面 企业信息管理页面 货物信息管理页面 公告信息管理页面 193 C H A P T E R 5 第 5 章 物流信息网 5.1 概 述 现代物流行业突飞猛进,传统物流行业的操作模式已经不适应现代的物流行业,如何 缩短物流过程,降低产品库存,加速对市场的反应,这是所有物流企业所面对的问题。本 系统就是针对这些问题为中小型企业提供的一套物流管理系统。系统的开发能够帮助企业 实现对物流全过程的优化调度和动态控制,高效整合企业的物流业务,以全面提高经济效 益和效率为目的,提供高效、实用、技术的物流管理系统和运营手段。 5.2 系 统 分 析 5.2.1 需求分析 通过市场调查,要求本系统具有以下的功能。  统一友好的操作界面,能保证系统的易用性。  规范、完善的基础信息设置。  全方位的信息查询功能。  提供会员服务功能模块,包括注册会员、管理会员信息、发布信息、发布信息管 理功能。  为物流企业提供行业的辅助工具。  为管理员提供后台管理入口。  通过后台对各类信息进行管理。  对网站会员信息进行管理。 5.2.2 可行性分析 由于传统物流行业操作过程复杂,手续繁多,业务信息多,围绕这些信息的处理也很 繁杂。物流行业的竞争日益激烈,这种竞争,一方面表现在发展客户的市场开拓上,另一 方面表现为收集处理信息的速度、广度和深度,以及在业务操作中,对业务数据处理的准 确性和严密性,而更高层次上,还涉及到公司整体业务的控制和协调。 物流信息网主要为各类物流企业提供了浏览、查询物流行业信息、供求信息等功能, 帮助企业更多的了解行业的动态信息,提高企业的运营效率。通过物流信息网,使企业能 够更及时地调整企业的发展趋势以及适应市场的变化。 5.3 总 体 设 计 5.3.1 项目规划 物流信息网是一个专业的物流信息网站,由网站前台信息浏览和后台管理两部分组成。  前台功能模块 前台功能模块主要包括各类信息发布、详细信息查看、信息查询、帮助中心、会员注 194 SQL Server 2005 数据库系统开发案例精选 册和后台登录入口等功能模块。  后台功能模块 后台管理模块主要包括企业信息管理、货物信息管理、车辆信息管理、行业信息管理、 帮助信息管理、物流知识管理、公告信息管理、会员信息管理、退出后台管理模块。 5.3.2 系统功能结构图 根据物流信息网的特点,可分为前台和后台两个部分设计。前台主要用于用户浏览各 类信息、信息查询、会员注册等;后台主要用于管理各类信息的发布、删除、修改、查询 等。物流信息网前台系统功能结构如图 5.1 所示。 物流信息网前台 物流动态 物流知识 货物信息 车辆信息 企业信息 信息查询 物流信息查看 物流知识查看物流知识分类货物信息查看货物信息发布车辆信息查看车辆信息发布企业信息查看企业信息发布 信息分类查询 会员管理车辆信息查询 会员登录会员注册密码找回 车辆号码所属地查询 帮助中心 图 5.1 物流信息网前台系统功能结构 物流信息网后台系统功能结构如图 5.2 所示。 物流信息网后台 企业信息 货物信息 车辆信息 行业信息 公告信息 帮助信息 物流知识 会员信息 企业信息查询企业信息删除货物信息删除货物信息查询车辆信息查询车辆信息删除行业信息删除行业信息添加行业信息修改公告信息修改公告信息添加公告信息删除帮助信息删除帮助信息添加帮助信息修改物流信息删除物流信息修改物流信息添加会员信息验证会员信息删除会员信息查询 图 5.2 物流信息网后台系统功能结构 5.4 系 统 设 计 5.4.1 设计目标 本系统是物流企业信息发布、浏览与查询的行业网站,主要实现如下目标。  提供完备的会员管理功能。  为物流企业提供查询功能。  通过后台对前台各类信息进行全面的管理。  物流行业内企业对各类信息的发布、查询等功能。 195 C H A P T E R 5 第 5 章 物流信息网  提供会员注册功能。  系统运行稳定、安全可靠。 5.4.2 开发及运行环境 硬件平台:  CPU Pentium Ⅲ及其兼容处理器,建议主频 600MHz 或更高。  内存 512MB 以上。 软件平台:  操作系统 Windows 2000 Server SP4、Windows 2000 Advanced Server SP4、Windows 2000 Data Center Server SP4、Windows Server 2003 SP1、Windows 2003 企业版 SP1、Windows 2003 数据中心版 SP1。  数据库 SQL Server 2005。  浏览器 IE 5.0,推荐使用 IE 6.0。  Web 服务器 IIS 5.0。  分辨率 最佳效果 1024×768 像素。 5.4.3 Windows 2003 的 IIS 配置 1.安装 Internet 信息服务 安装 IIS 的具体操作步骤如下。 (1)单击“开始”→“控制面板”→“添加或删除程序”命令,启动“添加或删除程 序”工具。 (2)单击【添加/删除 Windows 组件】按钮,弹出“Windows 组件向导”窗口。在 Windows 组件列表中,选择“应用程序服务器”,单击【详细信息】按钮,在弹出的窗口中(可以查 看应用程序服务器的所有子选项)选择“Internet 信息服务(IIS)”选项。 (3)单击【确定】按钮,依次单击【下一步】按钮,完成 IIS 的安装。 2.配置匿名身份验证 要配置匿名身份验证,请按以下步骤操作。 (1)单击“开始”→“管理工具”→“Internet 信息服务”命令。 (2)展开“服务器名称”(其中服务器名称为当前服务器的名称),鼠标右键单击“默 认网站”,在弹出的快捷菜单中选择“属性”命令。 (3)在打开的“默认网站属性”对话框中,选择“目录安全性”选项卡。 (4)在“身份验证和访问控制”栏中,单击【编辑】按钮,选择“启用匿名访问”复 选框,然后在“用户访问需经过身份验证”栏中,选择“集成 Windows 身份验证”复选框, 依次单击【确定】按钮完成匿名身份验证的配置。 3.基本 Web 站点配置 基本 Web 站点的配置步骤如下。 (1)单击“开始”→“管理工具”→“Internet 信息服务(IIS)管理器”命令。 (2)展开服务器名称(服务器名称为当前服务器的名称)下的 Web 站点节点。 196 SQL Server 2005 数据库系统开发案例精选 (3)鼠标右键单击“默认网站”节点,选择“属性”命令。 (4)选择“网站”选项卡,如果您已为计算机分配了多个 IP 地址,请在“IP 地址”下 拉列表中选择您要指定给此 Web 站点的 IP 地址。 (5)选择“主目录”选项卡,如果想使用存储在本地计算机上的 Web 内容,则选择“此 计算机上的目录”单选按钮,然后在“本地路径”文本框中键入文件路径(或单击【浏览】 按钮选择文件路径)。例如,默认路径为 C:\Inetpub\wwwroot。 (6)选择“文档”选项卡,单击【添加】按钮,打开“添加内容页”对话框,在“默 认内容页”文本框中,键入 index.asp,单击【确定】按钮,将 index.asp 添加到“启用默认 文档”列表中。单击【上移】按钮,直到 index.asp 显示在列表的顶部,最后单击【确定】 按钮,关闭“默认网站属性”对话框。 (7)鼠标右键单击“默认网站”节点,在弹出的快捷菜单中选择“权限”命令,在 弹出的窗口中会显示出在此 Web 站点上具有操作权限的用户账户。单击【添加】按钮添 加其他可操作此 Web 站点的用户账户。单击【确定】按钮,返回到“Internet 信息服务” 窗口。 (8)鼠标右键单击“默认网站”,在弹出的快捷菜单中选择“启动”命令,即可启动 Internet 服务器。  注意 如何启用 ASP 支持:Windows Server 2003 默认安装,是不安装 IIS 6.0 的,需要另外 安装。安装完 IIS 6.0,还需要单独开启对 ASP 的支持。方法如下。 控制面板→管理工具→Web 服务扩展→Active Server Pages→允许 5.4.4 Web 服务扩展 Web 服务扩展的操作步骤如下。 (1)单击“所有程序”→“管理工具”→“Internet 信息服务(IIS)管理器”命令。 (2)展开服务器名称(其中服务器名称为该服务器的名称)节点下的“Web 服务 扩展”子节点,在右侧打开的窗口中,分别选择 Active Server Pages 和“Internet 数据 连接器”文件,单击【允许】按钮,将文件的状态由“禁止”设置为“允许”,如图 5.3 所示。 将文件的状态由“禁 止”设置为“允许” 双击 选择“禁止”状态的 文件,该按钮可用 图 5.3 Web 服务扩展 197 C H A P T E R 5 第 5 章 物流信息网 至此 Web 服务器配置完成。 5.5 数据库设计 本系统数据库采用 SQL Server 2005 数据库,系统数据库名称为 db_wuliu。数据库 db_wuliu 中包含 9 张表。下面分别给出数据表概要说明、数据表关系概要说明及主要数据 表的结构。 5.5.1 数据表的实体 E-R 图 根据数据表结构的设计,规划出相应的实体 E-R 图,这些实体中包含各种具体信息, 并通过相互之间的作用形成数据的流动。具体数据表的实体 E-R 图描述如下。 图 5.4 为后台管理项目信息实体 E-R 图。 图 5.5 为帮助信息实体 E-R 图。 项目名称 后台管理项目信息实体 前台项目名称 项目英文名称项目编号 信息标题 帮助信息实体 信息内容 发布时间项目编号 图 5.4 后台管理项目信息实体 E-R 图 图 5.5 帮助信息实体 E-R 图 图 5.6 为公告信息实体 E-R 图。 图 5.7 为物流动态信息实体 E-R 图。 公告标题 公告信息实体 公告内容 发布时间项目编号 新闻标题 物流动态信息实体 新闻内容 发布时间信息编号 图 5.6 公告信息实体 E-R 图 图 5.7 物流动态信息实体 E-R 图 5.5.2 主要数据表的结构 由于本书的篇幅所限,在此只给出较为重要的数据表,其他数据表请参见本书附带的 光盘。  tb_CarMessage(车辆信息表) 车辆信息表主要用于保存会员发布的车辆信息,该表的结构如表 5.1 所示。 198 SQL Server 2005 数据库系统开发案例精选 表 5.1 tb_CarMessage 表的结构 字 段 名 数 据 类 型 长 度 主 键 否 描 述 ID int 4 是 惟一标识 TradeMark varchar 30 否 车牌号码 Brand varchar 50 否 车辆品名 Style varchar 30 否 车辆类型 CarLoad varchar 10 否 车辆载重 UsedTime int 4 否 使用时间 DriverName varchar 30 否 驾驶员姓名 DriverTime int 4 否 驾驶时间 LicenceNumber varchar 50 否 驾照号码 LicenceStyle varchar 20 否 驾照类型 TranspotStyle varchar 20 否 运输类型 LinkMan varchar 20 否 联系人 LinkPhone varchar 50 否 联系电话 Remark varchar 100 否 备注 IssueDate datetime 8 否 发布时间 UserName varchar 20 否 发布人  tb_Enterprise(企业信息表) 企业信息表主要用于保存用户发布的企业信息。该表的结构如表 5.2 所示。 表 5.2 tb_Enterprise 表的结构 列 名 数 据 类 型 长 度 主 键 否 描 述 ID int 4 是 惟一标识 Name varchar 100 否 商品名称 Vendibility float 8 否 市场价 Memberprice float 8 否 会员价 Pictrue varchar 100 否 图片信息地址 Reside varchar 100 否 所属分类 Remark varchar 200 否 备注信息 Sell int 4 否 销售量 Style varchar 20 否 销售类型 Groom varchar 10 否 推荐参数  tb_GoodsMeg(货物信息表) 货物信息表主要用于保存货物信息。该表的结构如表 5.3 所示。 表 5.3 tb_GoodsMeg 表的结构 列 名 数 据 类 型 长 度 主 键 否 描 述 ID int 4 是 惟一标识 GoodsStyle varchar 50 否 货物类型 199 C H A P T E R 5 第 5 章 物流信息网 续表 列 名 数 据 类 型 长 度 主 键 否 描 述 GoodsName varchar 100 否 货物名称 GoodsNumber Varchar 100 否 货物数量 GoodsUnit varchar 50 否 数量单位 StartOmit varchar 100 否 起始省份 StartCity varchar 20 否 起始城市 EndOmit varchar 30 否 抵达省份 EndCity varchar 30 否 抵达城市 Style varchar 30 否 运输类型 TransportTime varchar 50 否 运输时间 Phone varchar 50 否 联系电话 Link varchar 200 否 联系人 IssueDate datetime 8 否 发布时间 Remark varchar 800 否 备注 Request varchar 50 否 车辆要求 UserName varchar 50 否 发布人  tb_Knowledge(物流知识信息表) 物流知识信息表主要用于保存物流的相关知识信息。该表的结构如表 5.4 所示。 表 5.4 tb_Knowledge 表的结构 列 名 数 据 类 型 长 度 主 键 否 描 述 ID int 4 否 惟一标识 Title varchar 200 否 知识标题 Content varchar 2000 否 知识内容 IssueDate datetime 8 否 发布时间 Reside varchar 100 否 知识类别  tb_NewMeg(物流动态信息表) 物流动态信息表主要用于保存物流的最新动态信息。该表的结构如表 5.5 所示。 表 5.5 tb_NewMeg 表的结构 列 名 数 据 类 型 长 度 主 键 否 描 述 ID int 4 否 惟一标识 Title varchar 200 否 信息标题 Content varchar 2000 否 信息内容 IssueDate datatime 8 否 发布时间  tb_UserMeg(用户信息表) 用户信息表主要用于保存用户注册的相关信息。该表的结构如表 5.6 所示。 200 SQL Server 2005 数据库系统开发案例精选 表 5.6 tb_UserMeg 表的结构 列 名 数 据 类 型 长 度 主 键 否 描 述 ID int 4 是 项目编号 UserName varchar(100) 100 否 用户名 Gender varchar(100) 100 否 性别 Password varchar(100) 100 否 密码 Question varchar(300) 300 否 密码提示问题 Answer varchar(300) 300 否 密码提示问题的答案 Email varchar(150) 150 否 E-mail 地址 EnterpriseName varchar(500) 500 否 企业名称 EnterpriseStyle varchar(500) 500 否 企业类型 WorkArea varchar(300) 300 否 经营范围 Area varchar(300) 300 否 所在区域 Address varchar(300) 300 否 企业地址 PostalCode varchar(300) 300 否 邮政编码 Synopsis varchar(100) 100 否 企业简介 Phone varchar(800) 800 否 联系电话 Fax varchar(100) 100 否 企业传真 HandSet varchar(100) 100 否 手机号码 LinkMan varchar(100) 100 否 联系人 OverPass varchar(100) 100 否 验证标志 5.5.3 数据表概要说明 从读者角度出发,为了使读者对本系统后台数据库中数据表有一个清晰的认识,笔者 在此特设计一个数据表树型结构图,该数据表树型结构图包含了系统中所有的数据表,如 图 5.8 所示。 图 5.8 数据表树型结构图 201 C H A P T E R 5 第 5 章 物流信息网 5.6 文件管理规划 在置身于编码设计前,可先将网站中可能应用到的文件夹创建出来。例如创建一个名 为 Conn 的文件夹,该文件夹主要用于保存网站中数据库的连接文件,既方便以后的开发 工作,又可规范网站整体结构,可谓一举两得。笔者在开发物流信息网时,首先设计了图 5.9 所示的文件夹结构图,在开发时只需将文件保存在相应的文件夹中即可,非常方便。 图 5.9 文件管理规划 5.7 前台主要功能模块详细设计 5.7.1 前台文件总体架构 前台页面主要包括以下功能模块。  网站导航:主要包括网站的旗帜广告条、主功能导航两部分。  货物信息:主要用于货物信息发布、货物信息显示两部分。  车牌号码的所属地区查询:主要用于查询指定条件的车牌号码属于哪个地区。  信息查询:主要用于实现信息的分类查询功能。  会员登录:主要包括会员登录、会员注册、密码找回 3 个部分。  企业友情链接:主要用于显示企业友情链接的相关信息。  后台登录入口:主要为管理员登录后台提供登录入口。 5.7.2 文件架构 物流信息管理系统的前台文件架构如图 5.10 所示。 202 SQL Server 2005 数据库系统开发案例精选 图 5.10 文件架构图 5.7.3 前台页面的运行结果 前台页面的运行结果如图 5.11 所示。 1 2 3 4 5 6 7 8 9 图 5.11 前台页面运行结果 203 C H A P T E R 5 第 5 章 物流信息网 为了方便读者阅读和有效利用本书附赠光盘的实例,笔者将网站页面的各部分说明以 列表形式给出,如表 5.7 所示。 表 5.7 网站首页解析 区 域 名 称 说 明 对 应 文 件 1 网站导航 主要用于显示当前网站的功能导航 Index.asp 2 会员登录 主要包括会员注册、找回密码和会员登录 Login/login.asp.asp 3 车牌号码的所属地区查询 主要用于查询车牌号码的所属地区 Search/search.asp 4 帮助中心 主要用于提供网站内的相关帮助 Help/help.asp 5 网站基本信息展示区 主要用于展示网站内最新的基本信息 Index.asp 6 本站公告 主要用于宣传网站内最新的信息 right.asp 7 企业链接 主要用于为网站提供友情链接 Link.asp 8 网站计数器 主要用于统计网站流量 Bottom.asp 9 版权信息 主要用于展示网站的版权信息及提供网 站后台登录入口 Bottom.asp 5.8 车牌号码所属地区查询模块设计 车牌号码所属地区查询是指按指定条件模糊查询车牌号码所属地区,车牌号码所属地 区查询页面的设计效果如图 5.12 所示。 车牌号码所属地区查询页面所涉及的 HTML 表单元素如表 5.8 所示。 分别在“省、市、自治区”与“代号”下拉列表中设置查 询条件后,单击【确认】按钮,此时将触发 JavaScript 脚本函数 checkcar(),该函数的作用是将详细的地区名称信息显示在文本 框中,关键代码如下: 表 5.8 车牌号码所属地区页面所涉及的 HTML 表单元素 名 称 类 型 含 义 重 要 属 性 form10 Form 表单 action="" method="post" name="form10" id="form10" country select 省、市、自治区 图 5.12 车牌号码所属地区 页面设计效果 204 SQL Server 2005 数据库系统开发案例精选 续表 名 称 类 型 含 义 重 要 属 性 city Select 代号 Submit button 【确认】按钮 answer text 结果显示  function checkcar() { var omit=form10.country.value; var city=form10.city.value;  switch (omit) { case "京": form10.answer.value="北京"; break; case "津": form10.answer.value="天津"; break; case "沪": form10.answer.value="上海"; break; case "渝": form10.answer.value="重庆"; break; case "冀": switch(city) { case "A": form10.answer.value="石家庄市"; break; case "B": form10.answer.value="唐山市"; break; case "C": form10.answer.value="秦皇岛市"; break; case "D": form10.answer.value="邯郸市"; break; 205 C H A P T E R 5 第 5 章 物流信息网 case "E": form10.answer.value="邢台市"; break; case "F": form10.answer.value="保定市"; break; case "G": form10.answer.value="张家口市"; break; case "H": form10.answer.value="承德市"; break; case "J": form10.answer.value="沧州市" ; break; case "K": form10.answer.value="邯郸行署"; break; case "L": form10.answer.value="邢台行署"; break; case "M": form10.answer.value="石家庄行署"; break; case "N": form10.answer.value="保定行署"; break; case "P": form10.answer.value="张家口行署"; break; case "Q": form10.answer.value="承德行署"; break; case "R": form10.answer.value="廊坊市"; break; case "S": form10.answer.value="沧州行署"; break; case "T": form10.answer.value="衡水行署"; break; default: form10.answer.value="没有该车牌号码所在区域的信息"; break; } break; …… default: form10.answer.value="没有该车牌号码所在区域的信息"; break; } 206 SQL Server 2005 数据库系统开发案例精选 break; case "吉": default: form10.answer.value="没有该车牌号码所在区域的信息"; break; } }  代码导读  Function 语句:用于声明 Function 过程的名称、参数以及构成其主体的代码。  Switch 语句:Switch 是典型的多路分支语句,其作用与嵌套使用 if 语句基本相同, 但 Switch 语句比 if 语句更具有可读性,而且 Switch 语句允许在找不到一个匹配条件的情 况下执行默认的一组语句。 Switch 语句的语法格式如下。 switch (expression) { case judgement1: statement1; break; case judgement2: statement2; break; … default: defaultstatement; break; } 车牌号码所属地区查询页面的运行结果如图 5.13 所示。 图 5.13 运行结果图 5.9 会员管理模块设计 会员管理模块主要包括会员注册、会员登录和密码找回 3 个部分,在会员管理页面中, 用户可以通过单击【登录】按钮进行会员登录;单击【注册】按钮进行会员注册;单击【忘 密】按钮进行会员密码找回操作。会员管理页面的文件架构如图 5.14 所示。 207 C H A P T E R 5 第 5 章 物流信息网 图 5.14 会员管理页面文件架构图 5.9.1 会员注册 用户可以通过会员注册页面进行会员注册。用户注册成为会员就可以对网站内所有相 关信息进行浏览、查询等。在进行会员注册时,用户必须合法地填写会员信息,同时要求 会员记住密码问题、问题答案,以方便密码丢失时的密码找回操作。会员注册页面的设计 效果如图 5.15 所示。 图 5.15 会员注册页面的设计效果 会员注册页面所涉及的 HTML 表单元素如表 5.9 所示。 表 5.9 会员注册页面所涉及的 HTML 表单元素 名 称 类 型 含 义 重 要 属 性 form2 Form 表单 username text 用户名 password password 密码(至少 6 位) 208 SQL Server 2005 数据库系统开发案例精选 续表 名 称 类 型 含 义 重 要 属 性 password2 password 确认密码(至少 6 位) question text 密码问题 answer text 问题答案 Submit2 submit 【注 册】按钮 Submit reset 【重置】按钮 会员信息填写完毕后,通过单击【注册】按钮将填写的数据信息添加到指定的数据表 中。注册成功后,系统将给予相关提示信息。相关代码如下: <% username=request.form("username") gender=request.form("garden") password=request.form("password") question=request.form("question") answer=request.form("answer") email=request.form("email") enterprisename=request.form("enterprisename") enterprisestyle=request.form("enterprisestyle") workarea=request.form("workarea") area=request.form("area") address=request.form("address") postalcode=request.form("postalnumber") synopsis=request.form("remark") phone=request.form("phone") fax=request.form("fax") combined=request.form("handset") linkman=request.form("linkman") sql="select * from tb_UserMeg where UserName=’"&username&"’" rs.open sql,conn  if not rs.eof or not rs.bof then %> <% else set rs=nothing conn.close set conn=nothing %> <% sql="select * from tb_UserMeg where EnterpriseName=’"&enterprisename&"’" rs.open sql,conn if not rs.eof or not rs.bof then %> <% else set rs=nothing  conn.close set conn=nothing %> <% sql="insert into tb_UserMeg values(’"&username&"’,’"&gender&"’,’"&password&"’,’"&question&"’,’"&answer&"’,’"&email&"’,’"&enterprisen ame&"’,’"&enterprisestyle&"’,’"&workarea&"’,’"&area&"’,’"&address&"’,’"&postalcode&"’,’"&synopsis&"’,’"&ph one&"’,’"&fax&"’,’"&combined&"’,’"&linkman&"’,’未通过’)" rs.open sql,conn %> <% end if %> <% end if %>  代码导读  iF...then....else 语句:根据表达式的值有条件地执行一组语句。  close 语句:应用该语句关闭指定的记录集。  open 方法:应用 window 对象的 open 方法可打开一个动态页。 用户注册页面的运行结果如图 5.16 所示。 图 5.16 用户注册页面的运行结果 主要用于判断企业是否已经注册 主要应用 insert into 语句向数据表中插入数据 210 SQL Server 2005 数据库系统开发案例精选 5.9.2 找回密码 找回密码主要是为了方便已注册过的会员在密码丢失时找回密码。找回密码主要分 3 步。第一步,输入已注册的会员名称;第二步,系统会根据输入的会员名称把相应的密码 问题列出来,然后输入问题答案;第三步,如果问题答案正确,则成功找回密码;否则系 统将提示“您输入的答案有误!”。找回密码页面的设计效果如图 5.17 所示。 图 5.17 找回密码页面的设计效果 找回密码页面所涉及的 HTML 表单元素如表 5.10 所示。 表 5.10 找回密码页面所涉及的 HTML 表单元素 名 称 类 型 含 义 重 要 属 性 form1 Form 表单 username hidden 隐藏域 answer text 请输入问题答案 Submit submit 【确认】按钮 Submit2 reset 【重置】按钮 在会员管理页面中,输入已注册过的用户名称后单击【忘密】按钮,将弹出找回密码 提示对话框,在“找回密码”提示对话框中根据系统提示的密码问题输入正确的问题答案, 单击【确认】按钮即可成功找回会员密码。相关代码如下: <% username=request.form("username") answer=request.form("answer") sql="select * from tb_UserMeg where UserName=’"&username&"’ and Answer=’"&answer&"’" rs.open sql,conn if rs.eof or rs.bof then %> <% else %> <% end if %> 5.9.3 会员登录 当用户注册成为会员后,就可以登录。登录成功后,会员可以对网站内相关信息进行 浏览、查询等。会员登录页面的相关代码如下: <% username=request.Form("username") password=request.Form("userpassword")  sql="select * from tb_UserMeg where UserName=’"&username&"’" rs.open sql,conn if rs.eof or rs.bof then %> <% else %> <%  if rs("PassWord")<>password then%> <% else if rs("OverPass")="未通过" then %> <% else session("name")=username 技术细节 使用 session 参数存储用户登录信息。用户登录成功后,将登录时的用户名信息存储 在 session 参数中。当用户进行相关操作时,系统将会调用存储用户登录信息的 session 参 数作对比,以此来判断该用户是否通过验证。只有通过验证的用户才可以进行添加、修改、 删除操作,而没有通过验证的用户则没有此功能。 <% else session("name")=username response.redirect("../index.asp") %> 212 SQL Server 2005 数据库系统开发案例精选  response.redirect("../index.asp") %> <% end if %> <%end if %> <%end if %>  代码导读  where 子句:select 语句的 where 子句用来控制结果集的记录构成,用 户需要在 where 子句中指定一系列查询条件,而只有满足这些查询条件的记 录才可以用来构造结果集。  <>运算符:不等于指定的值。  redirect 方法:跳转到指定的动态页。 5.10 货物信息模块设计 货物信息模块主要分为货物信息发布和货物详细信息显示两部分。下面分别对这两部 分进行介绍。 5.10.1 货物信息发布 货物信息发布主要用于向网站中发布相关的货物信息,在货物信息发布页面中信息填 写完毕后,单击【发布】按钮将完成货物信息的发布。在该模块中不可以发布相同的货物 信息。代码如下: <% ming=request.Form("name") types=request.Form("type") shuliang=request.Form("number") danwei=request.Form("units") start1=request.Form("startomit") start2=request.Form("startcity") end1=request.Form("endomit") end2=request.Form("endcity") if request.Form("time")="" then times="没有时间上的要求" else time1=request.Form("time") end if type2=request.Form("style") if request.Form("car")="" then car="对车辆没有特殊要求" else car=request.Form("car") end if if request.Form("meg")="" then meg="没有货物的备注信息" else 213 C H A P T E R 5 第 5 章 物流信息网 meg=request.Form("meg") end if names=request.Form("linkman") phone=request.Form("phone") yonghu=session("name")  sql="select * from tb_GoodsMeg where GoodsName=’"&ming&"’ and GoodsStyle=’"&types&"’ and GoodsNumber=’"&shuliang&"’ and GoodUnit=’"&danwei&"’ and StartOmit=’"&start1&"’ and StartCity= ’"&start2&"’ and EndOmit=’"&end1&"’ and EndCity=’"&end2&"’ and TranSportTime=’"&time1&"’ and Style= ’"&type2&"’ and Request=’"&car&"’ and Remark=’"&meg&"’ and Link=’"&names&"’ and Phone=’"&phone&"’ and UserName=’"&yonghu&"’" rs.open sql,conn if not rs.eof or not rs.bof then %> <% else set rs=nothing conn.close set conn=nothing %> <%  sql="insert into tb_GoodsMeg values(’"&types&"’,’"&ming&"’,’"&shuliang&"’,’"&danwei&"’, ’"&start1&"’,’"&start2&"’,’"&end1&"’,’"&end2&"’,’"&type2&"’,’"&time1&"’,’"&phone&"’,’"&names&"’,’"&now() &"’,’"&meg&"’,’"&car&"’,’"&yonghu&"’)" rs.open sql,conn set rs=nothing conn.close set conn=nothing %> 技术细节 在编写 ASP 应用程序时,常常会遇到一些重复代码段。当修改或者增强这些相同代 码段的功能时,必须逐一修改,这样导致了编程效率的降低和错误的增加。对于这个问题, 可以通过嵌入代码模块的方法来解决,可以将这些公用代码段封装到某个位置,在用到时 调用这个代码段即可。 如果希望 ASP 程序中包含代码模块,需要事先定义好模块,并将它储存在一个后缀 名为 inc 的文件里,然后在其他任何想调用此模块的地方使用 include 标签,其语句为: <% sql="select * from tb_GoodsMeg where GoodsName=’"&ming&"’ and GoodsStyle=’"&types&"’ and GoodsNumber=’"&shuliang&"’ and GoodUnit=’"&danwei&"’ and StartOmit=’"&start1&"’ and StartCity=’"&start2&"’ and EndOmit=’"&end1&"’ and EndCity=’"&end2&"’ and TranSportTime=’"&time1&"’ and Style=’"&type2&"’ and Request=’"&car&"’ and Remark=’"&meg&"’ and Link=’"&names&"’ and Phone=’" &phone&"’ and UserName=’"&yonghu&"’" rs.open sql,conn if not rs.eof or not rs.bof then %> 214 SQL Server 2005 数据库系统开发案例精选 <% end if end if %>  代码导读  and 运算符:用于对两个表达式进行逻辑与运算。  insert into⋯values ⋯:用 insert 语句将记录添加到数据表中。  opener.location.reload()语句:应用该语句可实现关闭子窗口时刷新父窗口。 5.10.2 货物详细信息显示 货物信息发布完毕后可以单击【详细】按钮,进行货物详细信息查看。货物详细信息 显示主要通过货物信息的 ID 号作为参数进行传递。在展示页面中这些货物信息将按照发布 时间进行降序排列。代码如下: <% id=request.Form("id") ming=request.Form("name") types=request.Form("type") shuliang=request.Form("number") danwei=request.Form("units") start1=request.Form("startomit") start2=request.Form("startcity") end1=request.Form("endomit") end2=request.Form("endcity") if request.Form("time")="" then times="没有时间上的要求" else time1=request.Form("time") end if type2=request.Form("style") if request.Form("car")="" then car="对车辆没有特殊要求" else car=request.Form("car") end if if request.Form("meg")="" then meg="没有货物的备注信息" else meg=request.Form("meg") end if names=request.Form("linkman") phone=request.Form("phone") yonghu=session("name") sql="select * from tb_GoodsMeg where GoodsName=’"&ming&"’ and GoodsStyle=’"&types&"’ and GoodsNumber=’"&shuliang&"’ and GoodUnit=’"&danwei&"’ and StartOmit=’"&start1&"’ and StartCity=’"&start2&"’ and EndOmit=’"&end1&"’ and EndCity=’"&end2&"’ and TranSportTime=’"&time1&"’ and Style=’"&type2&"’ and Request=’"&car&"’ and Remark=’"&meg&"’ and Link=’"&names&"’ and Phone=’"&phone&"’ and User Name=’"&yonghu&"’" rs.open sql,conn if not rs.eof or not rs.bof then %> <% else set rs=nothing conn.close set conn=nothing %> <% sql="update tb_GoodsMeg set GoodsName=’"&ming&"’,GoodsStyle=’"&types&"’,GoodsNumber=’"&shuliang&"’,GoodUnit=’"&danwei&"’,StartOmit=’ "&start1&"’,StartCity=’"&start2&"’,EndOmit=’"&end1&"’,EndCity=’"&end2&"’,TranSportTime=’"&time1&"’,Style=’"&ty pe2&"’,Request=’"&car&"’,Remark=’"&meg&"’,Link=’"&names&"’,Phone=’"&phone&"’,UserName=’"&yonghu&"’,Issu eDate=’"&date()&"’ where ID="&id rs.open sql,conn set rs=nothing conn.close set conn=nothing %> <% sql="select * from tb_GoodsMeg where GoodsName=’"&ming&"’ and GoodsStyle=’"&types&"’ and GoodsNumber=’"&shuliang&"’ and GoodUnit=’"&danwei&"’ and StartOmit=’"&start1&"’ and StartCity= ’"&start2&"’ and EndOmit=’"&end1&"’ and EndCity=’"&end2&"’ and TranSportTime=’"&time1&"’ and Style=’"&type2&"’ and Request=’"&car&"’ and Remark=’"&meg&"’ and Link=’"&names&"’ and Phone=’"&phone&"’ and UserName =’"&yonghu&"’" rs.open sql,conn if not rs.eof or not rs.bof then %> <% end if end if %> 货物详细信息显示页面的运行结果如图 5.18 所示。 图 5.18 货物详细信息显示 主要应用 update 语句更新指定记录 216 SQL Server 2005 数据库系统开发案例精选  注意 物流知识、车辆信息、企业信息这几个功能模块的实现与货物信息模块的实现方法相 似,在此不作介绍。 5.11 信息查询模块设计 信息查询模块主要用于各种信息的快速查询。在此笔者将信息的分类以下拉列表的形 式给出。浏览者可以在“关键字”文本框内输入要查询信息的关键字;并在“信息类别” 下拉列表中选择要查询信息的类别,单击【查询确认】按钮,此时表单元素将被提交到结 果展示页面进行数据处理操作。信息查询页面的设计效果如图 5.19 所示。 图 5.19 信息查询页面设计效果 信息查询页面所涉及的 HTML 表单元素如表 5.11 所示。 表 5.11 信息查询页面所涉及的 HTML 表单元素 名 称 类 型 含 义 重 要 属 性 form1 form 表单 meg text 关键字 select select 信息类别 Submit2 submit 【查询确认】按钮 在输入完相关查询条件后,将表单中的数据提交到结果展示页面。在该页面中首先会 根据提交的表单数据进行数据库检索,关键代码如下: <% 217 C H A P T E R 5 第 5 章 物流信息网 tb=request.Form("select") meg=request.Form("meg") sql="select * from "&tb rs.open sql,conn leng=rs.fields.count  redim arrays(leng) for i=1 to rs.fields.count-1 arrays(i)=rs(i).name next for i=1 to rs.fields.count-2  str=arrays(i)&" like ’%"&meg&"%’ or " sum=sum+str next str=arrays(leng-1)&" like ’%"&meg&"%’" sum=sum+str set rs=nothing conn.close set conn=nothing %> <% select case tb %> <% case "tb_GoodsMeg" %> <% case "tb_CarMessage" %> <% case "tb_EnterpriseMeg" %> <% case "tb_KnowledgeMeg" %> <% case "tb_NewMeg" %> <% end select %> <% sql="select * from "&tb&" where "&sum  rs.pagesize=24 page=request.QueryString("pages") if page="" then page=1 end if rs.open sql,conn,1,3 %>  代码导读  ReDim 语句:主要用于声明动态数组变量并分配或重新分配存储空间。  like 运算符:进行模糊查询。  pagesize 函数:每页显示的记录数。例如:pagesize=10 表示每页显示 10 条记录。 数据库检索完成后,将根据以下代码判断查询结果是否存在,并对查询结果进行分页 显示。代码如下: <% if not rs.eof or not rs.bof then rs.absolutepage=cint(page) i=0 while not rs.eof and i 主要应用 select case 语句进行循环判断 218 SQL Server 2005 数据库系统开发案例精选  <% select case tb %> <% case "tb_GoodsMeg" %> <% case "tb_CarMessage" %> <% case "tb_EnterpriseMeg" %> <% case "tb_KnowledgeMeg" %> <% case "tb_NewMeg" %> <% end select %> <%  rs.movenext() wend %>
<% if page=1 then if page<>rs.pagecount then %> 下一页 最后一页 <% end if %> <% else %> <%  if page 第一页 上一页 下一页 最后一页 <% else %> 第一页 上一页 <% end if %> <% end if 219 C H A P T E R 5 第 5 章 物流信息网 %> <% else %>
没有您要查找的信息
<% end if %>  代码导读  select⋯ case 语句:是 if⋯then ⋯else 结构的一种变通形式,简单易读。  movenext 语句:向下移动记录指针。  pagecount 函数:最大页码。例如:maxpage=pagecount 中 maxpage 获取了最大的 页码。  链接 在信息查询模块中应用到 ReDim 语句,该语句的详细介绍请参见第 3 章 3.8 节。 通过以下代码实现将查询结果输出到浏览器中,关键代码如下: action="" method="post"> <%=rs("TradeMark")%> <%=rs("Style")%> <%=rs("Brand")%> <%=rs("CarLoad")%>吨 <%=rs("UsedTime")%>年 <%=rs("DriverTime")%>年 <%=rs("TranSportStyle")%>  注意 鉴于不同类别信息的字段不同,本节将以车辆信息的查询结果展示为例。 在结果展示页面中添加详细信息查看按钮,通过单击【详细】按钮进入相关详细信息 页面,关键代码如下: <% ’,’’,’width=580,height=400,toolbar=no,location=no,sta tus=no,menubar=no,scrollbars=yes’)">详细 %> 220 SQL Server 2005 数据库系统开发案例精选 技巧 在进行搜索功能模块设计时,如果搜索涉及到了多个数据表,可以将搜索模块中的关 键字类别名称的值设为数据表的名称(一般情况下,搜索功能模块在设计时,是包含关键 字和关键字类别两个表达组件的),这样就不用去对用户要查询的数据表进行判断了,可 以直接将表单数据作为数据表名进行查询。 5.12 后台主要功能模块详细设计 5.12.1 后台总体架构 物流信息网的后台主要由 9 个模块组成,分别是企业信息管理、货物信息管理、车辆 信息管理、行业信息管理、公告信息管理、帮助信息管理、物流知识信息管理、会员信息 管理和后台管理退出。后台管理的设计架构如图 5.20 所示。 后台登录入口 manage\Login\ login.asp 后台主体页面 退出后台管理 exit.asp管理导航页 manage\left.asp 管理主体页 manage\default.asp 企业信息管理 manage\ Enterprise\ enterprise.asp 行业信息管理 manage\new\ new.asp 货物信息管理 manage\Goods\ goods.asp 车辆信息管理 manage\Cars\ car.asp 公告信息管理 manage\Placard\ placard.asp 帮助信息管理 manage\Help\ help.asp 物流知识管理 manage\ Knowledge\ knowledge.asp 会员信息管理 manage\Member\ member.asp 图 5.20 后台管理设计架构 221 C H A P T E R 5 第 5 章 物流信息网 5.12.2 后台管理页面的实现过程 在前台页面中提供了后台登录入口,管理人员可通过此入口进入到后台管理页面。通 过后台管理页面将实现对物流信息网中相关模块中的数据进行添加、删除、修改、显示、 查询等操作。后台管理页面运行结果如图 5.21 所示。 1 2 3 4 图 5.21 后台运行结果 为了方便读者阅读和有效利用本书附赠光盘的实例,笔者将网站后台页面的各部分说 明以列表形式给出,如表 5.12 所示。 表 5.12 网站后台解析 区 域 名 称 说 明 对 应 文 件 1 后台管理功能导航区 主要用于显示当前后台管理的功能导航 Manage\left.asp 2 网站基本功能管理展示区 主要用于展示网站后台的相关操作 Manage\ default.asp 3 网站计数器 主要用于统计网站流量 Bottom.asp 4 版权信息 主要用于展示网站的版权信息 Bottom.asp 222 SQL Server 2005 数据库系统开发案例精选 5.13 企业信息管理模块设计 企业信息管理模块主要包括企业信息查询、企业信息删除两部分,管理员可以通过后 台功能导航区进入企业信息管理页面。在该页面中,可以通过企业信息查询功能部分设置 查询条件,查询相关的企业信息;也可以单击【管理】按钮,进行企业信息的删除操作。 下面分别对这两部分进行详细介绍。 5.13.1 企业信息查询 在企业信息查询模块中,通过输入指定的关键字、关键字的类型,就可以快速地查询 到相关企业信息,企业信息查询页面的设计效果如图 5.22 所示。 图 5.22 企业信息查询页面的设计效果 企业信息查询页面所涉及的 HTML 表单元素如表 5.13 所示。 表 5.13 企业信息查询页面所涉及的 HTML 表单元素 名 称 类 型 含 义 重 要 属 性 searchs Form 表单
keywords text 关键字 types select 关键字类型 Submit submit 【查询】按钮 223 C H A P T E R 5 第 5 章 物流信息网 实现企业信息查询的关键代码如下: <% if request.form("keywords")="" then sql="select * from tb_EnterpriseMeg " str="暂时没有用户发布企业信息!" else sql="select * from tb_EnterpriseMeg where "&request.form("types")&" like ’%"&request. Form("keywords")&"%’ order by IssueDate desc" str="没有你所要查找的信息" end if rs.pagesize=10  page=request.QueryString("pages") 技术细节 QueryString 集合:获取作为跟在请求的 URL 的问号后面的文本传递给 Web 服务器 的值。通过使用 HTTP GET 方法或手工将表格的值添加到 URL,表格的值可以被附加在 请求的 URL 之后。QueryString 集合可以获取由以下 3 种方法传递的数据。 (1)直接在浏览器地址栏中输入链接 http://www.mingrisoft.com/Login.asp?UID=admin&PWD=manager (2)在 HTML 中使用超链接 (3)使用 Form 表单 QueryString 集合的语法格式如下。 Request.QueryString(variable)[(index)|.Count] Request.QueryString(参数)的值是出现在 Query_String 中所有参数的值的数组。通过调 用 Request.QueryString(parameter).Count 可以确定参数有多少个值。同一个表单中,多个 元素可以有相同的名字。 if page="" then page=1 end if rs.open sql,conn,1,3 if not rs.eof or not rs.bof then  rs.absolutepage=cint(page) i=0 while not rs.eof i=i+1 formname="form"&i %>  代码导读  QueryString 集合:主要用于获取作为跟在请求的 URL 问号后面的文本传递给 Web 服务器的值。  CInt 函数:主要用于返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 企业信息查询页面的运行结果如图 5.23 所示。 主要应用 order by 语句对企业企业进行排 224 SQL Server 2005 数据库系统开发案例精选 图 5.23 企业信息查询页面运行结果 5.13.2 企业信息删除 在企业信息管理模块中,通过单击【管理】按钮将进入企业信息删除页面,在该页面 中单击【删除】按钮,指定的企业信息将被删除。实现该功能主要通过传递企业信息的 ID 号,作为删除指定企业信息的条件。关键代码如下: <% id=request.Form("id") sql="delete from tb_EnterpriseMeg where ID="&id rs.open sql,conn set rs=nothing conn.close set conn=nothing %> <% sql="select * from tb_EnterpriseMeg where ID="&id rs.open sql,conn if rs.eof or rs.bof then %> <% else %> <% end if %> <% set rs=nothing 主要应用 delete 语句删除指定的企业信息 225 C H A P T E R 5 第 5 章 物流信息网 conn.close set conn=nothing %> 5.14 物流知识管理模块设计 物流知识管理模块主要包括物流知识添加、物流知识删除、物流知识修改 3 部分。在 物流知识管理页面中,单击“知识讲解信息添加”超链接添加企业物流知识;单击【管理】 按钮进入物流知识管理页面,在该页面中可以对指定的物流知识信息进行修改、删除操作。 下面分别对这 3 部分进行详细介绍。 5.14.1 物流知识添加 单击“知识讲解信息添加”超链接,进入物流知识添加页面添加相应的物流知识。物 流知识添加页面的设计效果如图 5.24 所示。 图 5.24 物流知识添加页面的设计效果 物流知识添加页面所涉及的 HTML 表单元素如表 5.14 所示。 表 5.14 物流知识添加页面所涉及的 HTML 表单元素 名 称 类 型 含 义 重 要 属 性 form1 Form 表单
reside select 知识分类 title text 讲解标题 content textarea 讲解内容 Submit2 button 【添加】按钮 Submit reset 【重置】按钮 226 SQL Server 2005 数据库系统开发案例精选 在进行物流知识添加时,需要注意的是相同标题的信息不能进行添加。如果该信息必 须添加,此时需要更改标题或将同标题的信息删除后再重新进行添加。实现添加物流知识 功能的代码如下: <%  title=request.form("title") content=request.form("content") reside=request.Form("reside")  sql="select * from tb_KnowLedgeMeg where Title=’"&title&"’ and Reside=’"&reside&"’" rs.open sql,conn if not rs.eof or not rs.bof then %> <% set rs=nothing  conn.close set conn=nothing %> <% else %> <% sql="insert into tb_KnowLedgeMeg values(’"&title&"’,’"&content&"’,’"&Date()&"’,’"&reside&"’)" rs.open sql,conn set rs=nothing conn.close set conn=nothing %> <% sql="select * from tb_KnowLedgeMeg where Title=’"&title&"’ and Reside=’"&reside&"’" rs.open sql,conn  if rs.eof or rs.bof then %> <% else %> <% end if %> <% end if %> 227 C H A P T E R 5 第 5 章 物流信息网  代码导读 Form 集合:使用 POST 方法将 HTML 表单提交给服务器时,表单元素可以作为 Form 集合的成员来检索。  And 运算符:主要用于对两个表达式进行逻辑与运算。  close 语句:主要用于关闭指定的记录集。 If...Then...Else 语句:根据表达式的值有条件地执行一组语句。 物流知识添加页面的运行结果如图 5.25 所示。 图 5.25 物流知识添加页面的运行结果 5.14.2 物流知识修改 在物流知识管理页面中,单击【修改】按钮进入信息修改页面。在该页面中如果用户 没有对相关信息进行修改操作,则单击【修改】按钮时,系统将给予相应的提示信息。相 关代码如下: <% id=request.form("id") title=request.form("title") content=request.form("content") sql="select * from tb_KnowledgeMeg where Title=’"&title&"’ and Content=’"&content&"’" rs.open sql,conn if not rs.eof or not rs.bof then %> <% set rs=nothing conn.close set conn=nothing %> <% else %> 228 SQL Server 2005 数据库系统开发案例精选 <% sql="update tb_KnowledgeMeg set Title=’"&title&"’,Content=’"&content&"’,IssueDate=’"&date()&"’ where ID="&id rs.open sql,conn set rs=nothing conn.close set conn=nothing %> <% sql="select * from tb_KnowledgeMeg where Title=’"&title&"’ and Content=’"&content&"’" rs.open sql,conn if rs.eof or rs.bof then %> <% else %> <% end if %> <% end if %> 5.14.3 物流知识删除 在物流知识管理页面中,通过单击【删除】按钮实现物流知识的删除操作。代码如下: <% id=request.Form("id") sql="delete from tb_KnowledgeMeg where ID="&id rs.open sql,conn set rs=nothing conn.close set conn=nothing %> <% sql="select * from tb_KnowledgeMeg where ID="&id rs.open sql,conn if rs.eof or rs.bof then %> 229 C H A P T E R 5 第 5 章 物流信息网 <% else %> <% end if %> <% set rs=nothing conn.close set conn=nothing %> 5.15 会员信息管理模块设计 会员信息管理模块所具有的功能和其他管理模块基本相同,只是会员信息模块中增加 了“会员验证”功能。这主要是为了方便管理员的管理。会员注册成功后,必须由管理员 验证通过后,才可以进行添加信息操作,并可对自己添加的信息进行修改、删除等操作; 如果没有验证通过,则不能进行任何操作。下面主要对会员信息验证功能进行详细介绍。 会员信息验证模块页面的设计效果如图 5.26 所示。 图 5.26 会员信息验证页面的设计效果 会员信息验证页面所涉及的 HTML 表单元素如表 5.15 所示。 表 5.15 会员信息验证页面所涉及的 HTML 表单元素 名 称 类 型 含 义 重 要 属 性 form2 Form 表单 Submit2 submit 【验证】按钮 > Submit2 submit 【验证】按钮 id hidden 隐藏域 > 230 SQL Server 2005 数据库系统开发案例精选 设置【验证】按钮是否可用,当会员信息已通过“验证”,此时【验证】按钮为灰度即 不可用状态;当会员信息未通过“验证”时,该【验证】按钮为可用状态。代码如下: <% id=request.QueryString("id") sql="select * from tb_UserMeg where ID="&id rs.open sql,conn if not rs.eof then %>
<% if rs("OverPass")="通过" then %> > <% else %> <% end if %> >
>
判断会员信息是否通过“验证”,如果已通过“验证”,则赋予相应的功能权限;否则 将不能进行货物信息、车辆信息、企业信息的浏览。代码如下: <% id=request.form("id") %> <% sql="update tb_UserMeg set OverPass=’通过’ where ID="&id rs.open sql,conn set rs=nothing conn.close set conn=nothing %> <% sql="select * from tb_UserMeg where ID="&id&" and OverPass=’通过’" rs.open sql,conn 231 C H A P T E R 5 第 5 章 物流信息网 if rs.eof or rs.bof then %> <% else %> <% end if %> 会员信息验证模块的运行结果如图 5.27 所示。 图 5.27 会员信息验证模块运行结果 5.16 疑难问题分析解决 5.16.1 应用 FileSystemObject 组件实现网站计数器 应用 FileSystemObject 组件实现计数器的关键是如何判断用户是否为初次访问该页面, 如果是初次访问,则对计数器进行加 1 操作,否则只需读取计数器的值即可。在本案例中 将使用 session 参数来判断用户是否为初次访问。 FileSystemObject 组件实现计数器功能的程序代码如下: <% whichfile=server.mappath("counter/count.txt") Set fs=CreateObject("Scripting.FileSystemObject") Set thisfile=fs.opentextfile(whichfile) visitors=thisfile.readline if session("count")="" then visitors=visitors+1 session("count")="1" end if 232 SQL Server 2005 数据库系统开发案例精选 thisfile.close countlen=len(visitors) for i=1 to countlen response.write "" next set out=fs.createtextfile(whichfile) out.writeline(visitors) out.close set fs=nothing %> 技术细节 FileSystemObject 组件 ASP 并没有内置专用的对象来存取服务器端的文件夹与文件,若要存取服务器端的 文件夹与文件,必须使用 FileSystemObject 服务器组件,在应用该组件时需要应用 Server.CreateObject 方法建立一个 FileSystemObject 服务器组件的对象实例,该对象可以 创建、打开或读写文件,并可以对文件和文件夹进行新建、复制、移动、删除等操作。 FileSystemObject 组件对象实例的部分方法如下。 (1)CreateTextFile 方法 该方法用于获得用户指定的文件名并创建该文件,它返回一个 TextStream 对象,可 以用该对象在文件被创建后操作该文件。 (2)OpenTextFile 方法 该方法用于获得用户指定的文件名并打开该文件,利用它所带的参数可以对文件进行各 种操作。该方法也返回一个 TextStream 对象,应用该对象可以在文件被打开后操作该文件。 (3)BuildPath 方法 通过 BuildPath 方法可以在指定的路径后面添加文件或者文件夹名称。该方法只返回 指定的路径,不检查指定的路径是否正确。 (4)CopyFile 方法 通过 CopyFile 方法将一个或者多个文件从某位置复制到另一位置。 (5)CopyFolder 方法 通过 CopyFolder 方法将文件夹从某位置复制到另一位置。 (6)DeleteFolder 方法 通过 DeleteFolder 方法删除一个指定的文件夹以及其中的内容。 5.16.2 关闭子窗口时刷新父窗口 当用户完成提交、更改、删除数据的操作后,经常会出现当前操作已经完成的提示, 并关闭当前窗口,但关闭当前窗口后,父窗口的数据仍停留在原来的状态。可以通过刷新 父窗口的方法显示最新的数据库内容,程序代码如下: 5.16.3 强行关闭主窗口 在使用 JavaScript 脚本语言的 Window 对象的 Close 方法关闭当前窗口时,如果当前窗 口是主窗口或者是父窗口,将弹出是否关闭当前窗口的对话框,如果此时用户选择的是不 233 C H A P T E R 5 第 5 章 物流信息网 关闭,则将出现一个空白的窗口,反之则没有,虽然空白的窗口不影响程序的运行,但是 当用户遇到这样的情况时,对网站的印象会大打折扣,那么如何才能在关闭主窗口或者父 窗口时不弹出询问对话框呢?通过下面的代码可实现此功能:
5.16.4 使用 session 参数存储用户登录信息 用户登录成功后,将登录时的用户名信息存储在 session 参数中(本例中该参数的名称 为 name)。当用户进行物流详细信息查看时,详细信息展示页面在检索数据库并将结果集 输出到浏览器的同时,会将结果集中的发布人信息同存储用户登录信息的 session 参数作对 比,以此来判断该信息是否为当前用户发布的,如果是当前用户发布的,则赋予用户修改 和删除该信息的权限,否则当前用户只可以浏览该信息。 判断当前用户是否为当前信息的发布人的程序代码如下: <% id=request.QueryString("id") sql="select * from tb_CarMessage where ID="&id rs.open sql,conn if not rs.eof then %> <% if session("name")=rs("UserName") then %>
put name="id" type="hidden" value="<%=rs("ID")%>">
">
<% end if %> <% end if %> 5.17 程序调试及错误处理 笔者在开发物流信息网时,应用 FSO 组件编写的网站计数器在本机上运行一切正常, 而在其他机器上进行测试时,则出现图 5.28 所示的错误。 经过分析获知,笔者的主机硬盘采用的是 FAT32 分区,而测试的主机硬盘则采用 NTFS 分区。由于 NTFS 分区对用户权限进行严格限制,使每个用户只能按照系统赋予的权限进 234 SQL Server 2005 数据库系统开发案例精选 图 5.28 出现没有权限错误 行操作。这样可以充分保护网络系统与数据的安全,当一般用户需要对系统中的文件或文 件夹进行写操作时,就需要拥有足够的权限。此时可以通过如下步骤进行错误处理。 (1)以 Administrator 身份登录系统,只有 Administrator 才可以对用户的权限进行设置。 (2)在“我的电脑”中找到用于记录访客人数的 文件夹 Logistics。 (3)选中 Logistics 文件夹,在该文件夹上单击鼠标 右键,在弹出的快捷菜单中选择“属性”菜单项,将弹出 “Logistics 属性”对话框,在该对话框中选择“安全”选 项卡,如图 5.29 所示。 (4)选中用户名称列表中的 Users(MRMRKJSML\ Users)项,在下面的权限列表中将显示该用户所拥有 的权限,选择“完全控制”所对应的“允许”复选框, 此时“修改”和“写入”所对应的“允许”复选框也 同时被选中,即用户可以完全控制(包括修改、写入、 读取及运行)该文件。单击【确定】按钮即可。 此时刷新浏览器后,该网页将正常运行,同时显 示访客人数。如图 5.30 所示。 图 5.30 计数器正常显示  注意 在 NTFS 分区格式下链接 Access 数据库也需要设置数据库文件的访问权限。 图 5.29 “Logistics 属性”对话框 6 供求信息网 开发导读 实例说明  实例名称:供求信息网  实例路径:光盘\mingrisoft\ 供求信息网。  实例运行文件:光盘\mingris- oft\供求信息网\Index.asp。  用户名:mr。  密码:mrsoft。  用户在使用本实例前,请仔细 阅读光盘中的光盘使用说明、 程序界面修改配置说明书、安 装说明书、使用说明书,这样 可以使您更好地学习和使用本 实例。 在计算机中使用本章实例的源程序,用户需安装 Microsoft Visual Studio 2005 或其他网页开发工具。 本实例需要配置 IIS,配置说明详见 5.6.2 节或光 盘使用说明。 本实例数据库为 SQL Server 2005,使用本实例 前,请安装 SQL Server 2005。安装时,验证模式为 混合模式,用户名为 sa,密码为空。 本实例提供了 5 套程序背景和素材,有些格式需 要使用特殊软件处理。 如要修改 JPG/GIF 格式文件,需要安装 Photoshop 图像编辑软件。 236 SQL Server 2005 数据库系统开发案例精选 本案例由多个程序界面组成,下面仅列出几个典型界面,其他界面参见光盘中的源 程序。 网站首页 企业用户注册页面 需求信息展示页面 供求信息发布页面 后台企业用户信息查看页面 供求信息删除页面 后台留言管理页面 供求信息审核页面 237 C H A P T E R 6 第 6 章 供求信息网 6.1 概 述 当今社会商家如要在商场上取得先机、消费者如要购买到称心如意的商品、刚刚毕 业的大学生如要抢先一步获得满意的工作⋯⋯答案就在于是否能找到一个广泛的、快速 的、自由的信息交流平台。于是,以因特网为基础的信息交流平台即供求信息网出现了。 供求信息网致力于优化信息交流,实现信息的快速交流。它与传统的信息交流相比有以 下几个优点。 (1)及时性:利用网络传输的快捷性,只要客户的信息一发布,在因特网中的任何 地方都能够浏览到。无疑,这种快捷性使得用户在发布信息和获得信息上都快人一步, 抢得先机。 (2)广泛性:现在因特网遍布全球,无论是对于客户发布信息或者获得信息都具有很 大的选择范围。 (3)方便:只要能上网,就能很轻松地浏览或发布信息,而且,现在发布信息一般是 免费的,这比起找中介还能省下一笔费用。 供求信息网基于网络的开放性,具有良好的兼容性、通用性、可扩展性,可与其他互 联网服务实现良好的集成;网站采用.NET 开发,在稳定性和安全性方面比较有优势;系统 基于中文版 Windows 2003 Server 和 SQL Server 2005 开发⋯⋯ 6.2 系 统 分 析 6.2.1 需求分析 通过调查,要求供求信息网具有以下功能。  由于操作人员的计算机知识水平有限,要求有良好的人机界面。  管理系统用户,由于该系统的使用对象多,要求有较好的权限管理。  为充分展现网站的交互性,供求信息网采用动态网页技术实现用户信息在线发布。  使用留言板作为网站管理人员与客户之间的主要交流工具。  当外界环境(停电、网络病毒)干扰本系统时,系统可以自动保护原始数据的安全。  在相应的权限下,删除数据方便简单,数据稳定性好。  数据计算自动完成,尽量减少人工干预。  安全退出系统。 6.2.2 可行性分析  经济性 供求信息网致力于免费地为个人和企业提供一个自由、快速的信息交流空间,实现了 供求信息的自由快速传播。  技术性 通过信息发布管理,实现了个人或企业快速发布信息的功能,同时也实现了对发布信 息的审核功能。 238 SQL Server 2005 数据库系统开发案例精选 6.3 总 体 设 计 6.3.1 项目规划 根据供求信息网的需求,可以将其分为前台和后台两个部分设计。  前台展示模块 前台主要实现了用户注册、用户登录、供求信息展示、供求信息查询、供求信息发布、 留言板留言、详细信息查看等功能。  后台管理模块 后台实现了管理员对供求信息的查询、审核和删除及对会员账户的冻结及删除功能。 6.3.2 系统功能结构图 供求信息网的前台功能结构如图 6.1 所示。 供求信息网的后台功能结构如图 6.2 所示。 供求信息网前台 会 员 登 录 后 台 入 口 留 言 板 人 才 市 场 服 务 信 息 代 理 信 息 合 作 信 息 供 应 信 息 需 求 信 息 会 员 注 册 转 让 信 息 图 6.1 供求信息网前台功能结构图 图 6.2 供求信息后台功能示意图 6.4 系 统 设 计 6.4.1 设计目标 本系统是为了提供一个中小型信息交流平台而设计的。主要实现如下目标。  本系统采用人机对话的方式,界面友好、信息查询准确、快速、数据存储安全可靠。  管理员可以对用户发布的信息进行审核。一旦用户发布了不良信息,管理员可以 对该信息标志为“未通过”,使该信息不能显示在前台页面上。  管理员可以对经常发布不良信息的用户进行“封号”处理。该用户将不能再登录。  对用户输入的数据,网站进行严格的数据检验,尽可能排除人为的错误。  网站最大限度的实现了易维护性和易操作性。  网站运行稳定、安全可靠。 6.4.2 开发及运行环境 硬件平台: 239 C H A P T E R 6 第 6 章 供求信息网  CPU P4 1.8GHz;  内存 512MB 以上。 软件平台:  操作系统 Windows XP/Windows 2000/Windows 2003(推荐)。  数据库 SQL Server 2005。  开发环境 Microsoft .NET Framework SDK v2.0。  开发工具 Microsoft Visual Studio 2005。  开发语言 C#语言。  服务器 IIS 6.0。  浏览器 IE 5.0,推荐使用 IE 6.0。  分辨率最佳效果 1024×768 像素。 6.5 数据库设计 本系统数据库采用 SQL Server 2005 数据库,系统数据库名称为 db_ggxxgl。数据库 db_ggxxgl 中包含 6 张表。下面分别给出主要数据表的实体 E-R 图、主要数据表结构及数据表概要说明。 6.5.1 数据表的实体 E-R 图 根据数据表结构的设计,规划出相应的实体 E-R 图,这些实体中包含各种具体信息, 并通过相互之间的作用形成数据的流动。具体数据表的实体 E-R 图描述如下。 图 6.3 为留言板信息实体 E-R 图。 图 6.4 为回复留言信息实体 E-R 图。  留言人 留言板信息实体 主题 留言时间留言ID 留言内容 回复留言ID 回复内容 回复留言信息实体 回复时间 回复主题 图 6.3 留言板信息实体 E-R 图 图 6.4 回复留言信息实体 E-R 图 6.5.2 主要数据表的结构 由于本书的篇幅所限,笔者在此只给出较为重要的数据表结构,其他数据表请参见本 书附带的光盘。  tb_Inf(发布信息表) 发布信息表用于存储客户发布的所有信息,该表的结构如表 6.1 所示。 表 6.1 tb_Inf 表的结构 字 段 名 数 据 类 型 长 度 主 键 否 描 述 id Int 4 是 信息 ID 自动编号 name Varchar 50 信息主题 userName Varchar 20 发布人 240 SQL Server 2005 数据库系统开发案例精选 续表 字 段 名 数 据 类 型 长 度 主 键 否 描 述 type Varchar 50 信息分类 content Varchar 50 信息内容 lineMan Varchar 50 联系人 phone Varchar 50 联系电话 address Varchar 50 地址 issueDate Datetime 8 发布日期 term Varchar 50 有效日期 check Bit 1 是否审核(默认值为 0)  tb_message(留言板信息表) 留言板信息表用于存储留言板中的所有留言信息,该表的结构如表 6.2 所示。 表 6.2 tb_message 表的结构 字 段 名 数 据 类 型 长 度 主 键 否 描 述 id Int 4 是 留言 ID,自动编号 Name Varchar 20 留言人 Title Varchar 20 主题 content Varchar 30 内容 date Datetime 8 留言时间  tb_answer(回复留言信息表) 回复留言信息表用于存储所有的留言回复信息,该表的结构如表 6.3 所示。 表 6.3 tb_ answer 表的结构 字 段 名 数 据 类 型 长 度 主 键 否 描 述 id Int 4 是 回复留言 ID,自动编号 content Varchar 30 回复内容 title varchar 100 回复主题 date Datetime 8 回复时间  tb_qy(企业用户注册表) 企业用户注册表用于存储所有注册企业的账号、密码及个人信息,该表的结构如表 6.4 所示。 表 6.4 tb_qy 表的结构 字 段 名 数 据 类 型 长 度 主 键 否 描 述 Id Int 4 是 用户 ID,自动编号 name Varchar 20 用户名 password Varchar 20 密码 enterpriseName Varchar 50 企业名称 enterpriseType Varchar 50 企业类型 workArea Varchar 50 经营范围 address Varchar 50 企业地址 241 C H A P T E R 6 第 6 章 供求信息网 续表 字 段 名 数 据 类 型 长 度 主 键 否 描 述 production Varchar 50 主要产品 email Varchar 50 E-mail 地址 phone Varchar 50 联系电话 net Varchar 50 企业网站 linkMan Varchar 20 联系人 linkAddress Varchar 200 通信地址 regdate Datetime 8 注册日期 Check Bit 1 是否冻结(默认值为 0) 6.5.3 数据表概要说明 从读者角度出发,为了使读者对本系统后台数据库中数据表有一个清晰的认识,笔者 在此特设计一个数据表树型结构图,该数据表树型结构图包含了系统中所有的数据表,如 图 6.5 所示。 图 6.5 数据表树型结构图 6.6 技 术 准 备 6.6.1 读者技术要求 要很好的学习本案例,读者要有一些 C#基础。熟悉在 Microsoft Visual Studio 2005 环 境中对数据进行添加、删除和修改等基本操作。熟悉 IIS 的配置。 6.6.2 配置 IIS 1.配置 IIS 在安装成功 IIS 之后,用户可以按照下面的步骤配置 IIS。 (1)依次选择“开始”→“设置”→“控制面板”→“管理工具”→“Internet 信息服 务(IIS)管理器”命令,弹出“Internet 信息服务(IIS)管理器”窗口。 (2)选择“默认网站”节点,单击右键,在弹出的快捷菜单中选择“新建”→“虚拟 目录”命令,弹出“虚拟目录创建向导”对话框。 242 SQL Server 2005 数据库系统开发案例精选 (3)单击【下一步】按钮,弹出“虚拟目录别名”对话框,在“别名”文本框中输入 “供求信息管理”。 (4)单击【下一步】按钮,弹出“选择目录路径”对话框,单击“路径”文本框后的 “浏览”按钮,在弹出的“浏览文件夹”对话 框中选择网站所在路径。 (5)单击【确定】按钮,将选择的网站路 径添加至“路径”文本框中。单击【下一步】 按钮,弹出“虚拟目录访问权限”对话框,如 图 6.6 所示。选择“运行脚本”复选框,单击 【下一步】按钮,单击【完成】按钮,完成 Internet 信息服务(IIS)管理器的配置。 配置完 Internet 信息服务(IIS)管理器之 后,用户就可以浏览该网站了(打开 IE 浏览 器,在地址栏中输入 htttp://localhost/PrInfo, 按〈Enter〉键即可浏览网站了)。 2.关于使用 IIS 常见问题分析  选择 ASP.NET 版本号 如果用户在本地既安装了 Microsoft Visual Studio 2005,又安装了 Microsoft Visual Studio 2003,则要求用户手动选择 ASP.NET 版本。在“Internet 信息服务(IIS)管理器” 窗口中右键单击已创建好的虚拟目录,在弹出的快捷菜单中选择“属性”命令,弹出图 6.7 所示的对话框。在“ASP.NET 版本”下拉列表中选择版本号(Microsoft Visual Studio 2003 对应的版本号是以 1.0 开头的,版本号根据 Microsoft Visual Studio 2003 版本不同而不同。 Microsoft Visual Studio 2005 版本号是以 2.0 开头的)。  权限问题 在上传图片时,如果出现某文件夹拒绝访问的问题,则在该文件夹上添加一个 EveryOne 用户并将其权限设置为完全控制,下面以 Images 文件夹为例,操作步骤如下。 (1)在 Images 文件夹上单击鼠标右键,在弹出的快捷菜单中选择“属性”命令,在弹出的 对话框中选择“安全”选项卡,单击【添加】按钮,弹出图 6.8 所示的“选择用户或组”对话框。 图 6.7 选择 ASP.NET 版本对话框 图 6.8 选择用户或组对话框 图 6.6 虚拟目录访问权限 243 C H A P T E R 6 第 6 章 供求信息网 (2)单击“选择用户或组”对话框中的【高级】按钮,弹出图 6.9 所示的对话框。 (3)单击“立即查找”按钮,在搜索结果栏中找到 EveryOne 用户,单击“确定”按钮 将其添加到“安全”选项卡中,如图 6.10 所示。 图 6.9 选择用户或组对话框 图 6.10 添加 EveryOne 用户 (4)在 EveryOne 的权限中选择“完全控制”,完成用户添加。 6.6.3 文件管理规划 开发 ASP.NET 程序时,首先要创建很多 Web 页、用户控件以及类,来完成基本的功能操作。 不过,在编写代码之前,可以先把网站中可能用 到的文件夹创建出来(例如:创建一个名为 Image 的文件夹,用于保存网站中需要的图片),这样 可以方便以后的开发工作,也可以规范网站的整 体架构。因此在开发该网站之前,笔者首先设计 了图 6.11 所示的文件夹结构图,在开发时只需将 相应文件保存到对应文件夹下即可。 6.7 公共模块编写 6.7.1 Web.Config 文件设计 在本网站中,Web.Config 文件主要配置参数是连接数据库的字符串,配置好之后,就 省略了在其他页面中一遍又一遍地写连接数据库的字符串的操作。要设置它,只要在 add 标记内写如下代码: 图 6.11 文件管理规划 244 SQL Server 2005 数据库系统开发案例精选 6.7.2 DB(数据库操作)类 公共类的编写可以减少重复代码,并且有利于代码维护。 在解决方案资源管理器的项目名称上右键单击项目文件,在弹出的快捷菜单中选择“添 加新项”命令,弹出“添加新项”对话框,选择“类”,修改名称为 DB.cs。如图 6.12 所示。 图 6.12 创建类文件 1.DB 类中的 GetCon()方法 GetCon 方法用于取得连接数据库字符串,打开数据库连接,返回一个 SqlConnection 类型的 con 对象。代码如下: public static SqlConnection GetCon() { SqlConnection con = new SqlConnection(ConfigurationManager.AppSettings["DSN"]);//用Conf igurationManager的AppSettings属性取得连接字符串 con.Open();//打开连接 return con; } 2.DB 类中的 ExSql()方法 ExSql()方法需要获取 SQL 语句即 string 类型字符串,然后连接数据库,对数据库进行 操作之后,再返回到数据库。代码如下: public static bool ExSql(string str) { SqlConnection conn = DB.GetCon();//连接上数据库,并打开了连接 SqlCommand com = new SqlCommand(str,conn); com.ExecuteNonQuery();//返回受影响的行数 return true; conn.Close();//关闭连接 } 3.DB 类中的 reDs()方法 reDs 方法用于返回一个 DataSet 对象,使用它的时候传入一个 SQL 语句作为参数,根 245 C H A P T E R 6 第 6 章 供求信息网 据参数返回对应的数据集。代码如下: public static DataSet reDs(string str) { SqlConnection conn = DB.GetCon();//连接上数据库,并打开了连接 SqlDataAdapter da = new SqlDataAdapter (str, conn); DataSet ds = new DataSet(); da.Fill(ds); return ds;//返回DataSet对象 } 4.DB 类中的 reDr 方法 reDr 方法返回一个 SqlDataReader 对象,根据输入的参数以 SqlDataReader 对象返回检 索到的符合条件的一组数据。代码如下: public static SqlDataReader reDr(string str) { SqlConnection conn = DB.GetCon(); SqlCommand com = new SqlCommand(str, conn); SqlDataReader dr = com.ExecuteReader(); return dr;//返回SqlDataReader对象dr conn.Close();//关闭连接 } 6.7.3 创建用户控件 Web 用户控件主要是方便重复使用,当某个模块要多次用到就可以将该模块创建成 Web 用户控件。在解决方案资源管理器中,右键单击项目文件,在弹出的快捷菜单中选择 “添加新项”→“Web 用户控件”命令,弹出“添加新项”对话框。在“名称”文本框中输 入 header.ascx,单击【添加】按钮创建成功。在此控件中主要实现了用户登录、导航、进 入用户注册界面和留言板的功能。用户控件的页面设计如图 6.13 所示。 图 6.13 用户控件设计图 1.前台页面设计 header.ascx 页面中主要使用的控件及控件用途如表 6.5 所示。 表 6.5 header.ascx 用到的控件列表 工 具 箱 控 件 名 称 数 量 用 途 HTML Table 3 布局页面 标准 DropDownList 1 选择用户登录类型 标准 TextBox 2 数据录入 标准 LinkButton 4 进入相应的页面 246 SQL Server 2005 数据库系统开发案例精选 续表 工 具 箱 控 件 名 称 数 量 用 途 标准 Label 1 显示用户名 导航 SiteMapPath 4 导航条 主要控件的属性设置如下。 (1)TextBox 控件的属性设置:在该页面中有两个 TextBox 控件,其 ID 分别为 txtName 和 txtPassword。txtName 在用户登录时接受用户名,txtPassword 接受用户密码。设置 txtPassword 的 TextMode 属性为 Password。 (2)DropDownList 控件的属性设置:该控件主要用来存放用户设置的下拉选择条件, 这里设置该控件的 ID 属性为 ddlType,Items 属性分别为“企业用户”、“个人用户”。 (3)SiteMapPath 控件的属性设置:SiteMapPath 是网站站点导航控件。在该页面中有 4 个 SiteMapPath,它们被用来链接到站点的各个页面。 2.后台功能代码 在命名空间区域中,引用 using System.Data.SqlClient 命名空间。在该页的页面加载事 件中,主要判断用户是否登录以及通过代码给 DropDownList 控件添加固定子项。该页 Page_Load 事件代码如下: protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { this.ddlType.Items.Add(new ListItem("企业用户")); this.ddlType.Items.Add(new ListItem("个人用户")); } if (Session["flag"] != null)//如果用户合法登录 { this.labUserName.Text = DB.UserName; } else { Session["userName"] = ""; } } 单击【登录】按钮时,将触发 Click 事件,在 Click 事件中判断用户是否合法。如果是 合法用户,将 Session["flag"]设为 true,否则为 false。功能代码如下: protected void lnkbtnOK_Click(object sender, EventArgs e) { string cmdText=string.Empty; if (this.ddlType.SelectedValue.ToString() == "企业用户")//选择企业类型登录 { cmdText = "select * from tb_qy where [check]=’0’and"; cmdText += name = "’" + this.txtUserName.Text.Trim() + "’"; cmdText+= "and passWord=’" + this.txtPassword.Text.Trim() + "’"; } if (this.ddlType.SelectedValue.ToString() == "个人用户")//选择个人类型登录 { 247 C H A P T E R 6 第 6 章 供求信息网 cmdText = "select * from tb_per where [check]=’0’and"; cmdText += name = "’" + this.txtUserName.Text.Trim() + "’"; cmdText+= "and passWord=’" + this.txtPassword.Text.Trim() + "’"; } SqlDataReader dr = DB.reDr(); dr.Read(); if (dr.HasRows)//该用户存在 { Session["flag"] = true;//Session["flag"]用来辨别用户是否合法登录 DB.UserName = this.txtUserName.Text.Trim(); this.labUserName.Text = this.txtUserName.Text.Trim(); } else { Session["flag"] = false; Response.Write(""); } //清空TextBox控件文本 this.txtUserName.Text = ""; } 单击【退出登录】按钮时,将触发 Click 事件,在 Click 事件中把 Session["flag"]设为 空,使用户处于非登录状态。代码如下: protected void lnkbtnOut_Click(object sender, EventArgs e) { if (Session["flag"] != null)//判断是否已经登录 { Session["flag"] = null;//已经登录则由登录状态变为非登录状态 this.labUserName.Text = ""; } } 单击【回到主页】按钮时,将触发 lbn_index_Click 事件,在此事件中使用 Response 方法来链接到目标页。代码如下: protected void lbn_index_Click(object sender, EventArgs e) { Response.Redirect("~/index.aspx");//链接到主页 } 单击【没有注册?】按钮时,将触发 lnkbtnjudge_Click 事件,在此事件中使用 Response 方法来链接到目标页。代码如下。 protected void lnkbtnjudge_Click(object sender, EventArgs e) { //判断当前页的URL是否为主页 if (Request.RawUrl == "/Index.aspx") { Response.Write(""); } else { Response.Write(""); } } 248 SQL Server 2005 数据库系统开发案例精选 6.8 网站前台主要功能模块设计 6.8.1 前台文件总体架构 1.模块功能介绍 前台页面主要包括以下功能模块。  网站导航模块:包括功能导航条模块。  会员模块:主要包括会员登录、注册两个部分。  信息发布模块:主要包括会员信息发布和留言板留言两大部分,其中会员信息发 布包含供应信息发布、需求信息发布、合作信息发布、代理信息发布、服务信息发布、转 让信息发布、招聘信息发布和求职信息发布 8 个部分。  信息展示模块:包括供应信息展示、需求信息展示、合作信息展示、代理信息展示、 服务信息展示、转让信息展示、招聘信息展示、求职信息展示和留言板留言信息展示 9 个部分。  详细信息查看模块:包括会员发布详细信息查看模块。  最新发布信息展示:展示包括在各类信息中发布日期排名前 5 位的信息。  后台登录入口:为管理员进入后台提供一个入口。 2.文件架构 供求信息网前台文件架构如图 6.14 所示。 图 6.14 供求信息网前台文件架构 6.8.2 网站首页设计 首页主要提供了会员注册、会员登录、展示客户发布的最新信息、导航进入各类信息 展示页和登录发布信息页、以及进入留言板留言等功能。用户可以通过功能导航条进入对 应的信息展示页面。首页运行结果如图 6.15 所示。 249 C H A P T E R 6 第 6 章 供求信息网 图 6.15 首页运行结果 1.前台页面设计 网站首页中主要使用的控件及控件用途如表 6.6 所示。 表 6.6 首页控件列表 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 3 布局页面 数据 GridView 4 显示数据 标准 LinkButton 4 实现页面跳转 本页主要用到了 GridView 控件,GridView 控件主要用来显示数据,并可对数据进 行选择、排序、分页、编辑和删除操作。在本页面中 GridView 实现了对数据的绑定和分 页功能,通过后台代码将一个表或者视图作为数据源绑定到 GridView 上,GridView 默 认就会将数据源上的所有字段显示出来。如果你不想让所有的字段显示,可将 GridView 控件的 AutoGenerateColumn 属性设为 false(默认为 true)然后,单击“ ”图标按钮打 开“GridView 任务”快捷菜单,选择“编辑列”命令,打开“字段”对话框,如图 6.16 所示。 在“可用字段”列表中选定 BoundField 列,单击【添加】按钮,绑定列就被加到“选 定的字段”列表中。对于绑定列,一般有两个属性要设置,即显示页眉文本的 HearderText 属性和控件所绑定的字段的 DataField 属性。例如,在本页加入了页眉文本为“信息主题” 的绑定列,其 DataField 属性为 name。按上述方法添加其余的绑定列。 250 SQL Server 2005 数据库系统开发案例精选 图 6.16 “字段”对话框 在“可用字段”列表中,选择 HyperLinkField 项,单击【添加】按钮,超级链接列就 被添加到“选定的字段”列表中。对于超级链接列,一般有 4 个属性要设置,即控制页眉 文本的 HearderText 属性、控制按钮文本的 Text 属性、控制绑定到超链接的 NavigateUrl 属 性的 DataNavigateUrlFields 属性、控制绑定到超链接的值应用的格式设置的 DataNavigate UrlFromatString 属性。例如,在本页超级链接列的 HearderText 和 Text 属性值都为“详细 信息”,其 DataNavigateUrlFields 属性值为 id,DataNavigateUrlFromatString 属性值为 show Details_inf.aspx?id={0}。“详细信息”列的作用是单击【详细信息】按钮,超链接到 show Details_inf.aspx 页并向它传一个 ID 值。 2.后台功能代码 在命名空间区域中,引用 using System.Data.SqlClient 命名空间。 在 Page_Load 页装载事件中,编写调用自定义方法绑定对应的 GridView 控件,将最新 发布的供求信息显示在主页上。详细代码如下: protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { this.GV1_DataBind(); this.GV2_DataBind(); this.GV3_DataBind(); this.GV4_DataBind(); } } 方法 GV1_DataBind 将最新发布的且通过管理员审核的需求信息或供应信息绑定到 GridView 控件上。详细代码如下: public void GV1_DataBind() { SqlDataReader dr1 = DB.reDr("select top 5 * from tb_inf where [check]=’1’ and (type=’需求信息’or type=’供应信息’) order by issueDate desc "); this.GridView1.DataSource = dr1; 调用方法绑定GridView控件 this.GridView1.DataKeyNames = new string[] { "id" }; this.GridView1.DataBind(); } 方法 GV2_DataBind 将最新发布的且通过管理员审核的合作信息或代理信息绑定到 调用 GV1_DataBind 方 法绑定 GridView 控件 返回 5 条最新发布且通过审 核的需求信息或供应信息 251 C H A P T E R 6 第 6 章 供求信息网 GridView 控件上。详细代码如下: public void GV2_DataBind() { //返回5条最新发布且通过审核的合作信息或代理信息 SqlDataReader dr2 = DB.reDr("select top 5 * from tb_inf where [check]=’1’ and (type=’合作信息 ’or type=’代理信息’ )order by issueDate desc "); this.GridView2.DataSource = dr2; this.GridView2.DataKeyNames = new string[] { "id" }; this.GridView2.DataBind(); } 方法 GV3_DataBind 将最新发布的且通过管理员审核的转让信息或服务信息绑定到 GridView 控件上。详细代码如下: public void GV3_DataBind() { //返回5条最新发布且通过审核的转让信息或服务信息 SqlDataReader dr3 = DB.reDr("select top 5 * from tb_inf where [check]=’1’ and (type=’转让信息 ’or type=’服务信息’)order by issueDate desc "); this.GridView3.DataSource = dr3; this.GridView3.DataKeyNames = new string[] { "id" }; this.GridView3.DataBind(); } 方法 GV4_DataBind 将最新发布的且通过管理员审核的招聘信息或求职信息绑定到 GridView 控件上。详细代码如下: public void GV4_DataBind() { //返回5条最新发布且通过审核的招聘信息或求职信息 SqlDataReader dr4 = DB.reDr("select top 5 * from tb_inf where [check]=’1’ and (type=’招聘信息 ’or type=’求职信息’) order by issueDate desc "); this.GridView4.DataSource = dr4; this.GridView4.DataKeyNames = new string[] { "id" }; this.GridView4.DataBind(); } 首页中有 4 个 LinkButton 按钮,分别链接到不同页面,以 ID 属性为 LinkButton1 的 LinkButton 为例,单击该按钮之后,使用 Redirect 方法跳转到目标页。详细代码如下: protected void LinkButton1_Click(object sender, EventArgs e) { Response.Redirect("~/Commom/demand.aspx"); } 技术细节 在使用 DataList 控件显示数据时,用到了 DataBinder.Eval()方法来绑定数据源中的某 一个字段。DataBinder.Eval()方法有 3 个参数。表示格式如下。 <%# DataBinder.Eval(Container.DataItem,"字段名","{0:d}")%> 也可以写成这样: <%# DataBinder.Eval(Container,"DataItem.字段名","{0:d}")%> 它们是等价的 这 3 个参数分别是数据项的命名容器、数据字段名和格式字符串。其中第 3 个参数可 以不提供。只有当需要格式转换时才使用它。例如用户需要把数据库中长日期格式转换成 短日期格式时,才需要使用它。 252 SQL Server 2005 数据库系统开发案例精选 6.8.3 信息展示页设计 信息展示页包括需求信息、供应信息、合作信息、代理信息、转让信息、服务信息、 招聘信息、求职信息 8 部分。这 8 部分分别展示了不同类别的信息。下面以需求信息模块 为例来介绍。需求信息页面运行结果如图 6.17 所示。 图 6.17 需求信息页面运行结果 1.前台页面设计 需求信息页面中主要使用的控件及控件用途如表 6.7 所示。 表 6.7 需求信息页面中主要使用的控件及控件用途 工 具 箱 控 件 名 称 数 量 用 途 HTML Table 3 布局页面 标准 LinkButton 2 实现跳转页面 标准 panel 1 实现多控件隐藏 数据 GridView 1 显示数据 主要控件的属性设置如下。 Panel 控件属性设置:Panel 控件可以实现将 Panel 控件中的所有控件整体隐藏或显示。 在本页中 Panel 的 ID 属性设置为 panel1,Visible 属性默认为 true。 GridView 控件属性设置:在本页中,GridView 控件实现了对数据的分页显示。本页中 将 GridView 控件的 Id 属性设置为 gv_demand,AllowPaging 属性设为 true(它默认为 false), 253 C H A P T E R 6 第 6 章 供求信息网 通过 PageSize 属性来控制一页显示多少行数据,在本页设为 4。 2.后台功能代码 在命名空间区域中,引用 using System.Data.SqlClient 命名空间。 在 Page_Load 页装载事件中,绑定 ID 属性为 gv_demand 的 GridView 控件,将需求信 息显示在页面上。详细代码如下: protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { this.bind();//绑定GridView 控件 } } 方法 bind 将所有通过网站管理员审核的信息按照发布日期的先后显示在页面上(新发 布的信息显示在页面的前面),详细代码如下: public void bind() { string cmdText="select * from tb_inf where [check]=’1’and type=’需求信息’ order by issueDate desc "; DataSet ds = DB.reDs(cmdText); this.gv_demand.DataSource = ds; this.gv_demand.DataBind(); } 对 GridView 控件进行分页时,要触发 GridView 的 OnSelectedIndexChanging 事件。在 OnSelectedIndexChanging 事件中编写如下代码: protected void gv_demand_PageIndexChanging(object sender, GridViewPageEventArgs e) { this.gv_demand.PageIndex = e.NewPageIndex; this.gv1_DataBind(); } 当单击【发布信息】按钮时,触发其 Click 事件,在此事件中判断用户是否登录,如 果登录了进入到信息发布页面,否则提示用户登录。详细代码如下: protected void lnkButtonOK_Click(object sender, EventArgs e) { if (Session["flag"] == null)//判断用户是否登录 { //提示登录 Response.Write(""); } else { Response.Redirect("~/Commom/issueInformation.aspx");//进入信息发布页 } } 6.8.4 用户注册模块设计 注册模块包括企业用户注册和个人用户注册。企业用户注册页面用于企业注册,个人 用户注册页面主要提供个人注册。由于它们的界面设计及功能代码都大致一样,所以在这 里只以企业注册页为例进行介绍。企业用户注册页运行结果如图 6.18 所示。 254 SQL Server 2005 数据库系统开发案例精选 图 6.18 企业注册页运行结果 1.前台页面设计 企业用户注册页面中主要使用的控件及控件用途如表 6.8 所示。 表 6.8 企业注册页面中主要使用的控件及控件用途 工 具 箱 控 件 名 称 数 量 用 途 HTML Table 2 布局页面 HTML Input(Reset) 1 清空 TextBox 中的数据 标准 Button 1 提交数据 标准 TextBox 14 数据录入 验证 RequiredFieldValidator 12 验证文本 TextBox 不能为空 验证 CompareValidator 1 用于比较两个文本框里的值 验证 RegularExpressionValidator 2 验证密码长度\E-mail 地址 标准 LinkButton 1 检查用户名是否存在 主要控件的属性设置如下。 (1)Input(Reset)控件属性设置:该控件是客户端控件,主要用来重置页面中的控件 设置,这里设置其 Value 值为“重置”。 (2)TextBox 控件属性设置:在本页中将 ID 为 txtPassWord 和 txtPassWordAgaind 的 TextBox 控件的 TextMode 属性设置为 Password。 (3)RequiredFieldValidator 控件属性设置:在本页中,RequiredFieldValidator 控件用来 验证 TextBox 控件的 Text 属性是否为空。由 ControlToValidate 属性来设置验证哪一个 Text Box 控件,由 ErrorMessage 属性来设置当 TextBox 控件的 Text 为空时,RequiredField Validator 控件提示的错误信息内容。 (4)CompareValidator 控件属性设置:CompareValidator 控件用来验证两个控件的 Text 255 C H A P T E R 6 第 6 章 供求信息网 属性是否满足一定的关系。通过 Type 属性来说明比较的数据类型,Type 类型有 string、integer 、 double、date、currency。在本页中 CompareValidator 控件用来验证两次密码输入是否一致。所以, Type 的属性值为 string。在本页中通过 ControlToVaildator 和 ControlToCompare 来设置 Id 分别为 txtpassWord 和 txtPassWordAgain 的 TextBox 控件相比较,由 ErrorMessage 属性来设置当 txtpassWord和txtPassWordAgain的Text属性不等时, CompareValidator控件提示的错误信息内容。 (5)RegularExpressionValidator 控件属性设置:RegularExpressionValidator 通过正则表达式 来验证控件的 Text 值的输入是否满足一定的规则。在本页面中分别用来判断密码长度是否在 6~16 和用户输入的 E-mail 地址是否正确。验证密码长度只要设置 RegularExpressionValidator 的 ValidationExpression 值为\w{6,16}。验证 E-mail 地址通过单击 ValidationExpression 属性打 开“正则表达式编辑器”选择“Internet 电子邮件地址”项后,单击【确定】即可。 2.后台功能代码 在命名空间区域中,引用 using System.Data.SqlClient 命名空间。 注册信息分为两类:必填信息和选填信息。填写了用户名之后,首先检测用户名是否 重复,如果没有重复则允许继续填写。填写完信息后单击【提交】按钮时,验证控件会验 证表单里的数据,如果通过验证,将注册信息保存到数据库中。详细代码如下: protected void btn_ok_Click(object sender, EventArgs e) { string userName = this.txtUserName.Text.Trim(); string passWord = this.txtPassWord.Text.Trim(); string pwdAgain= this.tztPassWordAgain.Text.Trim(); string question= this.txtQuestion.Text.Trim(); string answer= this.txtAnswer.Text.Trim(); string enterprisename= this.txtEnterpriseName.Text.Trim(); string enterpriseType= this.txtEnterpriseType.Text.Trim(); string workArea = this.txtWorkArea.Text.Trim(); string address= this.txtAddress.Text.Trim(); string email= this.txtEmail.Text.Trim(); string phone = this.txtPhone.Text.Trim(); string net= this.txtNet.Text.Trim(); string linkMan= this.txt.Text.Trim(); string linkAddress = this.txtCommunicateAddress.Text.Trim();  DateTime regDate=DateTime.Now; string sqlstr = "insert into tb_qy (name,passWord,question,answer,enterprisename,enterpriseType, "; sqlstr+=" workArea,address,email,phone,net,linkMan,linkAddress,regDate) "; sqlstr+= "values(’" + userName + "’,’" + passWord + "’,’" + question + "’,’" + answer + "’, "; sqlstr+="’" + enterpriseType + "’,’" + workArea + "’,’" + address + "’,’" + email + "’, "; sqlstr+="’" + enterprisename + "’ ,’" + phone + "’,’" + net + "’, "; sqlstr+="’" + linkMan + "’,’" + linkAddress + "’,’" + regDate.ToShortDateString() + "’)"; //把表单里的信息插入到数据库的SQL语句 try { DB.ExSql(sqlstr);//调用方法执行SQL命令 Response.Write(""); } catch { Response.Write(""); } } 使用局部变量获取用户输入信 息,然后向数据库中插入该信息 256 SQL Server 2005 数据库系统开发案例精选 单击【检测用户名】按钮,检查用户名是否在数据库中已经存在。详细代码如下: protected void lbtCheckName_Click(object sender, EventArgs e) { SqlConnection con = DB.GetCon(); //调用方法从数据库中检查用户名是否存在 SqlDataReader dr = DB.reDr("select * from tb_qy where name=’" + this.txtUserName.Text.Trim() + "’");  dr.Read(); if (dr.HasRows) {  Response.Write(""); this.txtUserName.Text = ""; } else { Response.Write(""); } }  代码导读  Now 函数:使用该方法取得当前系统时间。  Read 方法:使用 Read 方法读取下一条记录。  alert 方法:在 JavaScript 脚本中,使用该方法弹出带有用户自定义信息的窗体。 6.8.5 信息发布页设计 信息发布页是提供会员发布信息的页面。在该页面中用户将发布信息填写完整之后, 单击【提交】按钮,将信息保存到数据库中,等待管理员的审核。如果信息通过了审核,用 户发布的信息即可在网站上显示出来供访问者浏览。信息发布页面运行结果如图 6.19 所示。 图 6.19 信息发布页运行结果 257 C H A P T E R 6 第 6 章 供求信息网 1.前台页面设计 信息发布页面中主要使用的控件及控件用途如表 6.9 所示。 表 6.9 信息发布页面中主要使用的控件及控件用途 工 具 箱 控 件 名 称 数 量 用 途 HTML Table 1 布局页面 HTML Input(Reset) 1 清空 TextBox 中的数据 标准 Button 1 提交数据 标准 TextBox 6 数据录入 标准 DropDownList 1 显示发布类型 验证 RequiredFieldValidator 3 验证文本 TextBox 是否为空 验证 RangeValidator 1 有效日期范围 主要控件的属性设置如下。 (1)Input(Reset)控件属性设置:该控件是客户端控件,主要用来重置页面中的控件设 置,这里设置其 Value 属性值为“重置”。 (2)DropDownList 控件属性设置:该控件主要用来存放用户设置的下拉选择条件,这 里设置其 ID 属性为 ddlSelectType,Items 属性为“需求信息”、“供应信息”、“合作信息”、 “代理信息”、“转让信息”、“服务信息”、“招聘信息”、“求职信息”。 (3)RangeValidator 控件属性设置:RangeValidator 控件用来验证控件 Text 属性值是否 在给定的范围内。通过它的 Type 属性来控制验证对象 Text 属性值的类型。MaximumValue 和 MinimumValue 属性用来控制 Text 属性值的范围。在本页,要验证的是信息发布的有效 期的天数,故 Type 属性设置为 Integer。由于信息有效期为 15~120 天,把 MaximumValue 属性值设为 120,把 MinimumValue 属性值设为 15。 2.后台功能代码 在命名空间区域中,引用 using System.Data.SqlClient 命名空间。 在 Page_Load 页装载事件中,主要实现了用 Session["flag"]判断用户是否登录和在 Drip DownList 中添加项的功能。如果 Session["flag"]为空时提示用户没有登录然后跳转到首页。 代码如下: protected void Page_Load(object sender, EventArgs e) {  if (!IsPostBack) { //使用Add方法添加DropDownList控件的子项 this.ddlSelectType.Items.Add(new ListItem("--请选择类型--")); this.ddlSelectType.Items.Add(new ListItem("需求信息")); this.ddlSelectType.Items.Add(new ListItem("供应信息")); this.ddlSelectType.Items.Add(new ListItem("合作信息")); this.ddlSelectType.Items.Add(new ListItem("代理信息")); this.ddlSelectType.Items.Add(new ListItem("转让信息")); this.ddlSelectType.Items.Add(new ListItem("服务信息")); this.ddlSelectType.Items.Add(new ListItem("招聘信息")); this.ddlSelectType.Items.Add(new ListItem("求职信息")); //使用正则表达式使得在TextBox控件中只能输入数字 txtValidity.Attributes["onkeyup"] = "value=value.replace(/[^\\d]/g,’’)"; } 使用 Add 方法向 DropDownList 控件中添加子项 258 SQL Server 2005 数据库系统开发案例精选 if (Session["flag"] == null) { Response.Write(""); } } 当用户填写完信息后单击【提交】按钮时,触发 Click 事件,将发布信息保存到数据 库中,代码如下: protected void btnClickOk_Click(object sender, EventArgs e) { if (Session["flag"] != null) { if (this.txtContent.Text.Length < 200)//信息内容是否超过200字 { string DD_str = this.ddlSelectType.SelectedValue.ToString(); string Title = this.txtTitle.Text.Trim(); string Content = this.txtContent.Text.Trim(); string LinkMan = this.txtLinkman.Text.Trim(); string Phone = this.txtPhone.Text.Trim(); string Address = this.txtAddress.Text.Trim(); string Validity = this.txtValidity.Text.Trim(); DateTime dt = DateTime.Now;//取的系统时间  try { //用Session["userName"]取的用户名默认作为信息的发布人 string sqlstr = "insert into tb_inf values(’" + Title + "’, "; sqlstr+="’" + Session["userName"].ToString() + "’,’" + DD_str + "’,’" + Content + "’,"; sqlstr+=" ’" + LinkMan + "’,’" + Phone + "’,’" + Address + "’,’" + dt.ToShortDateString() + "’,’" + Validity + "’)"; DB.ExSql(sqlstr); Response.Write(""); } } else { Response.Write(""); } } else { Response.Write(""); } } 向发布信息表中插入一条记录 259 C H A P T E R 6 第 6 章 供求信息网  代码导读  IsPostBack 属性:判断页面是否第一次加载, 通过使用该属性来减少代码执行的 数量。  try⋯ catch 方法:在 try 块中放入容易产生异常的代码,在 catch 块中抛出异常。 6.8.6 留言板模块设计 留言板是网站管理者和普通用户之间沟通的一座桥梁。用户可以在留言板上发表自己对网 站的看法和建议,而管理员可以针对该用户的留言给予及时的反馈。留言板包括留言显示页和 回复信息查看页。留言板的留言显示页及回复信息查看页的运行结果如图 6.20 和图 6.21 所示。 图 6.20 留言显示页运行结果 图 6.21 回复信息查看页运行结果 1.留言信息显示页 留言信息显示页的主要功能是显示留言信息及用户发布信息。  前台页面设计 在留言信息显示页中主要使用的控件及控件用途如表 6.10 所示。 260 SQL Server 2005 数据库系统开发案例精选 表 6.10 留言信息显示页中主要使用控件及控件用途 工 具 箱 控 件 名 称 数 量 用 途 HTML Table 3 布局页面 HTML Input 1 清空 TextBox 中的数据 标准 Button 1 提交数据 标准 TextBox 6 数据录入 标准 LinkButton 2 单击导航到上一页\下一页 标准 Label 6 用于显示信息 数据 DataList 1 循环显示信息 验证 RequiredFieldValidator 2 验证文本 TextBox 是否为空 验证 RangeValidator 1 控制信息内容的长度 主要控件的属性设置如下。 (1)Input(Reset)控件属性设置:该控件是客户端控件,主要用来重置页面中的控件 设置,这里设置其 Value 属性值为“重置”。 (2)Label 控件属性设置:在本页,有 4 个 Label 控件被放在 DataList 控件的标记为 Item Templated 项的模板内,要使 Label 控件能够显示数据,需要设置其 Text 属性。设置 Id 分别为 labTitle、labUserName、labTime、labContent 的 Label 控件对应的 Text 属性的值依次为 ’<%# DataBinder.Eval(Container,"DataItem.title") %>’ ’<%# DataBinder.Eval(Container,"DataItem.name") %>’ ’<%# DataBinder.Eval(Container,"DataItem.issueDate") %>’ ’<%# DataBinder.Eval(Container,"DataItem.content") %>’ 其中 title、name、issueDate、content 分别为数据库中表的字段。 (3)DataList 控件属性设置:选中 ID 为 DataList1 的控件,单击“ ”图标在弹出的 “DataList 任务”快捷菜单中选中“编辑模板”命令,打开“模板编辑模式”,在“显示” 下拉列表中选择要编辑的项模板,如图 6.22 所示。在 DataList 项模板里添加一个表格用来 布局页面;添加 4 个 Label 控件用来显示数据;添加一个“查看回复”超链接文本,这个 超链接文本对应的代码为
’ text-decoration: none">查看回复 图 6.22 DataList 任务模板编辑模式 (4)RangeValidator 控件属性设置:RangeValidator 控件用来验证控件 Text 的文本值是 否在一定的范围内。本页中,RangeValidator 控件用来验证 txtContent 文本内容是否超过 200 字符。只要把 RangeValidator 的 type 属性值设为 string ,然后设置 MaximumValue 和 MinimumValue 的值分别为 200、0 即可。 261 C H A P T E R 6 第 6 章 供求信息网  后台功能代码 在留言信息显示页的命名空间区域中,引用 using System.Data.SqlClient 命名空间。 在 Page_Load 页装载事件中,编写调用自定义方法与 DataList 控件进行数据绑定的代 码。详细代码如下: protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { dl_DataBind(); } } 方法 dl_DataBind()将检索到的数据绑定到 DataList1 上显示出来并实现了分页的功能。 详细代码如下: public void dl_DataBind() { int CurrentPage = Convert.ToInt32(labNowPage.Text);//获取当前页数 PagedDataSource ps = new PagedDataSource();//生成PagedDataSource的实例 DataSet ds = DB.reDs("select * from tb_message"); ps.DataSource = ds.Tables[0].DefaultView; ps.AllowPaging = true; //是否可以分页 ps.PageSize = 4; //显示的数量 ps.CurrentPageIndex = CurrentPage - 1; //取得当前页的页码 lnkbtnFront.Enabled = true; lnkbtnNext.Enabled = true; if (CurrentPage == 1) { lnkbtnFront.Enabled = false;//不显示上一页按钮 } if (CurrentPage == ps.PageCount) { lnkbtnNext.Enabled = false;//不显示下一页 } this.labCount.Text = Convert.ToString(ps.PageCount); this.DataList1.DataSource = ps; this.DataList1.DataKeyField = "id"; this.DataList1.DataBind(); } 单击【上一页】按钮,将当前页数减 1,然后重新绑定 dataList 控件。详细代码如下: //上一页 protected void lnkbtnPrve_Click(object sender, EventArgs e) { this.labNowPage.Text = Convert.ToString(Convert.ToInt32(this.labNowPage.Text) - 1); this.dl_DataBind(); } 单击【下一页】按钮,将当前页数加 1,然后重新绑定 DataList 控件。详细代码如下: //下一页 protected void lnkbtnNext_Click(object sender, EventArgs e) { this.labNowPage.Text = Convert.ToString(Convert.ToInt32(this.labNowPage.Text) + 1); this.dl_DataBind(); } 262 SQL Server 2005 数据库系统开发案例精选 技术细节 使用 DataList 控件实现分页时,由于 DataList 控件本身不带与分页相关的属性。不能 像在 GridView 控件中利用其本身的分页属性比较简单的实现分页功能。 在 DataList 中,通过 PageDataSource 类来实现分页功能。该类封装了 DataGrid 控件 的分页属性。这里以 5.6.6 节中例子来演示该类的用法。 PagedDataSource ps = new PagedDataSource();//实例化 PagedDataSource 类 DataSet ds = DB.reDs("select * from tb_message");//生成数据集 ps.DataSource = ds.Tables[0].DefaultView;//获取绑定 DataList 的数据源 ps.AllowPaging = true; //是否可以分页 ps.PageSize = 4; //显示的数量 当用户填完留言信息时,单击【提交】按钮触发 Click 事件,在 Click 事件中先判断该 用户是否登录,如果没有登陆提示用户登录。如果已经登录使用 ExSql()方法将留言信息插 入到数据库中。代码如下: protected void btn_cilckok_Click(object sender, EventArgs e) { if (Session["flag"] != null)//判断用户是否登录 { DateTime dt = DateTime.Now;//取得系统时间 try { //用Session["userName"]取得用户名 DB.ExSql("insert into tb_message values(’" + Session["userName"].ToString() + "’,’" + this.txt_title.Text.Trim() + "’,’" + this.txt_content.Text.Trim() + "’,’" + dt.ToShortDateString() + "’)"); Response.Write(""); dl_DataBind(); this.txt_title.Text = ""; this.txt_content.Text = ""; } catch (Exception oe) { Response.Write(""); } } else { Response.Write(""); } } 2.回复信息查看页 由于回复信息查看页设计比较简单,在这里对其前台页面设计不做介绍,下面直接介 绍该页后台功能代码的实现。 首先,在该页命名空间区域中,引用 using System.Data.SqlClient 命名空间。 当用户单击“查看回复”超链接时,会向留言信息查看页传送该留言信息 ID,在 Page_Load 页装载事件时,使用 Request 方法接受 ID 值,根据值从数据库中检索回复信息, 如果该留言信息没有被回复则弹出“该留言还没有被回复!”的提示信息,然后跳转到留言 信息显示页,否则显示该留言信息的回复内容,具体代码如下: protected void Page_Load(object sender, EventArgs e) { 263 C H A P T E R 6 第 6 章 供求信息网 if (!IsPostBack) { this.labErrorMessage.Visible = false;  string strid = Request["id"].ToString(); string sqlstr = "select * from tb_answer where id=’" + strid + "’"; SqlDataReader dr = DB.reDr(sqlstr); dr.Read();  if (dr.HasRows) { this.dl_DataBind(); } else { Response.Write(""); } } }  代码导读  Request 方法:当请求页面使用.aspx?ID={0}的形式向该页面传值时,就可以使用 Request 方法来获得 ID 的值。  HasRows 属性:使用该方法来判断 SqlDataReader 对象中是否包含记录。 方法 dl_DataBind 使用 Request 方法接收 ID 的值,通过留言信息 ID 来检索该留言的回 复内容,通过 DataList 控件将回复内容显示在页面上。代码如下: public void dl_DataBind() { string strid = Request["id"].ToString(); string sqlstr = "select * from tb_answer where id=’" + strid + "’"; SqlDataReader dr = DB.reDr(sqlstr); DataList1.DataSource = dr; DataList1.DataKeyField = "userID"; this.DataList1.DataBind(); } 6.8.7 详细信息显示页 详细信息显示页用于显示会员发布信息的 详细内容。 当使用 GridView 控件来显示某个表的数据 时,会遇到由于表的字段太多或者某个字段内容 太长的情况。这样的话,如果绑定所有的字段会 使得 GridView 被数据撑的很长,不利于页面布 局。一般的解决方法是在 GridView 上加一个超 链接按钮,单击它时跳转到显示这条记录的详细 信息的页面上。本网站中,详细信息显示页的运 行效果如图 6.23 所示。 1.前台页面设计 详细信息显示页面中主要使用的控件及控件用途如表 6.11 所示。 图 6.23 详细信息显示页运行结果 264 SQL Server 2005 数据库系统开发案例精选 表 6.11 详细信息显示页面中主要使用的控件及控件用途 工 具 箱 控 件 名 称 数 量 用 途 HTML Table 1 布局页面 HTML Input(Button) 1 返回到上一页 标准 TextBox 10 显示数据 前台页面中主要控件属性设置如下。 (1)Input 控件属性设置:该控件是客户端控件,主要用来返回到上一页,这里设置其 Value 属性值为“重置”。它要实现返回到上一页的功能,还必须定义其单击事件。双击 Input 控件,在其单击事件中加入代码“history.go(-1);”。 (2)TextBox 控件属性设置:在本页中用到的 TextBox 的 ID 属性分别为 txtID、txtTitle、 txtUserName 、txtType、txtContent、txtLinkMan、txtPhone、txtAddress、txtIssueDate、txtTerm, 用来显示发布信息的详细信息。 2.后台功能代码 在命名空间区域中,引用 using System.Data.SqlClient 命名空间。 在 Page_Load 页装载事件中,实现了用 Request 方法接收到发布信息 ID 的值。通过 ID 检索到该记录,然后将该记录的详细内容显示在页面上。代码如下: protected void Page_Load(object sender, EventArgs e) { string id = this.Request["id"].ToString();//获取主键值 string sqlstr = "select * from tb_inf where id=’"+id+"’"; SqlDataReader sdr = DB.reDr(sqlstr);//用SqlDataReader检索数据 sdr.Read(); //绑定到TextBox this.txtID.Text=sdr["id"].ToString(); this.txtTitle.Text = sdr["name"].ToString(); this.txtUserName.Text = sdr["userName"].ToString(); this.txtType.Text=sdr["type"].ToString(); this.txtContent.Text = sdr["content"].ToString(); this.txtLinkMan.Text = sdr["lineMan"].ToString(); this.txtPhone.Text = sdr["phone"].ToString(); this.txtAddress.Text = sdr["address"].ToString(); this.txtIssueDate.Text = sdr["issueDate"].ToString(); this.txtTerm.Text = sdr["term"].ToString(); } 6.9 后台主要功能模块详细设计 6.9.1 后台总体架构 1.模块功能介绍 后台页面主要包括以下功能模块。 后台登录模块:管理员登录后台的入口。 会员资料管理模块:主要包括企业用户资料查看、个人用户资料查看、会员资料查询、 将 SqlDataReader 对象中的 记录绑定到控件上显示出来 265 C H A P T E R 6 第 6 章 供求信息网 会员资料删除、账户冻结处理等模块。 供求信息管理模块:主要包括供求信息查询、供求信息删除和供求信息审核等模块。 留言板管理:主要包括对留言信息的回复、查看和删除等功能。 2.文件架构 供求信息网后台文件架构,如图 6.24 所示。 图 6.24 供求信息网后台文件架构 6.9.2 后台登录页设计 后台登录页是网站管理员管理网站的入口,输入用户名和密码,通过验证后即可进入 后台。后台登录页的设计效果如图 6.25 所示。 图 6.25 后台登录页面设计效果 1.前台页面设计 后台登录页面中主要使用的控件及控件用途如表 6.12 所示。 266 SQL Server 2005 数据库系统开发案例精选 表 6.12 后台登录页中主要使用的控件及控件用途 工 具 箱 控 件 名 称 数 量 用 途 HTML Table 1 布局页面 HTML Input(Button) 1 返回到上一页 标准 Button 1 提交数据 标准 TextBox 2 数据录入 验证 RequiredFieldValidator 2 验证文本 TextBox 是否为空 后台页面中主要的控件属性设置如下。 (1)Input 控件属性设置:该控件是客户端控件,主要用来返回到上一页,这里设置其 Value 属性值为“返回”。它要实现返回到上一页,还必须定义其 Click 事件,在 Click 事件 中加入代码“history.go(-1);”。 (2)TextBox 控件属性设置:把 ID 为 txtPassword 的 TextBox 控件的 TextMode 属性设 置为 Password。 (3)RequiredFieldValidator 控件属性设置:在本页中,两个 RequiredFieldValidator 验证 控件的 ID 分别为 RequiredFieldValidator1 和 RequiredFieldValidator2,ControlValidate 属性 分别设置为 txtUserName 和 txtPassword,将 ErrorMessage 属性的值都设为“*不能为空”。 2.后台功能代码 在留言信息显示页的命名空间区域中,引用 using System.Data.SqlClient 命名空间。在 登录页面上填写完登录信息后,单击【登录】按钮,触发其 Click 事件,在 Click 事件中根 据用户输入的用户名和密码来判断该用户是否合法,如果不合法弹出错误信息,否则进入 到后台首页。详细代码如下: protected void btn_clickok_Click(object sender, EventArgs e) { string name = this.txtUserName.Text.Trim(); string pwd = this.txtPassword.Text.Trim(); SqlConnection con1 = DB.GetCon(); string cmdText="select * from tb_adm where userName=’" + name + "’ and passWord=’" + pwd + "’"; SqlCommand com = new SqlCommand(cmdText, con1); //返回查询结果集的第一行 int count = Convert.ToInt32(com.ExecuteScalar()); //如果查询结果大于零,则表示存在该用户 if (count > 0) { //使用Session["flag"]标记用户是否登录 Session["flag"] = true; Session["userName"] = this.txtUserName.Text.Trim(); //跳转到目标页 Response.Redirect("Default.aspx"); } else { Response.Write(""); } } 267 C H A P T E R 6 第 6 章 供求信息网 6.9.3 后台首页设计 后台管理首页主要由两大部分组成,一部分是功能导航区,另一部分是操作区。功能 导航区主要用于实现网站后台管理的导航功能;操作区主要用于显示要管理的内容,是使 用框架集实现的。后台管理首页的设计效果如图 6.26 所示。 图 6.26 后台管理首页设计效果 1.前台页面设计 把后台管理首页从“设计”切换到“源”模式,在适当的位置添上如下代码: 首页还应用到了 TreeView 控件,它使管理员可以清晰的查看信息的从属关系,方便管理 员的管理。在本页中,选中 ID 为 TreeView1 的控件,单击“ ”按钮,在弹出的“TreeView 任务”快捷菜单选中“编辑节点”项。打开“TreeView 节点编辑器”添加根节点和子节点, 如图 6.27 所示。在子节点(如 Text 属性为“企业用户资料”的节点)上设置其 NavigateUrl 图 6.27 节点编辑器 268 SQL Server 2005 数据库系统开发案例精选 属性值为~/page/show_qy.aspx,表示当用户单击“企业用户资料”节点时就会链接到 show_qy.aspx 页面。TreeView 的 Target 属性是设置链接到 show_qy.aspx 时,show_qy.aspx 页的 显示位置。在这里 show_qy.aspx 页将显示在被标记为 rightFrame 的框架内,然后在后台管理首 页的右边空白单元格加上代码“”,这样 show_qy.aspx 就会显示在首页的右边空白单元格内。 2.后台功能代码 在 Page_Load 页装载事件中,判断管理员是否登录,如果未登录,页面跳转向登录页 面。代码如下: protected void Page_Load(object sender, EventArgs e) { //判断用户是否登录 if (Session["flag"] == null) { //如果没有登录则跳转到登录页 Response.Redirect(""); } } 6.9.4 会员信息展示页设计 会员信息展示页包含企业会员信息和个人会员信息。由于这两页实现的功能基本上相 同,这里只介绍企业信息页。企业信息页展示了全部企业会员的信息。企业信息展示页的 运行结果如图 6.28 所示。 图 6.28 企业信息页面运行结果 1.前台页面设计 页面的主体是一个 GridView 控件,其 ID 属性为 GridView1,打开“属性”对话框, 设置 AllowPaging 属性为 true,单击“ ”图标按钮后双击 PageIndexChanging 事件,在 PageIndexChanging 事件中编写实现分页的代码。 关于 GridView 控件的使用方法请参见 5.8.1 节。 2.后台功能代码 在 Page_Load 页装载事件中,主要判断用户是否登录和绑定 GridView 控件。详细代码如下: 269 C H A P T E R 6 第 6 章 供求信息网 protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { //判断用户是否登录 if (Session["flag"] == null) { //如果没有登录则跳转到登录页 Response.Write(""); } //绑定GridView控件显示企业用户信息 this.GridView1_Show(); } } 在 GridView1_Show()方法中,调用 DB 类的静态方法 reDs 来返回一个 DataSet 类型的 数据集。并将它绑定到 GridView 控件在页面中显示出来。详细代码如下: public void GridView1_Show() { DataSet ds1 = DB.reDs("select * from tb_qy"); this.GridView1.DataSource = ds1; //设置GridView控件中项的主键 this.GridView1.DataKeyNames = new string[] { "id" }; this.GridView1.DataBind(); } 由于在数据库中冻结和未冻结的信息用数据类型为 bit 的数字表示(“0”表示未冻结, “1”表示已冻结)。在 GridView 中显示为 False 或者 True(False 表示数字“1”,True 表示 数字“0”)。因为在显示时不能显示 False 或者 True,所以必须把其转换成相应的汉字。在 GridView1 的 RowDataBound 事件中编写如下代码实现转换汉字的功能: protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e) { if (e.Row.RowType == DataControlRowType.DataRow) { if (e.Row.Cells[5].Text == "True") { //使用红色字体显示已冻结 e.Row.Cells[5].Text = "已冻结"; } else { e.Row.Cells[5].Text = "未冻结"; } } } 要实现 GridView1 控件的分页功能,应将 GridView1 控件的 AllowPaging 属性设为 True, 并在其 PageIndexChanging 事件中编写如下代码: protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e) { this.GridView1.PageIndex = e.NewPageIndex; this.GridView1_Show(); } 270 SQL Server 2005 数据库系统开发案例精选 6.9.5 资料删除页设计 资料删除页分为会员资料删除和供求信息删除两部分,由于它们无论是页面设计还是 功能实现都如出一辙,所以这里只以会员资料删除页为例来介绍。同会员信息展示页一样, 它们都在同一个页面上实现。管理员登录进入到会员删除页面之后,通过单选按钮选择删 除企业用户信息还是个人用户信息,然后输入要删除用户的 ID,查找出来之后,再删除。 会员资料删除页的运行结果如图 6.29 所示。 图 6.29 会员资料删除页页面效果图 1.前台页面设计 会员资料删除页面中主要使用的控件及控件用途如表 6.13 所示。 表 6.13 会员资料删除页面中主要使用的控件及控件用途 工 具 箱 控 件 名 称 数 量 用 途 HTML Table 2 布局页面 标准 Panel 2 实现部分控件的整体隐藏 标准 RadioButton 2 选择查询类型 标准 Button 1 查询对应 ID 的详细信息 数据 GridView 2 分别显示企业和个人数据 标准 TextBox 1 数据录入 验证 RequiredFieldValidator 1 验证文本 TextBox 是否为空 前台页面中主要控件属性设置如下。 (1)Panel 控件属性设置:Panel 控件能够使在 Panel 中的控件整体隐藏或显示。在本 页中 Panel 对应的 ID 分别是 Panel1、Panel2,其中 Panel1 是控制整个查询模块显示和隐藏 的,Panel2 控制 GridView1 的显示和隐藏。 (2)RadioButton 控件属性设置:RadioButton 又被称为单选按钮,通过 Checked 属性 来判断其是否被选中。一般由多个单选按钮放在一起使用,将它的 GroupName 属性设置为同 一个值。在运行时只能选择一个 RadioButton。在本页中,用到了两个 RadioButton 控件,其中 RadioButton1 的 Checked 属性默认为 True,Text 属性设置为“查询全部”,GroupName 属性设 置为“1”;RadioButton2 的 Text 属性设置为“按 ID 查询”,GroupName 属性设置为“1”。 (3)RequiredFieldValidator 控件属性设置:在本页中,它是用来验证 TextBox 控件的 Text 271 C H A P T E R 6 第 6 章 供求信息网 属性是否为空。由 ControlToValidate 属性来设置验证哪一个 TextBox 控件,由 ErrorMessage 属 性来设置当 TextBox 控件的 Text 为空时,RequiredFieldValidator 控件提示的错误信息内容。 (4)GridView 控件属性设置:在 ID 为 GridView1 的 GridView 控件上单击“ ”图标按钮, 打开“GridView 任务”快捷菜单,选择“编辑列”命令,打开“字段”对话框,在“可用字段” 列表中选定 CommandField 列,单击“+”号,展开 CommandField 节点,添加“删除”按钮列。 单击“删除”按钮列时会触发 GridView1 的 RowDeleting 事件。其他属性设置请参见 5.8.3 节。 2.后台功能代码 在会员资料删除页的命名空间区域中,引用 using System.Data.SqlClient 命名空间。在 Page_Load 页装载事件中,辨别用户是否登录及设置 Panel 的 Visible 属性来控制哪一部分 隐藏,哪一部分显示。代码如下: protected void Page_Load(object sender, EventArgs e) { this.Panel1.Visible = true; this.Panel2.Visible = false; if (!IsPostBack) { if (Session["flag"] == null) { Response.Write(""); } } } 由于在数据库中冻结和未冻结的信息用数据类型为 bit 的数字表示(“0”表示未冻结, “1”表示已冻结)。在 GridView 中显示为 False 或者 True(False 表示数字“1”,True 表示 数字“0”)。因为在显示时不能显示 False 或者 True,所以必须把其转换成相应的汉字。在 GridView1 和 GridView2 的 RowDataBound 事件中编写如下代码转换汉字: protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e) { if (e.Row.RowType == DataControlRowType.DataRow) { if (e.Row.Cells[5].Text == "True") { //用红色字体显示已冻结 e.Row.Cells[5].Text = "冻结"; } else { e.Row.Cells[5].Text = "未冻结"; } //单击删除按钮时,提示是否确定删除 ((LinkButton)(e.Row.Cells[6].Controls[0])).Attributes.Add("onclick", "return confirm(’确定删 除吗?’)"); } } 下面代码用来实现在 ID 为 GridView1 的 GridView 控件中删除某一行记录。在 Grid View1 的 RowDeleting 事件中添加如下代码: protected void GridView1_RowDeleting(object sender, GridViewDeleteEventArgs e) { 272 SQL Server 2005 数据库系统开发案例精选 //取得在GridView1中选中行的id string str= this.GridView1.DataKeys[e.RowIndex].Value.ToString(); string str1 = "delete tb_qy where id=’"+str+"’"; DB.ExSql(str1);//调用方法来执行删除命令 this.Panel2.Visible = false;//让包含在Panel2中的控件整体隐藏 Response.Write(""); } 在 GridView2 的 RowDeleting 事件中,实现在 ID 为 GridView2 的 GridView 控件中删 除某一行记录,代码如下: protected void GridView2_RowDeleting(object sender, GridViewDeleteEventArgs e) { //取得在GridWiew中选中行的id string str = this.GridView2.DataKeys[e.RowIndex].Value.ToString(); string str1 = "delete tb_per where id=’" + str + "’"; DB.ExSql(str1); this.Panel3.Visible = false; this.TextBox1.Text = ""; } 单击【查询】按钮,触发 Click 事件。在 Cilck 事件中编写代码来查找要删除用户的信 息,执行删除。详细代码如下: protected void Button1_Click(object sender, EventArgs e) { if (this.RadioButton1.Checked == true)//选中查找企业用户类型 { string sqlstr1 = "select * from tb_qy where id=" + this.TextBox1.Text.Trim(); SqlDataReader sdr1 = DB.reDr(sqlstr1); if (sdr1.HasRows)//判断是否有数据被检索到,如果有则表示查找到相应的用户 { this.Panel2.Visible = true; this.GridView1.DataSource = sdr1; this.GridView1.DataKeyNames = new string[] { "id" }; this.GridView1.DataBind(); } else { Response.Write(""); } } if (this.RadioButton2.Checked == true)//选中查找个人用户类型 { string sqlstr2 = "select * from tb_per where id=" + this.TextBox1.Text.Trim(); SqlDataReader sdr2 = DB.reDr(sqlstr2); if (sdr2.HasRows) { this.Panel3.Visible = true; this.GridView2.DataSource = sdr2; this.GridView2.DataKeyNames = new string[] { "id" }; this.GridView2.DataBind(); } else { Response.Write(""); } 如果搜索到企业用户信息,则将 数据显示在 GridView1 控件上 如果搜索到个人用户信息,则将 数据显示在 GridView2 控件上 273 C H A P T E R 6 第 6 章 供求信息网 } } 6.9.6 供求信息审核页设计 供求信息审核是管理员对会员发布的消息进行审核的页面。当会员发布的消息涉及到 不健康内容或者内容中存在各方面的敏感问题时,管理员可以使这些信息不通过审核,审 核不过关的信息是不能在网站上显示的。供求信息审核页的运行结果如图 6.30 所示。 图 6.30 供求信息审核页的运行结果 1.前台页面设计 这一页的页面设计非常简单,只用到了一个 ID 为 GridView1 的 GridView 控件。单击 该控件的“ ”图标按钮打开“GridView 任务”快捷菜单,选择“编辑列”命令,打开“字 段”对话框,在“可用字段”对话框中选择 CommandField 列,单击“+”号展开 CommandField 节点,选择“选择”按钮列,将其 HeaderText 属性和 EditText 属性都设置为“通过/取消”, 单击“选择”按钮列时会触发 GridView1 的 SelectIndexChange 事件。在 GridView1 中还实 现了分页功能,要实现分页功能只要将其 AllowPaging 属性设为 true,然后双击 PageIndex Changing 事件,在 PageIndexChanging 事件中编写实现分页的代码即可。其余属性设置请 参见 5.9.3 节。 2.后台功能代码 在命名空间区域中,引用 using System.Data.SqlClient 命名空间。 在 Page_Load 页装载事件中,判断用户是否登录并通过调用自定义方法完成对 Grid View1 进行数据绑定。代码如下: protected void Page_Load(object sender, EventArgs e) { if (!this.IsPostBack) { //判断用户是否登录 if (Session["flag"] == null) 274 SQL Server 2005 数据库系统开发案例精选 { Response.Write(""); } this.gv_DataBind(); } } 在 gv_DataBind()方法中,调用 DB 类的静态方法 reDs()来返回检索到的数据集并将它 绑定到 GridView 控件上。代码如下: public void GV_DataBind() { string sqlstr1 = "select * from tb_inf order by issueDate desc"; DataSet ds = DB.reDs(sqlstr1); this.GridView1.DataSource = ds; //设置主键 this.GridView1.DataKeyNames = new string[] { "id" }; this.GridView1.DataBind(); } 选择 GridView 控件,显示 GridView 的事件,双击 RowDataBound 事件,在 RowData Bound 事件中编写如下代码: protected void GridView2_RowDataBound(object sender, GridViewRowEventArgs e) { if (e.Row.RowType == DataControlRowType.DataRow) { //如果GridView中的行的第6个单元格的文本值为false,则显示为未通过 if (e.Row.Cells[6].Text == "False") { e.Row.Cells[6].Text = "未通过"; } else//如果GridView中的行的第6个单元格的值为true,则显示为已通过 { e.Row.Cells[6].Text = "已通过"; } } } 单击“通过/取消”超级链接,修改相应记录的信息,实现该记录是否通过审核的功能, 可以通过单击“通过/取消”切换“已通过”状态和“未通过”状态。选中 GridView1 控件, 双击 SelectedIndexChanging 事件,在 SelectedIndexChanging 事件中编写代码如下: protected void GridView1_SelectedIndexChanging(object sender, GridViewSelectEventArgs e) { //取得当前行的主键 string id = this.GridView1.DataKeys[e.NewSelectedIndex].Value.ToString(); SqlConnection con1 = DB.GetCon(); //根据主键查找到该条记录的Check字段(Check的数据类型为Bit,显示在程序中为“True”和“False”) SqlCommand com = new SqlCommand("select [check] from tb_inf where id=’" + id + "’", con1); //取得该字段的值 string count = Convert.ToString(com.ExecuteScalar()); if (count == "False") { count = "1"; } else { count = "0"; 275 C H A P T E R 6 第 6 章 供求信息网 } //更新Check字段 com.CommandText = "update tb_inf set [check]=" + count + " where id=" + id; com.ExecuteNonQuery(); this.GV_DataBind(); } 下面代码实现了 GridView1 的分页功能,首先把 GridView1 的 AllowPaging 属性设为 True,并在其 PageIndexChanging 事件中编写如下代码: protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e) { this.GridView1.PageIndex= e.NewPageIndex; this.GV_DataBind(); }  链接 账户冻结处理页和供求信息审核页的代码及功能大致相同,这里不作介绍。账户冻结 处理页的页面设计及代码请参考源程序。 6.9.7 留言板信息管理模块 在留言板上管理员能够删除留言、查看留言和回复留言。当会员在留言板上留言之后,管 理员可以在留言板信息管理模块中回复留言。留言板分为 3 个页面来实现,即留言板管理主页、 回复留言页、查看回复页。下面以留言板主页为例进行介绍,其运行结果如图 6.31 所示。 图 6.31 留言板信息管理主页 1.前台页面设计 留言板管理页面设计请参考本章 5.6.6 节的留言板设计。在 5.6.6 节留言板的基础上, 只要在 DataList 的标记为 ItemTemplate 的模板项中加入超链接文本【回复留言】和一个 Id 为 lnkbtnDelete 的 LinkButton 按钮。超链接文本的 href 属性给留言回复查看页传一个 ID 的 值,留言回复查看页通过 Request 的方法接收 ID 的值,再用 ID 检索数据显示在页面上。 把 lnkbtnDelete 的 CommandName 属性设置为 delete。然后在 DataList 中对应的 Delete 276 SQL Server 2005 数据库系统开发案例精选 Command 事件中编写删除功能的代码。当单击 lnkbtnDelete 时就会触发 DataList 中的 DeleteCommand 事件,执行删除命令。它们的属性参照如下代码: style="color: #0000ff; text-decoration: none">回复留言 留言回复页面中主要使用控件及控件用途如表 6.14 所示。 表 6.14 留言回复页面中主要使用控件及控件用途 工 具 箱 控 件 名 称 数 量 用 途 HTML Table 1 布局页面 HTML Input(Button) 1 返回上一页 标准 TextBox 2 分别显示和输入信息 标准 LinkButton 2 显示上一页\下一页 标准 Label 2 显示当前页数\总页数 前台页面中主要控件属性设置如下。 (1)Input 属性设置:该控件是客户端控件,主要是用来返回到上一页,这里设置了其 Value 值为“重置”。它要实现返回到上一页,还必须定义它的单击事件。在其 Click 事件 中加入“history.go(-1);”这行代码。 (2)Label 属性设置:通过设置 Label 控件的 Visible 属性,可以确定它是否在页面上 显示。在本页中,ID 为 Label1 的 Label 控件的 Visible 属性默认为 false,只有当某一条留 言没有被回复时,用户单击【查看回复】链接到留言回复页,在留言回复页 Label 就会显 示没有找到记录的信息。 留言查看界面同样参见 5.8.6 节的查看回复页面设计。在其基础上只要在 DataList 的标 记为 ItemTemplate 的模板项中多加一个 Text 属性为【删除留言】的 LinkButton 按钮。将其 CommandName 属性设置为 delete 即可。 2.后台功能代码 在留言板管理主页的命名空间区域中,引用 using System.Data.SqlClient 命名空间。在 Page_Load 页装载事件中,辨别用户是否登录以及调用自定义方法将数据源与 DataList 控 件绑定。详细代码如下: protected void Page_Load(object sender, EventArgs e) { if (Session["flag"] == null) { Response.Redirect("login.aspx"); } this.dl_DataBind(); } 在 dl_DataBind 方法中,调用 reDr()方法返回一个数据集,绑定到 DataList1 上,在页 面上显示出来。详细代码如下: public void dl_DataBind() { int CurrentPage = Convert.ToInt32(labNowPage.Text);//获取当前页数 PagedDataSource ps = new PagedDataSource();//生成PagedDataSource的实例 DataSet ds = DB.reDs("select * from tb_message order by issueDate desc");//调用ReDataSet方法,以 全局变量cndText作为搜索条件返回DataSet对象 277 C H A P T E R 6 第 6 章 供求信息网 ps.DataSource = ds.Tables[0].DefaultView; ps.AllowPaging = true; //是否可以分页 ps.PageSize =3; //显示的数量 ps.CurrentPageIndex = CurrentPage - 1; //取得当前页的页码 lnkbtnFront.Enabled = true; lnkbtnNext.Enabled = true; if (CurrentPage == 1) { lnkbtnFront.Enabled = false;//不显示上一页按钮 } if (CurrentPage == ps.PageCount) { lnkbtnNext.Enabled = false;//不显示下一页 } this.labCount.Text = Convert.ToString(ps.PageCount); this.DataList1.DataSource = ps; this.DataList1.DataKeyField = "id"; this.DataList1.DataBind(); } 单击【删除留言】按钮时,触发 DataList1 的 DeteleCommand 事件,在 DeteleCommand 事件中编写执行删除功能的代码如下: protected void DataList1_DeleteCommand(object source, DataListCommandEventArgs e) { string id = this.DataList1.DataKeys[e.Item.ItemIndex].ToString(); //取得DataLiat的主键值 string sqlstr= "Delete from tb_message where ID=’" + Convert.ToInt32(id) + "’"; DB.ExSql(sqlstr);//通过方法执行删除命令 Response.Redirect("gl_message.aspx"); } 在留言回复页的命名空间区域中,引用 using System.Data.SqlClient 命名空间。在 Page_ Load 页装载事件中,辨别用户是否登录及通过 Request 方法接收传过来的 ID 值,再把该 ID 对应的留言主题显示在 TextBox 中。详细代码如下: protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { if (Session["flag"] == null) { Response.Write("你还没有登录!"); } string strid = Request["id"].ToString();//接收到ID string sqlstr = "select * from tb_message where id=’" + strid + "’"; SqlDataReader dr = DB.reDr(sqlstr); dr.Read(); this.TextBox1.Text = dr["title"].ToString();//把该ID对应的title字段绑定到TextBox1 dr.Close(); } } 单击【提交】按钮,触发其 Click 事件。在 Click 事件中将回复留言记录插入到数据库 中。详细代码如下: protected void btnOK_click_Click(object sender, EventArgs e) { DateTime dt = DateTime.Now;//取得系统时间 //取得TextBox2的文本长度 278 SQL Server 2005 数据库系统开发案例精选 int count = Convert.ToInt32(this.TextBox2.Text.Length.ToString()); if (count < 200)//文本长度小于200字才能提交 { string cmdText="insert into tb_answer values(’" + Request["id"].ToString() + "’"; cmdText+ =",’" + this.TextBox2.Text.Trim() + "’,’" + this.TextBox1.Text.Trim() + "’,’" + Session ["userName"].ToString() + "’,’" + dt.ToShortDateString() + "’)" ; DB.ExSql(); Response.Write(""); } else { Response.Write(""); } }  链接 关于回复留言页、查看回复页的具体代码实现请参考本书光盘中的源程序。 6.10 疑难问题分析解决 6.10.1 DataReader 和 DataSet 的区别 在用 DataReader 对象作为 GridView 控件的数据源时,要求 GridView 分页显示数据时, 会出现图 6.32 所示的错误。 图 6.32 使用 DataReader 作为数据源分页时出现的错误 当改用 DataSet 对象作为 GridView 控件的数据源时就不会提示“数据源不支持服务器 端的数据分页”错误。这是因为 DataReader 的 read 只能向前扫描数据,数据从数据库读出 来就像水从水库中流出来一样,它是不可逆的,所以 DataReader 对象是不支持分页功能的。 而 DataSet 则可以在与数据库断开的情况下对数据进行操作。 应该根据使用数据的目的来选择使用 DataSet 或者 DataReader 对象。DataReader 对象 向回复信息表中插入一条回复记录 279 C H A P T E R 6 第 6 章 供求信息网 通常用于一次性、只读的情况下读取数据。而 DataSet 用于更复杂的数据访问 下面对 DataReader 和 DataSet 对象作一个详细的比较,使初学者能够明白什么时候该 用 DataReader,什么情况下用 DataSet。 (1)如果要对数据源进行读和写的操作,那么就应该使用 DataSet 对象,DataReader 对象只适用于只读数据的情况。 (2)如果要组合一个或多个数据库的表,那么就应该使用 DataSet,DataReader 只能用 于单个数据库的单个表的连接。 (3)如果想在与数据库断开的情况下使用数据,就必须使用 DataSet 对象,DataReader 必须在连接的情况下才能使用。 (4)DataReader 只能输出向前的、只读的数据流,而 DataSet 把表存储在 DataSet 的对 象中,可以对数据进行任意操作。 (5)如果只要返回一组只读的数据,那么应该使用 DataReader,因为 DataReader 的对 象读取数据的速度比 DataSet 快,这时候用 DataReader 能提高数据访问性能。 6.10.2 常用的正则表达式 在 6.6.4 节中,使用了正则表达式来验证用户输入的 E-mail 地址是否正确,和控制用 户输入的密码位数在 6 至 16 位之间。其实,正则表达式的功能很强大,使用的范围比较广。 下面就介绍一些在实际开发中经常使用到的正则表达式,如表 6.15 所示。 表 6.15 常用的正则表达式 正则表达式 功能及作用 ^\d{n}$ 只能输入 n 位的数字 ^\d{n,}$ 至少输入 n 位的数字 ^\d{n,m}$ 只能输入 n~m 位的数字 ^[0-9]*$ 只能输入 0~9 之间的数字 \w{6,16} 只能输入 6~16 位之间的任意字符 ^[A-Za-z]+$ 只能输出 26 个英文字母组成的字符串 ^[A-Z]+$ 只能输出 26 个大写英文字母组成的字符串 ^[a-z]+$ 只能输出 26 个小写英文字母组成的字符串 ^[\u4e00-\u9fa5]{0,}$ 只能输入汉字 http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)? 验证 InternetURL 地址 (\(\d{3}\)|\d{3}-)?\d{8} 验证电话号码 \d{17}[\d|X]|\d{15} 验证身份证 ID \d{6} 验证邮政编码 \w+([-+.’]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)* 验证 E-mail 地址 6.11 程序调试与错误处理 如果在数据表中使用了 SQL Server 2005 保留的关键字作为表字段(例如:select、update、 insert 等都是 SQL Server 中保留的关键字),在向该表中插入字段时,如果没有对关键字进行处 理,就会出现错误。例如在本网站中使用到的一条用于从发布信息表中检索通过审核记录的 280 SQL Server 2005 数据库系统开发案例精选 SQL 语句。该 SQL 语句为:select top 5 * from tb_inf where check =’1’ and (type=’需求信息’or type=’供应信息’) order by issueDate desc。在调试程序时,出现了图 6.33 所示的错误信息。 图 6.33 没有对关键字处理时出现的错误信息 该错误信息提示在 check 关键字附近有语法错误,不能通过调试。在此只要将该 SQL 语句修改为:select top 5 * from tb_inf where [check] =’1’ and (type=’需求信息’or type=’供应 信息’) order by issueDate desc,即把关键字用[]括起来,就不会出现类似错误。 7 企业客户管理系统 开发导读 实例说明  实例名称:企业客户管理系统。  实例路径:光盘\企业客户管理 系统。  实例运行文件:光盘\mingris- oft\企业客户管理系统\Login. aspx。  用户名:mr。  密码:mrsoft。  用户在使用本实例前,请仔细 阅读光盘中的光盘使用说明、 程序界面修改配置说明书、安 装说明书、使用说明书,这样 可以使您更好地学习和使用本 实例。 在计算机中使用本章实例的源程序,用户须安装 Microsoft Visual Stadio 2005 或其他网页开发工具。 本实例需要配置 IIS,配置说明详见光盘使用 说明。 本实例数据库为 SQL Server 2005,使用本实例 前,请安装 SQL Server 2005。安装时,验证模式为 混合模式,用户名为 sa,密码为空。 本实例提供了 5 套程序背景和素材,有些格式需 要使用特殊软件处理。 JPG/GIF 文件,如要修改其文件,需要安装 Photoshop 编辑软件。 282 SQL Server 2005 数据库系统开发案例精选 本案例由多个网络程序界面组成,下面仅列出几个典型界面,其他界面请参见光盘中 的源程序。 首页 用户登录 站内搜索页面 详细信息显示页面 添加用户页面 服务调查显示页面 修改密码页面 任务分配页面 283 C H A P T E R 7 第 7 章 企业客户管理系统 7.1 概 述 在经济全球化的今天,建立以客户为中心的经营战略,可以加强企业和客户之间的联系。 对企业来讲,为客户提供一流的服务,是企业建立品牌、实现差别化服务、取得竞争的利器。 企业管理系统能实现信息的采集、分发、共享,一直到信息处理、信息反馈等功能。为了使 读者对企业客户系统有一个清晰的认识,本章将详细介绍如何实现企业客户管理系统。 7.2 系 统 分 析 7.2.1 需求分析 通过调查,要求系统需要实现以下功能。  由于操作人员的计算机知识普遍较差,要求有良好的人机界面。  管理系统用户,由于该系统的使用对象多,要求有较好的权限管理。  管理企业的会议信息、发文信息、公共信息。  提供个人办公服务。  对企业员工基本情况进行全面管理。  设置客户数据统计、打印功能。  当外界环境(停电、网络病毒)干扰本系统时,系统可以自动保护原始数据的安全。  在相应的权限下,删除数据方便简单,数据稳定性好。  数据计算自动完成,尽量减少人工干预。  系统退出。 7.2.2 可行性分析  经济性 本系统以客户为核心,实现了销售和服务的管理平台。能够改善客户关系,增加企业 收益,提高企业的竞争力。  技术性 本系统对企业客户的问题记录进行管理,并将问题记录分配给工程师进行处理。同时 实现了服务调查信息的管理。 7.3 总 体 设 计 7.3.1 项目规划 企业客户管理系统是一个典型的数据库开发应用程序,由信息管理模块、任务分配模 块、服务调查模块、用户管理模块等部分组成,规划系统功能模块如下。  信息管理模块 该模块主要功能是对客户问题记录进行添加、删除、查询等操作。 284 SQL Server 2005 数据库系统开发案例精选  任务分配模块 该模块主要功能是将客户问题记录分配给工程师进行处理。实现了对客户发布问题信 息的反馈及修改反馈信息的功能。  服务调查信息模块 该模块主要功能是对服务调查信息进行添加和删除等操作。  用户管理模块 该模块主要功能是对用户账户进行添加及修改当前用户的密码等操作。 企业客户主要由信息发布、发布信息查看和删除、任务分配、信息反馈、服务调查信 息查看与删除、添加用户信息、修改账户密码等模块组成。其中,信息发布模块包括了服 务调查信息添加模块,添加用户模块包括了删除用户模块。 7.3.2 系统功能结构图 企业客户管理系统功能结构如图 7.1 所示。 图 7.1 系统功能结构图 7.4 系 统 设 计 7.4.1 设计目标 本系统是针对中小型企业客户管理情况进行设计的,主要实现如下目标。  系统采用人机对话方式,界面清晰、信息查询灵活、方便、快捷、准确、数据存 储安全可靠。  键盘操作,快速响应。  在线发布客户问题记录。  在线反馈客户问题记录。  在线参加服务调查活动。  对系统用户进行管理。  对客户发布信息进行管理。  对反馈信息进行管理。  对服务调查信息进行管理。  系统最大限度地实现了易安装性、易维护性和易操作性。  系统运行稳定、安全可靠。 285 C H A P T E R 7 第 7 章 企业客户管理系统 7.4.2 开发及运行环境 硬件平台:  CPU:P4 1.8GHz。  内存:512MB 以上。 软件平台:  操作系统:Windows Server 2003。  数据库:SQL Server 2005。  开发环境:Microsoft .NET Framework SDK v2.0。  开发工具:Microsoft Visual Studio 2005。  开发语言:C#语言。  服务器:IIS 6.0。  浏览器:IE 5.0,推荐使用 IE 6.0。  分辨率:最佳效果 1024×768 像素。 7.5 数据库设计 本系统数据库采用 SQL Server 2005 数据库,系统数据库名称为 db_Qykhgl。该数据库包 含 4 张表。下面分别给出主要数据表的实体 E-R 图、主要数据表的结构和数据表概要说明等。 7.5.1 数据表的实体 E-R 图 根据数据表结构的设计,规划出相应的实体 E-R 图,这些实体中包含各种具体信息, 并通过相互之间的作用形成数据的流动。具体数据表的实体 E-R 图描述如下。 图 7.2 为用户信息实体 E-R 图。 图 7.3 为信息反馈实体 E-R 图。 用户名 用户信息实体 密码 性别 用户ID 性别 发布信息ID 信息发馈实体 发馈内容 回复人 发馈信息ID 发馈日期 标记字段 图 7.2 用户信息实体 E-R 图 图 7.3 信息反馈实体 E-R 图 图 7.4 为服务调查实体 E-R 图。 被调查人 服务调查实体 调查日期 评价 调查信息ID 意见 图 7.4 服务调查表实体 E-R 图 电话 反馈信息ID 反馈内容 反馈日期 286 SQL Server 2005 数据库系统开发案例精选 7.5.2 主要数据表的结构 在该系统中,一共要创建 4 个表,主要用于存放企业客户管理系统所需要的数据。下 面分别介绍这几个表。  tb_UserInfo(用户信息表) 表 tb_UserInfor 用于保存用户的详细信息。表 tb_UserInfo 的结构如表 7.1 所示。 表 7.1 表 tb_UserInfo 的结构 字 段 名 称 类 型 长 度 主 键 描 述 ID int 4 是 用户 ID UserName Varchar 20 用户名 Password Varchar 20 密码 Sex int 4 性别 Telephone Varchar 50 电话  tb_Records(信息发布表) 表 tb_Records 用于保存用户发布信息的记录。表 tb_Records 的结构如表 7.2 所示。 表 7.2 表 tb_Records 的结构 字 段 名 称 类 型 长 度 主 键 描 述 RecordID Int 4 是 发布信息 ID RecordTitle varchar 50 发布信息标题 RecordDetails varchar 200 发布内容 UserName varchar 20 用户名 Allot bit 1 是否指定工程师 CreateDate datetime 8 录入的时间 EngineerName varchar 20 工程师姓名  tb_ReRecordinfo(信息反馈表) 表 tb_ReRecordinfo 用于保存工程师回复用户信息的工作记录。表 tb_ReRecordinfo 的 表结构如表 7.3 所示。 表 7.3 表 tb_ReRecordinfo 的结构 字 段 名 称 类 型 长 度 主 键 描 述 ID int 4 是 反馈信息 ID RecordID int 4 发布信息 ID ReReordContent varchar 200 反馈内容 EngineerName varchar 20 回复人 RevertDate datetime 8 反馈日期 Flag int 4 标记信息是否被修改过  tb_ResearchInfo(服务调查表) 表 tb_ResearchInfo 用于保存客户对本网站的意见和评价。表 tb_ResearchInfo 的表结构 如表 7.4 所示。 287 C H A P T E R 7 第 7 章 企业客户管理系统 表 7.4 表 tb_ ResearchInfo 的结构 字 段 名 称 类 型 长 度 主 键 描 述 ID int 4 是 调查信息 ID UserName varchar 20 被调查人 ResearchDate datetime 8 调查日期 Apprise varchar 200 评价 ReIdea int 4 意见 7.5.3 数据表概要说明 从读者角度出发,为了使读者对本系统后台数据库中数据表有一个清晰的认识,笔者 在此设计了一个数据表树型结构图,该数据表树型结构图包含系统所有数据表,如图 7.5 所示。 图 7.5 数据表树型结构图 7.5.4 存储过程设计 企业客户管理系统的数据库操作比较频繁,因此对于经常使用的数据操作可以创建存 储过程,这样即方便了维护,又加快了系统的速度。下面是企业客户管理系统中应用的一 些主要存储过程。 (1)下面的存储过程的作用是在用户登录时,根据用户名、密码和角色在用户信息表 中查找该用户,如果该用户存在返回其 ID,否则返回空值。创建存储过程的语句如下: CREATE PROCEDURE SelUsers @UserName varchar(20), @Password varchar(20), @Type int, @ID int output AS select @ID=ID from tb_UsersInfo where UserName=@UserName and Password=@Password and Type=@Type GO (2)下面的存储过程的作用是管理员添加用户时,向用户信息表中插入用户信息。创 建存储过程的语句如下: CREATE PROCEDURE AddUsersInfo @UserName varchar (20), @Password varchar(20), @Sex int,@Telephone 288 SQL Server 2005 数据库系统开发案例精选 varchar (50),@Type int As insert into tb_UsersInfo (UserName,Password,Sex ,Telephone,Type) values (@UserName,@Password,@Sex,@Telephone,@Type) GO (3)下面的存储过程的作用是查询所有未分配工程师的发布信息。创建存储过程的语 句如下: CREATE PROCEDURE SelectRecords AS Select * from tb_Records where Allot=’0’ GO (4)下面的存储过程的作用是根据发布信息 ID 删除信息发布表中的记录。创建过程的 语句如下: CREATE PROCEDURE DelRecords @RecordID int AS delete tb_Records where RecordID=@RecordID GO (5)下面的存储过程的作用是根据发布信息 ID 返回该记录的详细信息。创建存储过程 的语句如下: CREATE PROCEDURE ReaderRecords @RecordID int, @RecordTitle varchar(50) output, @RecordDetails varchar(200) output, @CreateDate datetime output, @UserName varchar(20) output AS Select @RecordTitle=RecordTitle,@RecordDetails=RecordDetails,@CreateDate=CreateDate,@UserName=UserName from tb_Records where RecordID=@RecordID GO (6)下面的存储过程的作用是管理员分配工程师时,根据发布信息 ID 将工程师姓名更 新到信息发布表中,然后将标记字段 Allot(“0”为未分配工程师,“1”为已分配工程师) 设为“1”。创建存储过程的语句如下: CREATE PROCEDURE UpdateUserName @RecordID int , @EngineerName varchar (20) AS update tb_Records set EngineerName=@EngineerName, Allot =’1’ where RecordID=@RecordID GO (7)下面的存储过程的作用是显示发布信息的详细信息时,根据发布信息 ID 判断其对 应的反馈信息 ID 是否为空,如果不为空返回该发布信息和与其对应的反馈信息。否则,只 返回该发布信息 ID 对应的详细信息。创建存储过程的语句如下: CREATE PROCEDURE SelRecordReRecord @RecordID int , @ID int AS if @ID=0 select * from tb_Records where RecordID=@RecordID else 289 C H A P T E R 7 第 7 章 企业客户管理系统 select tb_Records.RecordID,tb_Records.RecordTitle,tb_Records.RecordDetails,tb_Records. UserName,tb_Records.Allot,tb_Records.CreateDate, tb_Records.EngineerName, tb_ReRecordInfo.ReRecordContent,tb_ReRecordInfo.RevertDate, tb_ ReRe cordInfo.Flag from tb_Records inner join tb_ReRecordInfo on tb_Records.RecordID=tb_ReRecordInfo.RecordID where tb_Records.RecordID=@RecordID GO (8)下面的存储过程的作用是工程师修改反馈信息时,根据发布信息 ID 将反馈内容及 修改时间更新到信息反馈表中,然后将标记字段 Flag(“0”表示该反馈信息没有被修改过, “1”表示该反馈信息修改过)设为“1”。创建存储过程的语句如下: CREATE PROCEDURE UpdateReRecordInfo @RecordID int, @ReRecordContent varchar(200), @RevertDate datetime AS update tb_ReRecordInfo set ReRecordContent=@ReRecordContent ,RevertDate=@RevertDate ,Flag=’1’ where RecordID=@RecordID (9)下面的存储过程的作用是显示发布信息的详细信息时,根据发布信息 ID 在反馈信 息表中查找匹配的记录,如果匹配失败把输出参数“@ID”赋值为“0”。创建存储过程的 语句如下: CREATE PROCEDURE Judge @RecordID int , @ID int output AS select @ID=ID from tb_ReRecordInfo where RecordID=@RecordID if @@Rowcount<1 select @ID=0 GO (10)下面的存储过程的作用是向信息反馈表中插入新记录。创建存储过程的语句如下: CREATE PROCEDURE InsertReRecordInfo @RecordID int , @ReReordContent varchar(200), @EngineerName varchar(20), @RevertDate datetime AS insert into tb_ReRecordInfo(RecordID,ReRecordContent,EngineerName,RevertDate) values(@RecordID ,@ReReordContent,@EngineerName,@RevertDate ) GO (11)下面的存储过程是向记录表中插入新数据。创建存储过程的语句如下: CREATE PROCEDURE AddRecord @RecordTitle varchar(50), @RecordDetails varchar(200), @UserName varchar(20), @Allot varchar(50), @CreateDate datetime As Insert into tb_Records (RecordTitle,RecordDetails,UserName ,Allot,CreateDate ) Values (@RecordTitle,@RecordDetails,@UserName ,@Allot,@CreateDate) GO (12)下面的存储过程的作用是使用站内搜索模块搜索发布信息时,根据搜索条件匹配 信息发布表中的 RecordID 和 RecordTitle 字段。创建存储过程的语句如下: 290 SQL Server 2005 数据库系统开发案例精选 CREATE PROCEDURE Find @Search varchar (50) AS select * from tb_Records where RecordID like ’%’+@Search+’%’ or RecordTitle like’%’+@Search+’%’ GO (13)下面存储过程的作用是工程师回复发布信息时,根据工程师的名字查找已指定工 程师且发布信息 ID 不在信息反馈表中的发布信息记录。创建存储过程的语句如下: CREATE PROCEDURE Revert @EngineerName varchar(20) As select * from tb_Records where Allot=1 and EngineerName=@EngineerName and RecordID not in(select tb_Records.RecordID from tb_ReRecordInfo inner join tb_Records on tb_ReRecordInfo.RecordID=tb_Records.RecordID ) GO (14)下面的存储过程的作用是用饼图动态显示用户评价,分别返回服务调查表中的所 有参加服务调查的总人数、满意用户的人数、不满意用户人数和感觉一般的用户人数。创 建存储过程的语句如下: CREATE PROCEDURE countIdea @All int output, @Good int output, @Bad int output, @Common int output AS select @All=count(*) from tb_ResearchInfo select @Good =count(*) from tb_ResearchInfo where ReIdea=’1’ select @common=count(*)from tb_ResearchInfo where ReIdea=’2’ select @Bad=count(*) from tb_ResearchInfo where ReIdea=’0’ GO 技巧 这里使用到了存储过程的输入参数和输出参数,输入参数是用户传给存储过程的参 数。在声明参数时不必加上 Input 关键字,因为不加关键字时参数默认为输入参数。输出 参数是由存储过程传出的参数。声明它的时候必须加上 Output 关键字。 7.6 技 术 准 备 7.6.1 读者知识要求 要很好地学习本案例,读者需要熟悉 SQL Server 2005 数据库的基本操作及存储过程的 创建及使用,还需要掌握 IIS 的相关配置。 7.6.2 存储过程的创建 为了读者更好地理解本例中存储过程的作用,同时也是为了读者更好地学习存储过程。 现在使用本例中的存储过程作为例子来讲解存储过程的几种用法及格式。 291 C H A P T E R 7 第 7 章 企业客户管理系统 第一种,也是最简单的一种。既没有输入参数也没有输出参数。 CREATE PROCEDURE SelRecords AS Select * From tb_UsersInfo where Type=’1’ GO 第二种是在本程序中经常使用的存储过程的格式。只有输入参数,没有输出参数。输 入参数是用户传给存储过程的值。输入参数的关键字是 input。如果在声明输出参数时没有 加上 output 关键字,则系统默认为输入参数。 CREATE PROCEDURE UpdateReRecordInfo @RecordID int, @ReRecordContent varchar(200), @RevertDate datetime AS update tb_ReRecordInfo set ReRecordContent=@ReRecordContent ,RevertDate=@RevertDate ,Flag=’1’ where RecordID=@RecordID 第三种是既有输入参数又有输出参数,其中输出参数的关键字是 output。输出参数是 执行存储过程后,存储过程返回给用户的值。 CREATE PROCEDURE Judge @RecordID int , @ID int output AS select @ID=ID from tb_ReRecordInfo where RecordID=@RecordID if @@Rowcount<1 select @ID=0 GO 7.6.3 存储过程的使用 创建完存储过程后,通过存储过程名调用对应的存储过程。如果该存储过程有输入参 数,则要给输入参数赋值。如果该存储过程还有输出参数,则要使用一个变量来存储其返 回的值。下面请看本例的一段代码。 public int Judge(int RecordID) { SqlConnection con = Operation.GetCon(); SqlCommand comm = new SqlCommand("Judge", con); //指明Sql命令的操作类型是使用存储过程 comm.CommandType = CommandType.StoredProcedure; //给存储过程添加输入参数 SqlParameter paraRecordID = new SqlParameter("@RecordID", SqlDbType.Int, 4); paraRecordID.Value = RecordID; comm.Parameters.Add(paraRecordID); //给存储过程添加输出参数 SqlParameter paraID = new SqlParameter("@ID", SqlDbType.Int, 4); paraID.Direction = ParameterDirection.Output;//指出该参数是存储过程的Output参数 comm.Parameters.Add(paraID); con.Open();//打开数据库连接 comm.ExecuteNonQuery();//进行数据库操作 con.Close();//关闭连接 int ID = (int)(paraID.Value);//根据存储过程的输出参数的值,对该方法的参数ID赋值 return ID; } 先获得输入参数“@RecordID” 的引用,然后给输入参数赋值 先获得输出参数“@ID”的引用, 然后指明该参数是输出参数 292 SQL Server 2005 数据库系统开发案例精选 7.7 网站总体架构 7.7.1 功能模块介绍 系统主要包括以下功能模块。  信息发布模块:主要用于客户问题记录的发布。  服务调查模块:主要用于展示服务调查信息的结果。  站内搜索模块:主要功能是通过发布信息 ID 与发布信息标题进行模糊查询。  用户管理模块:主要功能是添加用户账户和修改当前用户密码。  任务分配模块:主要功能是对客户问题进行信息反馈。 7.7.2 文件夹及文件架构布局 在开发.NET 程序时,首先要创建很多 Web 页、用户控件以及类,以完成基本的功能 操作。不过,在编写代码之前,可以先把网站中可能用到的文件夹创建出来(例如创建一 个名为 Image 的文件夹,用于保存网站中需要的图片),这样可以方便以后的开发工作,也 可以规范网站的整体架构。因此在开发企业客户管理系统前,首先设计了图 7.6 所示的文 件夹及文件架构图,在开发时只需将相应文件保存到对应文件夹下即可。 图 7.6 企业客户管理系统文件架构图 7.7.3 文件架构 企业客户管理系统文件架构如图 7.7 所示。 图 7.7 企业管理系统文件架构图 293 C H A P T E R 7 第 7 章 企业客户管理系统 7.8 公共模块编写 7.8.1 用户控件设计 创建 Web 用户控件主要是方便重复使用及修改,当某个模块要被多次用到时,就可以 把这个模块创建为 Web 用户控件。在本系统中使用了实现页面导航和系统版权的控件。运 行效果如图 7.8 和图 7.9 所示。 图 7.8 页面导航控件运行效果图 吉林省明日科技有限公司 电话:84972266 传真:84972266 @2000-2006 明日科技 图 7.9 系统版权控件运行效果图 1.前台页面设计 由于系统版权控件实现非常简单,关于它的设计就不介绍了。这里主要讲解页面导航 控件的设计及实现。 在该控件中主要用到的控件及用途如表 7.5 所示。 表 7.5 修改密码模块用到的控件 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 1 布局页面 标准 LinkButton 2 用于返回主页/退出登录 标准 HyperLink 7 链接到目标页 前台页面中主要控件属性设置如下。 (1)设置 Table 属性。在页面中,用到了两个 Table 控件,Table 控件是客户端控件, 主要用来布局页面,它们的 ID 属性分别为 Table1 和 Table2,把 Table1 的 Background 属性 设为“../Image/企业客户管理 banner.jpg”。 (2)设置 LinkButton 属性。在页面中,用到了两个 LinkButton 控件,其 ID 属性分别 为 lnkbtnBack 和 lnkbtnOut。它们 Text 属性分别为“返回主页”和“安全退出”。LnkbtnBack 控件用来返回到首页,lnkbtnOut 控件用来退出系统。 (3)设置 HyperLink 属性。在页面中,用到了 7 个 HyperLink 控件。其 ID 属性分别为 hpLinkRecordAdd 、 hpLinkResearch 、 hpLinkSearch 、 hpLinkPassword 、 hpLinkRevert 、 hpLinkAllot 和 hpLinkAddUser。由于它们的用法一致,只以 hpLinkRecordAdd 为例,设置 它的 ImageUrl、NavigateUrl 属性分别为“~/Image/添加用户按钮.jpg”和“~/Pages/ UserAdd.aspx”。 294 SQL Server 2005 数据库系统开发案例精选 2.后台功能代码 在该页的页面加载事件中判断用户是否登录和用户登录类型,如果没有登录则返回到 登录页。根据用户类型的不同,控制导航按钮的 Enabled 属性状态。从而控制用户的权限。 该页 Page_Load 事件代码如下: protected void Page_Load(object sender, EventArgs e) {  if (!IsPostBack) {  if (Session["flag"] == null) {  Response.Redirect("../Login.aspx"); } if (Session["TypeValues"].ToString() == "1") { this.hpLinkAllort.Enabled = false; this.hpLinkAddUser.Enabled = false; } if (Session["TypeValues"].ToString() == "2") {  this.hpLinkAllort.Enabled = false; this.hpLinkAddUser.Enabled = false; this.hpLinkRevert.Enabled = false; } } 单击【返回主页】按钮,链接到主页,其代码如下: protected void lnkbtnBack_Click(object sender, EventArgs e) { Response.Redirect("Index.aspx"); } 单击【安全退出】按钮,使用户由登录状态更改为非登录状态。其代码如下: protected void lnkbtnBack_Click(object sender, EventArgs e) { Response.Redirect("Index.aspx"); }  代码导读  IsPostBack:控制页面初始化代码的加载。当页面第一次加载时,该属性的值是 False。如果页面通过回发到服务器而加载,IsPostBack 的属性值为 True。  Session 变量:用来保存当前用户的状态。  Redirect 方法:跳转到目标页。  Enble 方法:是否启用对应的控件。 7.8.2 Web.Config 文件配置 为了方便对数据的操作和限制,本系统在 Web.Config 文件中配置一些参数,主要配置 参数是数据库连接字符串,其具体配置如下: 295 C H A P T E R 7 第 7 章 企业客户管理系统 ……//此处省略 7.8.3 实体类编写 在本系统中,包含记录信息、工作记录、服务调查和服务调查评价 4 种实体类。在 Records 类中存放了客户记录的信息实体,包括客户记录的客户记录 ID、记录标题、记录 内容等信息;在 ReRecord 类中存放了工作记录的实体信息,包括工作记录 ID、客户记录 ID、工作记录内容等信息;在 Research 类中存放了服务调查信息的实体信息,包括调查信 息 ID、服务调查时间、服务评价等;在 Count 类中存放了服务调查总人数、满意用户的人 数、不满意用户人数和感觉一般的用户人数。这 4 个类的定义如下: /**************************例程7-26 App_Code\Operate.cs *******************************/ public class Records { public int RecordID; public string RecordTitle; public string RecordDetails; public string UserName; public string Allot; public DateTime CreateDate; public string EngineerName; } public class ReRecord { public string ID; public string RecordID; public string ReReordContent; public string EngineerName; public DateTime RevertDate; public int Flag; } public class Research { public string UserName; public DateTime ResearchDate; public string Appraise; public int ReIdea; } public class Count { public int All; public int Good; public int Bad; public int Common; } 7.8.4 数据库操作类 由于对数据库操作需要频繁地连接数据库,如果每次连接都写一遍会很麻烦。这里把 数据库连接写在一个方法中,通过调用方法来连接数据库。该方法的代码如下: // *********************************Operate.cs******************************************* public static SqlConnection GetCon() 296 SQL Server 2005 数据库系统开发案例精选 { return new SqlConnection(System.Configuration.ConfigurationManager.AppSettings["DNS"]); } 对于数据库的数据操作大部分是调用操作类中的方法来实现的。在网站开发项目中以 类的形式来组织、封装一些常用的函数和事件,不仅可以提高代码的重用率,也大大方便 了代码的管理。其具体说明如下。 (1)在 FindPeople()方法中,首先调用 GetCon()方法建立与数据库的连接。然后调用存 储过程 SelUsers 向存储过程输入用户名、密码和角色。如果通过身份验证则返回该用户的 ID,否则返回空值。该方法的详细代码如下: // *********************************Operate.cs**************************************** // public static bool FindPeople(string UserName,string Password,int Type) { try { SqlConnection con = Operation.GetCon(); SqlCommand comm = new SqlCommand("SelUsers", con); //指明Sql命令的操作类型是使用存储过程 comm.CommandType = CommandType.StoredProcedure; //给存储过程添加参数 SqlParameter paraUserName = new SqlParameter("@UserName", SqlDbType.VarChar, 20); paraUserName.Value = UserName; comm.Parameters.Add(paraUserName); SqlParameter paraPassword = new SqlParameter("@Password", SqlDbType.VarChar, 20); paraPassword.Value = Password; comm.Parameters.Add(paraPassword); SqlParameter paraType = new SqlParameter("@Type", SqlDbType.Int, 4); paraType.Value = Type; comm.Parameters.Add(paraType); //指出该参数是存储过程的Output参数 SqlParameter paraID = new SqlParameter("@ID",SqlDbType.Int,4); paraID.Direction = ParameterDirection.Output; comm.Parameters.Add(paraID); con.Open(); comm.ExecuteNonQuery(); con.Close(); UserID = (int)paraID.Value;//根据存储过程的输出参数的值对该方法的参数UserID赋值 if (UserID!=null) { return true; } else { return false; } } catch { return false; } } (2)在 InsertUserInfo()方法中,调用存储过程 AddUsersInfo 向用户信息表中插入一条 新记录。如果记录添加成功返回 True,否则返回 False。该方法的详细代码如下: // *********************************Operate.cs***************************************** public static bool InsertUserInfo(string UserName,string Password,int Sex,string Telephone,int Type) 297 C H A P T E R 7 第 7 章 企业客户管理系统 { try { SqlConnection con = Operation.GetCon(); SqlCommand comm = new SqlCommand("AddUsersInfo", con); //指明Sql命令的操作类型是使用存储过程 comm.CommandType = CommandType.StoredProcedure; //给存储过程添加参数 SqlParameter paraUserName = new SqlParameter("@UserName", SqlDbType.VarChar, 20); paraUserName.Value = UserName; comm.Parameters.Add(paraUserName); SqlParameter paraPassword = new SqlParameter("@Password", SqlDbType.VarChar, 20); paraPassword.Value = Password; comm.Parameters.Add(paraPassword); SqlParameter paraSex = new SqlParameter("@Sex", SqlDbType.Int, 4); paraSex.Value = Sex; comm.Parameters.Add(paraSex); SqlParameter paraTelephone = new SqlParameter("@Telephone", SqlDbType.VarChar, 50); paraTelephone.Value = Telephone; comm.Parameters.Add(paraTelephone); SqlParameter paraType = new SqlParameter("@Type", SqlDbType.Int, 4); paraType.Value = Type; comm.Parameters.Add(paraType); con.Open();//打开数据库连接 comm.ExecuteNonQuery();//进行数据库操作 con.Close();//关闭连接 return true; } catch { return false; } } (3)在 ReDataSet()方法中,以存储过程名作为参数来返回 DataSet 数据集。该方法的 详细代码如下: public static DataSet ReDataSet(string StoreName) { SqlConnection con = Operation.GetCon(); SqlDataAdapter sda = new SqlDataAdapter(StoreName, con); //指明Sql命令的操作类型是使用存储过程 sda.SelectCommand.CommandType = CommandType.StoredProcedure; con.Open();//打开数据库连接 DataSet ds = new DataSet(); sda.Fill(ds, "Records");//进行数据库操作 con.Close();//关闭连接 return ds; } (4)在 ExSql()方法中,以存储过程名作为该方法的参数来执行 SQL 命令。而惟一标 识 ID 作为该存储过程的输入参数。该方法的详细代码如下: public static void ExSql(string StoreName,int ID) { SqlConnection con = Operation.GetCon(); SqlCommand comm = new SqlCommand(StoreName, con); comm.CommandType = CommandType.StoredProcedure;//指明Sql命令的操作类型是使用存储过程 SqlParameter para = new SqlParameter("@ID", SqlDbType.Int, 4);//给存储过程添加参数 para.Value = ID; 298 SQL Server 2005 数据库系统开发案例精选 comm.Parameters.Add(para); con.Open();//打开数据库连接 comm.ExecuteNonQuery();//进行数据库操作 con.Close();//关闭连接 } (5)在 ReDataReader()方法中,将 RecordID 作为输入参数传到存储过程 RederRecords 中,而通过 Records 类对象 Re 来接受存储过程输出参数的值。该方法的详细代码如下: public static bool ReDataReader(int RecordID,Records Re) { SqlConnection con = Operation.GetCon(); SqlCommand comm = new SqlCommand("ReaderRecords", con); comm.CommandType = CommandType.StoredProcedure;//指明Sql命令的操作类型是使用存储过程 //给存储过程添加参数 SqlParameter paraRecordID = new SqlParameter("@RecordID", SqlDbType.Int, 4); paraRecordID.Value = RecordID; comm.Parameters.Add(paraRecordID); SqlParameter paraRecordTitle = new SqlParameter("@RecordTitle", SqlDbType.VarChar, 50); paraRecordTitle.Direction = ParameterDirection.Output; comm.Parameters.Add(paraRecordTitle); SqlParameter paraRecordDetails = new SqlParameter("@RecordDetails", SqlDbType.VarChar, 200); paraRecordDetails.Direction = ParameterDirection.Output; comm.Parameters.Add(paraRecordDetails); SqlParameter paraCreateDate = new SqlParameter("@CreateDate", SqlDbType.DateTime, 8); paraCreateDate.Direction = ParameterDirection.Output; comm.Parameters.Add(paraCreateDate); SqlParameter paraUserName = new SqlParameter("@UserName", SqlDbType.VarChar, 20); paraUserName.Direction = ParameterDirection.Output; comm.Parameters.Add(paraUserName); try { con.Open();//打开数据库连接 comm.ExecuteNonQuery();//进行数据库操作 con.Close();//关闭连接 //根据存储过程的输出参数的值 Re对象赋值 Re.RecordTitle = paraRecordTitle.Value.ToString(); Re.RecordDetails = paraRecordDetails.Value.ToString(); Re.CreateDate = (DateTime)(paraCreateDate.Value); Re.UserName = paraUserName.Value.ToString(); return true; } catch { return false; } } (6)在 UpdateRecords()方法中,将客户 ID 和工程师名字作为输入参数传到存储过程 RederRecords 中,根据客户 ID 来更新发布信息表中 EngineerName 字段。详细代码如下: public static bool updateRecords(int ID,string EngineerName) { try { SqlConnection con = Operation.GetCon(); SqlCommand comm = new SqlCommand("UpdateUserName", con); //指明Sql命令的操作类型是使用存储过程 299 C H A P T E R 7 第 7 章 企业客户管理系统 comm.CommandType = CommandType.StoredProcedure; SqlParameter paraID = new SqlParameter("@RecordID", SqlDbType.Int, 4);//给存储过程添加参数 paraID.Value = ID; comm.Parameters.Add(paraID); SqlParameter paraEngineerName = new SqlParameter("@EngineerName", SqlDbType. Var Char, 20); paraEngineerName.Value = EngineerName; comm.Parameters.Add(paraEngineerName); con.Open();//打开数据库连接 comm.ExecuteNonQuery();//进行数据库操作 con.Close();//关闭连接 return true; } catch { return false; } } (7)在 SelRecordReRecord()方法中,将发布信息 ID 作为输入参数传到存储过程 Sel- RecordReRecord 中,通过 Judge()方法判断该发布信息是否有反馈信息。如果有则将反馈内 容和反馈时间取出来,否则只返回发布信息表中的内容,并用 Records 和 ReRecord 类对象 绑定返回的结果集。详细代码如下: public bool SelRecordReRecord(int RecordID,Records Re,ReRecord Red ) { SqlConnection con = Operation.GetCon(); SqlCommand comm = new SqlCommand ("SelRecordReRecord", con); comm.CommandType = CommandType.StoredProcedure;//指明Sql命令的操作类型是使用存储过程 //给存储过程添加参数 SqlParameter paraRecordID = new SqlParameter("@RecordID", SqlDbType.Int, 4); paraRecordID.Value = RecordID; comm.Parameters.Add(paraRecordID); SqlParameter paraID = new SqlParameter("@ID", SqlDbType.Int, 4); Operation oper = new Operation();//生成Operation类对象 int ID=oper.Judge(RecordID);//调用Judge方法返回int类型的值 paraID.Value = ID; comm.Parameters.Add(paraID); con.Open();//打开数据库连接 SqlDataReader dr = comm.ExecuteReader();//进行数据库操作 int id = (int)(paraID.Value); if (id==0) { dr.Read(); Re.RecordID = (int)(dr["RecordID"]);//返回SqlDataReader数据集给Re对象赋值 Re.RecordTitle = dr["RecordTitle"].ToString(); Re.RecordDetails = dr["RecordDetails"].ToString(); Re.UserName = dr["UserName"].ToString(); Re.EngineerName = dr["EngineerName"].ToString(); Re.CreateDate = (DateTime)(dr["CreateDate"]); con.Close();//关闭连接 return true; } else { dr.Read(); Re.RecordID = (int)(dr["RecordID"]);//返回SqlDataReader数据集给Red对象赋值 Re.RecordTitle = dr["RecordTitle"].ToString(); Re.RecordDetails = dr["RecordDetails"].ToString(); 300 SQL Server 2005 数据库系统开发案例精选 Re.EngineerName = dr["EngineerName"].ToString(); Re.CreateDate = (DateTime)(dr["CreateDate"]); Red.ReReordContent = dr["ReRecordContent"].ToString(); Red.RevertDate = (DateTime)(dr["RevertDate"]); Red.flag = (int)(DropDownList)(dr["flag"]); con.Close();//关闭连接 return false; } } (8)在 UpdateUsers()方法中,首先将用户 ID、密码作为输入参数传到存储过程 UpdateUserInfo 中,并判断用户名和密码是否正确,如果正确用新密码代替旧密码,否则 密码修改失败。详细代码如下: public static bool UpdateUsers(int ID,string Password,string NewPassword) { try { SqlConnection con = Operation.GetCon(); SqlCommand comm = new SqlCommand("UpdateUserInfo", con); //指明Sql命令的操作类型是使用存储过程 comm.CommandType = CommandType.StoredProcedure; SqlParameter paraID = new SqlParameter("@ID", SqlDbType.Int, 4);//给存储过程添加参数 paraID.Value = ID; comm.Parameters.Add(paraID); SqlParameter paraPassword = new SqlParameter("@Password", SqlDbType.VarChar, 20); paraPassword.Value = Password; comm.Parameters.Add(paraPassword); SqlParameter paraNewPassword = new SqlParameter("@NewPassword", SqlDbType. Var Char, 20); paraNewPassword.Value = NewPassword; comm.Parameters.Add(paraNewPassword); con.Open();//打开数据库连接 comm.ExecuteNonQuery();//进行数据库操作 con.Close();//关闭连接 return true; } catch { return false; } } (9)在 InsertRecords()方法中,将 Records 类对象 Re 的属性字段作为输入参数传到存 储过程 UpdateUserInfo 中,向发布信息表中插入一条记录。详细代码如下: public bool InsertRecords(Records Re) { try { SqlConnection con = Operation.GetCon(); SqlCommand comm = new SqlCommand("AddRecord", con); //指明Sql命令的操作类型是使用存储过程 comm.CommandType = CommandType.StoredProcedure; //给存储过程添加参数 SqlParameter paraRecordTitle = new SqlParameter("@RecordTitle", SqlDbType.VarChar, 50); paraRecordTitle.Value = Re.RecordTitle; comm.Parameters.Add(paraRecordTitle); SqlParameter paraRecordDetails = new SqlParameter("@RecordDetails", SqlDbType. Var Char, 200); paraRecordDetails.Value = Re.RecordDetails; 301 C H A P T E R 7 第 7 章 企业客户管理系统 comm.Parameters.Add(paraRecordDetails); SqlParameter paraUserName = new SqlParameter("@UserName", SqlDbType.VarChar, 20); paraUserName.Value = Re.UserName; comm.Parameters.Add(paraUserName); SqlParameter paraAllot = new SqlParameter("@Allot", SqlDbType.VarChar, 50); paraAllot.Value = Re.Allot; comm.Parameters.Add(paraAllot); SqlParameter paraCreateDate = new SqlParameter("@CreateDate", SqlDbType.DateTime, 8); paraCreateDate.Value = Re.CreateDate; comm.Parameters.Add(paraCreateDate); con.Open();//打开数据库连接 comm.ExecuteNonQuery();//进行数据库操作 con.Close();//关闭连接 return true; } catch { return false; } } (10)在 BindRecords()方法中,发布信息 ID 作为输入参数传到存储过程 BindRecords 中,根据发布信息 ID 在信息发布表中查找匹配的记录,再把结果集绑定到 Records 类对象 Re 上。详细代码如下: public bool BindRecords(int RecordID,Records Re) { try { SqlConnection con = Operation.GetCon(); SqlCommand comm = new SqlCommand("BindRecords", con); //指明Sql命令的操作类型是使用存储过程 comm.CommandType = CommandType.StoredProcedure; SqlParameter paraRecordID = new SqlParameter("@RecordID", SqlDbType.Int, 4); paraRecordID.Value = RecordID; comm.Parameters.Add(paraRecordID); con.Open();//打开数据库连接 SqlDataReader dr = comm.ExecuteReader();//进行数据库操作 dr.Read(); con.Close();//关闭连接 Re.RecordID = (int)(dr["RecordID"]); Re.RecordTitle = dr["RecordTitle"].ToString(); Re.RecordDetails = dr["RecordDetails"].ToString(); Re.EngineerName = dr["EngineerName"].ToString(); Re.CreateDate = (DateTime)(dr["CreateDate"]); return true; } catch { return false; } } (11)在 InsertResearchInfo()方法中,将 Research 类对象 Re 作为输入参数传到存储过 程 InsResearchInfo 中,向服务信息表中插入一条记录。详细代码如下: public bool InsertResearchInfo(Research Re) { try 302 SQL Server 2005 数据库系统开发案例精选 { SqlConnection con = Operation.GetCon(); SqlCommand comm = new SqlCommand("InsResearchInfo", con); //指明Sql命令的操作类型是使用存储过程 comm.CommandType = CommandType.StoredProcedure; //给存储过程添加参数 SqlParameter paraUserName = new SqlParameter("@UserName", SqlDbType.VarChar, 20); paraUserName.Value = Re.UserName;//根据Re对象给存储过程的输入参数赋值 comm.Parameters.Add(paraUserName); SqlParameter paraResearchDate = new SqlParameter("@ResearchDate", SqlDbType. Date Time, 8); paraResearchDate.Value = Re.ResearchDate; comm.Parameters.Add(paraResearchDate); SqlParameter paraAppraise = new SqlParameter("@Appraise", SqlDbType.VarChar, 200); paraAppraise.Value = Re.Appraise; comm.Parameters.Add(paraAppraise); SqlParameter paraReIdea = new SqlParameter("@ReIdea", SqlDbType.Int, 4); paraReIdea.Value = Re.ReIdea; comm.Parameters.Add(paraReIdea); con.Open();//打开数据库连接 comm.ExecuteNonQuery();//进行数据库操作 con.Close();//关闭连接 return true; } catch { return false; } } (12)在 InsertReRecordInfo()方法中,使用 ReRecord 类对象 myre 来作为输入参数传到 存储过程 InsertReRecordInfo 中,向服务信息表中插入一条新记录。详细代码如下: public bool InsertReRecordInfo( ReRecord myre) { try { SqlConnection con = Operation.GetCon(); SqlCommand comm = new SqlCommand("InsertReRecordInfo", con); comm.CommandType = CommandType.StoredProcedure; SqlParameter paraRecordID = new SqlParameter("@RecordID", SqlDbType.Int, 4); paraRecordID.Value = myre.RecordID; comm.Parameters.Add(paraRecordID); SqlParameter paraReReordContent = new SqlParameter("@ReReordContent", SqlDbType. VarChar, 200); paraReReordContent.Value = myre.ReReordContent; comm.Parameters.Add(paraReReordContent); SqlParameter paraEngineerName = new SqlParameter("@EngineerName", SqlDbType. Var Char, 20); paraEngineerName.Value = myre.EngineerName; comm.Parameters.Add(paraEngineerName); SqlParameter paraRevertDate = new SqlParameter("@RevertDate", SqlDbType.DateTime, 8); paraRevertDate.Value = myre.RevertDate; comm.Parameters.Add(paraRevertDate); con.Open(); comm.ExecuteNonQuery(); con.Close(); return true; } catch { return false; 303 C H A P T E R 7 第 7 章 企业客户管理系统 } } (13)在 UpdateReRecordInfo()方法中,使用客户记录 ID、和工作记录表中的记录内容 作为输入参数传到存储过程中,首先以客户记录 ID 作为参数调用 Judge()方法来判断对应 的工作记录 ID 是否为空。如果不为空,则根据输入参数来更新工作记录表。详细代码如下: public bool UpdateReRecordInfo(int RecordID,string ReRecordContent, DateTime dt) { Operation oper = new Operation(); int ID = oper.Judge(RecordID);//根据Judge()返回的值对变量ID赋值 if (ID != 0) { SqlConnection con = Operation.GetCon(); SqlCommand comm = new SqlCommand("UpdateReRecordInfo", con); //指明Sql命令的操作类型是使用存储过程 comm.CommandType = CommandType.StoredProcedure; SqlParameter paraRecordID = new SqlParameter("@RecordID", SqlDbType.Int, 4);//给存储过程 添加参数 paraRecordID.Value = RecordID; comm.Parameters.Add(paraRecordID); SqlParameter paraReRecordContent = new SqlParameter("@ReRecordContent", SqlDbType. VarChar, 200); paraReRecordContent.Value = ReRecordContent; comm.Parameters.Add(paraReRecordContent); SqlParameter paraRevertDate = new SqlParameter("@RevertDate", SqlDbType.DateTime, 8); paraRevertDate.Value=dt; comm.Parameters.Add(paraRevertDate); con.Open();//打开数据库连接 comm.ExecuteNonQuery();//进行数据库操作 con.Close();//关闭连接 return true; } else { return false; } } (14)在 Search 方法中,使用 Search 变量作为输入参数传到存储过程 Find 中,以 Search 变量为查询条件实现模糊查找。详细代码如下: public DataSet Search(string Search) { SqlConnection con = Operation.GetCon(); SqlDataAdapter sdr = new SqlDataAdapter("Find", con); //指明Sql命令的操作类型是使用存储过程 sdr.SelectCommand.CommandType = CommandType.StoredProcedure; //给存储过程添加参数 SqlParameter paraSearch = new SqlParameter("@Search", SqlDbType.VarChar, 50); paraSearch.Value = Search; sdr.SelectCommand.Parameters.Add(paraSearch); con.Open();//打开数据库连接 DataSet ds = new DataSet(); sdr.Fill(ds,"tb_Records"); con.Close(); return ds; } (15)在 count ()方法中,使用 Count 类对象 cou 绑定存储过程 CountIdea 的输出参数, 304 SQL Server 2005 数据库系统开发案例精选 该方法实现了输出参加服务调查的总人数、满意人数、不满意人数及感觉一般的人数。该 方法的详细代码如下: public bool count(Count cou) { try { SqlConnection con = Operation.GetCon(); SqlCommand comm = new SqlCommand("CountIdea", con); comm.CommandType = CommandType.StoredProcedure;//指明Sql命令的操作类型是使用存储过程 SqlParameter paraAll = new SqlParameter("@All", SqlDbType.Int, 4); paraAll.Direction = ParameterDirection.Output;//指出该参数是存储过程的Output参数 comm.Parameters.Add(paraAll); SqlParameter paraGood = new SqlParameter("@Good", SqlDbType.Int, 4); paraGood.Direction = ParameterDirection.Output;//指出该参数是存储过程的Output参数 comm.Parameters.Add(paraGood); SqlParameter paraBed = new SqlParameter("@Bad", SqlDbType.Int, 4); paraBed.Direction = ParameterDirection.Output;//指出该参数是存储过程的Output参数 comm.Parameters.Add(paraBed); SqlParameter paraCommon = new SqlParameter("@Common", SqlDbType.Int, 4); paraCommon.Direction = ParameterDirection.Output;//指出该参数是存储过程的Output参数 comm.Parameters.Add(paraCommon); con.Open();//打开数据库连接 comm.ExecuteNonQuery();//进行数据库操作 con.Close();//关闭连接 cou.All = (int)(paraAll.Value); //根据存储过程的输出参数的值 cou对象赋值 cou.Good = (int)(paraGood.Value); cou.Bad = (int)(paraBed.Value); cou.Common = (int)paraCommon.Value; return true; } catch { return false; } } (16)在 CheckUserName()方法中,使用参数 UserName 作为存储过程 CheckUserName 输入参数,根据参数在用户表中查找该用户,如果查找成功返回 False,否则返回 True。该 方法的详细代码如下: public bool CheckUserName(string UserName) public bool CheckUserName(string UserName) { SqlConnection con = Operation.GetCon(); SqlDataAdapter sda = new SqlDataAdapter("CheckUserName", con); //指明Sql命令的操作类型是使用存储过程 sda.SelectCommand.CommandType = CommandType.StoredProcedure; //给存储过程添加参数 SqlParameter paraUserName = new SqlParameter("@UserName", SqlDbType.VarChar, 20); paraUserName.Value = UserName; comm.SelectCommand.Parameters.Add(paraUserName); DataSet ds = new DataSet(); con.Open();//打开数据库连接 sda.Fill(ds);//执行数据库操作 con.Close();//关闭连接 if (ds.Tables[0].Rows.Count<1) 305 C H A P T E R 7 第 7 章 企业客户管理系统 { return true; } else { return false; } } 7.9 网 站 开 发 7.9.1 用户登录模块 用户登录模块主要用于验证用户登录系统时输入用户名、密码和身份是否正确,只有 通过验证才可以进入系统,否则将不能进入此系统。该页设计结果如图 7.10 所示。 图 7.10 用户登录页设计效果 1.前台页面设计 主要用到的控件及用途如表 7.6 所示。 表 7.6 用户登录模块用到的控件 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 1 布局页面 HTML InPut(Reset) 1 返回到上一页 标准 Button 1 登录 标准 TextBox 2 录入用户名/密码/ 前台页面中主要控件属性设置如下。 (1)设置 Input(Reset)属性。该控件是客户端控件,主要是用来重置页面中的控件设置, 这里设置了其 Value 值为“重置”。 (2)设置 TextBox 属性。该页面中用到了两个 TextBox 控件,其 ID 属性分别是 txtUserName 和 txtPassword,设置 txtPassword 的 TextMode 属性为 Password,使它显示的文本类型为密码。 2.后台功能代码 该页中,首先需要声明一个全局变量,用它来保存用户身份的值,具体代码如下。 306 SQL Server 2005 数据库系统开发案例精选 public int TypeValues;//定义变量TypeValues来保存代表用户身份的值(0代表管理员,1代表工程师,2 代表普通用户,3表示用户没有选择身份登录,该用户将无法登录) 在该页的页面加载事件中需要通过代码给 DropDownList 添加子项,该页 Page_Load 事件代码如下。 protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) {  this.ddlType.Items.Add(new ListItem("请选择身份"));//通过代码给DropDownList添加项 this.ddlType.Items.Add(new ListItem("管理员")); this.ddlType.Items.Add(new ListItem("工程师")); this.ddlType.Items.Add(new ListItem("普通员工")); } } 单击【登录】按钮时,将触发 btnLogin_Click 事件来验证用户是否通过验证。在此事 件中调用了 FindPeople()方法来判断用户是否合法。详细代码如下。 protected void btnLogin_Click(object sender, EventArgs e) {  string UserName=this.txtUserName.Text.Trim(); string Password=this.txtPassord.Text.Trim(); if (this.ddlType.SelectedValue == "管理员") { TypeValues = 0; } if (this.ddlType.SelectedValue == "工程师") { TypeValues = 1; } if (this.ddlType.SelectedValue == "普通员工") { TypeValues = 2; } if (this.ddlType.SelectedValue == "请选择身份") { TypeValues = 3; } if (Operation.FindPeople(UserName, Password, TypeValues)) {  Session["flag"] = true;//用来标识用户登录成功 Session["UserName"] = this.txtUserName.Text.Trim();//使用Session["UserName"]来保存用户名 Session["TypeValues"] = TypeValues;//使用Session["UserName"]来保存登录身份 Session["UserID"] = Operation.UserID;//使用 Session["UserID"]来保存用户ID  Response.Redirect("Index.aspx");//跳转到主页 } else { Response.Write(""); } }  代码导读  Add 方法:将新项追加到 DropDownList 项集合的结尾。  Trim 方法:将 TextBox 文本值结尾的空格去掉。  Session 变量:对象可以存储特定的用户会话所需的信息。其主要用于在给定的应 通过调用自定义 FindPeople 方 法判断用户是否通过身份验证 307 C H A P T E R 7 第 7 章 企业客户管理系统 用程序中所有用户之间共享信息,并在服务器运行期间持久地保存数据。当一个用户第一 次访问站点时,将为其创建一个 Session 对象,并一直保存到用户连接超时或中断连接时, 才释放该 Session 对象。  Redirect 方法:使用该方法跳转到目标页。 7.9.2 主页模块设计 在系统主页面上,主要实现了用 DataList 控件显示信息发布表的信息,并实现了分页 功能。单击发布信息标题可进入到详细信息显示页。该页运行结果如图 7.11 所示。 图 7.11 主页运行效果 1.前台页面设计 主要用到的控件及用途如表 7.7 所示。 表 7.7 主页模块用到的控件 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 3 布局页面 HTML InPut(Button) 1 返回到上一页 标准 Lable 4 分别显示首页/前一页/后一页/尾页 标准 LinkButton 2 分别显示总页数和当前页数 标准 TextBox 1 录入页面跳转到的页数 标准 DataList 1 用于显示信息发布表的信息 前台页面中主要控件属性设置如下。 308 SQL Server 2005 数据库系统开发案例精选 (1)Input(Button)属性设置:该控件是客户端控件,主要是用来返回到上一页,这 里设置了其 Value 值为“重置”。要实现返回到上一页的功能,还必须定义它的 Click 事件。 双击 Input 按钮,在它的 Click 事件中加入“history.go(-1);”。 (2)Lable 属性设置:该页面中,在 DataList 外部主要用到了两个 Label 控件,其 ID 属性分别为 labCount 和 labNowPage,两个控件属性设置基本相同,它们的 ForeColor 属性 设置都为 Red,只是 labNowPage 控件的 Text 属性初始值为 1。 (3)LinkButton 属性设置:该页面中,在 DataList 外部主要用到了 4 个 LinkButton 控 件,其 ID 属性分别为 lnkbtnFirst、lnkbtnFront、lnkbtnNext 和 lnkbtnLast,4 控件的 ForeColor 属性设置都为 Black,Text 属性值分别为“首页”、“上一页”、“下一页”和“尾页”。 该页面中用到了数据显示控件 DataList,主要用来存放从数据库中检索出的符合条件的数据。 用户从 Visual Studio 2005 工具箱的“数据”栏中拖拽出 DataList 控件放置到页面中, 单击其右上角的“ ”图标按钮,在快捷菜单(如图 7.12)中选择“编辑模板”或是右键 单击 DataList 选择快捷菜单中“编辑模板”中“项模板(ItemTemplate)”,即可在 DataList 的项模板(ItemTemplate)中进行编辑。本页面中 DataList 控件项模板编辑如图 7.13 所示。 图 7.12 DataList 快捷菜单 图 7.13 DataList1 项模板布局 DataList 控件中用到的控件列表如表 7.8 所示。 表 7.8 DataList 项模板布局控件列表 工 具 箱 控 件 名 称 数 量 用 途 HTML Table 1 布局页面 标准 Label 4 显示内容 标准 LinkButton 1 显示内容和单击跳转到目标页 表 7.8 中主要控件属性设置如下。 (1)Label 控件属性设置:DataList 控件中的 Label 控件是用来绑定数据库中相关字段, 并显示相关数据信息的。DataList 控件中 Label 控件 ID 属性分别为 labID、labTitle、 labUserName 和 labCreateDate,它们的 Text 属性分别和数据库中的字段绑定,由于其绑定 格式相同,这里就以绑定 labCreateDate 为例,其绑定代码如下: ’> (2)LinkButton 控件属性设置:DataList 控件中的 LinkButton 控件实现了绑定数据库 中相关字段和单击跳转到目标页。如上设置 LinkButton 的 Text 属性就能实现绑定数据库中 相关字段。把 LinkButton 控件的 CommandName 设置为 select,当单击 LinkButton 时将触 发 DataList 控件的 ItemCommand 事件。在此事件中写跳转页面的代码即可。 2.后台功能代码 在该页的页面加载事件中先判断用户是否登录,如果没有登录则跳转到登录页。然后 绑定 bind() 方法在 DataList 控件上显示数据。该页 Page_Load 事件代码如下。 309 C H A P T E R 7 第 7 章 企业客户管理系统 protected void Page_Load(object sender, EventArgs e) { if (Session["flag"] == null) { Response. Redirect ("../Login.aspx"); }  if (!IsPostBack) { //使用正则表达式限定在ID属性为txtGoto的TextBox控件中只能输入数字  txtGoto.Attributes["onkeyup"] = "value=value.replace(/[^\\d]/g,’’)"; this.bind(); } } 在 bind()方法中调用了 ReDataSet()方法来将信息发布表中的数据绑定到 DataList 控件 上,并且实现了分页功能。详细代码如下。 public void bind() { //CurrentPage变量用于存储当前页数  int CurrentPage = Convert.ToInt32(labNowPage.Text); PagedDataSource ps = new PagedDataSource();//生成PagedDataSource的实例 DataSet ds = Operation.ReDataSet("ShowRecords"); //调用ReDataSet方法返回DataSet对象 ps.DataSource = ds.Tables["Records"].DefaultView; ps.AllowPaging = true; //是否可以分页 ps.PageSize = 4; //显示的数量 ps.CurrentPageIndex = CurrentPage - 1; //取得当前页的页码  lnkbtnPrve.Enabled = true; lnkbtnTop.Enabled = true; lnkbtnNext.Enabled = true; lnkbtnLast.Enabled = true; //当前页是第一页 if (CurrentPage == 1) { lnkbtnTop.Enabled = false;//【第一页】按钮不能用 lnkbtnPrve.Enabled = false;//【上一页】按钮不能用 } //当前页是最后一页 if (CurrentPage == ps.PageCount) { lnkbtnNext.Enabled = false;//【下一页】按钮不能用 lnkbtnLast.Enabled = false;//【最后一页】按钮不能用 } this.labCount.Text = Convert.ToString(ps.PageCount); this.DataList1.DataSource = ps; this.DataList1.DataKeyField = "RecordID"; this.DataList1.DataBind(); } 控制 DataList 控件翻页主要是用到 LinkButton 控件,实现分页功能。详细代码如下: protected void lnkbtnTop_Click(object sender, EventArgs e) { this.labNowPage.Text = "1"; this.bind(); } //上一页 protected void lnkbtnPrve_Click(object sender, EventArgs e) { this.labNowPage.Text = Convert.ToString(Convert.ToInt32(this.labNowPage.Text) - 1); this.bind(); 310 SQL Server 2005 数据库系统开发案例精选 } //下一页 protected void lnkbtnNext_Click(object sender, EventArgs e) { this.labNowPage.Text = Convert.ToString(Convert.ToInt32(this.labNowPage.Text) + 1); this.bind(); } //尾页 protected void lnkbtnLast_Click(object sender, EventArgs e) { this.labNowPage.Text = this.labCount.Text; this.bind(); } //直接跳转 protected void btnGo_Click(object sender, EventArgs e) { int count = Convert.ToInt32(this.txtGoto.Text.Trim()); int all = Convert.ToInt32(this.labCount.Text); if (all < count) { Response.Write(""); } else { this.labNowPage.Text = this.txtGoto.Text; this.bind(); } } 当单击 DataLis1 中 ID 属性为 lnkbtnTit 的 LinkButton 控件时,将触发 DataList1 的 ItemCommand 事件,在此事件中使用 Redirect 方法跳转到 RecordDetails.aspx,并且向该页 面传一个发布信息 ID 的值。详细代码如下。 protected void DataList1_ItemCommand(object source, DataListCommandEventArgs e) { int RecordID = Convert.ToInt32(DataList1.DataKeys[e.Item.ItemIndex]); Response.Redirect("RecordDetails.aspx?RecordID=" + RecordID + ""); }  代码导读  IsPostBack 属性:通过该属性判断页面是否第一次加载。通过使用该属性来减少代 码执行的数量。  Attributes 属性:通过该属性获取该控件没有的任意特性。  Convert 类:使用该属性将一种基本数据类型转换为另一种基本数据类型。  Enabled 属性:通过设置该属性来控制控件是否可用(属性值为 True 时可用,否 则不可用)。 技术细节 在 DataList 控件中,是通过绑定 DataList 模板中的子控件来显示数据的。 在本系统中主要使用 Lable 作为 DataList 显示数据的子控件,绑定数据的关键代码 如下。 ’> 其中 CreateDate 是该 Lable 控件要显示的数据库中的字段。 判断用户输入的页数是否大于当前 页索引,如果大于则弹出警告框 311 C H A P T E R 7 第 7 章 企业客户管理系统 由于 DataList 控件不自带分页的功能,不能像在 GridView 控件中利用其自带的分页 功能,比较容易的实现分页。分页功能代码在本节有详细的代码可供读者参考。 7.9.3 站内搜索模块 本页是在主页基础上实现的,都是将数据绑定到 DataList 控件上。在本页调用了 Search() 方法检索数据,显示在 DataList 控件上。Search()方法实现了发布信息 ID 和发布信息标题 的模糊查询。该页运行结果如图 7.14 所示。 图 7.14 站内搜索页面效果 1.前台页面设计 主要用到的控件及用途如表 7.9 所示。 表 7.9 站内搜索模块用到的控件 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 4 布局页面 HTML InPut(Button) 1 返回到上一页 标准 Lable 6 分别显示总页数/当前页数/首页/前一页/后一页/尾页 标准 TextBox 2 录入搜索条件和跳转到的页数 验证 RequiredFieldValidator 1 验证 TextBox 文本是否为空 标准 DataList 1 用于显示信息发布表的信息 标准 Button 1 搜索 312 SQL Server 2005 数据库系统开发案例精选 本页是在主页的基础上实现的,主要功能是根据搜索条件将检索到的数据绑定到 DataList 控件在页面上显示出来。其中用于录入搜索条件的 TextBox 控件的 ID 属性为 txtSearch。 2.后台功能代码 在该页的页面加载事件中,先判断用户是否登录,如果没有登录则跳转到登录页。然 后绑定 Bind() 方法在 DataList 控件上显示数据。该页 Page_Load 事件代码如下。 protected void Page_Load(object sender, EventArgs e) { if (Session["flag"] == null) { Response.Redirect("../Login.aspx"); } if (!IsPostBack) { //使用正则表达式限定在ID属性为txtGoto的TextBox控件中只能输入数字 txtGoto.Attributes["onkeyup"] = "value=value.replace(/[^\\d]/g,’’)"; Bind(); } } 在 Bind()方法中,调用了公共类中的 ReDataSet ()方法返回一个 DataSet 数据集。将发 布信息全部绑定到 DataList 上显示出来并实现分页功能。由于本段代码较长,且在 5.7.2 节 中有详细描述,在此为节省篇幅,只给出与 5.7.2 节中不同的部分。 public void Bind() { ⋯⋯/ /此处省略 Operation oper=new Operation();//生成Operation类实例 DataSet ds = Operation.ReDataSet("ShowRecords");//调用ReDataSet方法返回DataSet对象 ps.DataSource = ds.Tables["Records"].DefaultView; ⋯⋯/ /此处省略 } 单击【搜索】按钮时将触发其 Click 事件,在 Click 事件中调用了 bind()方法来显示搜 索到记录。详细代码如下: protected void btnSearch_Click(object sender, EventArgs e) { this.bind(); } 在 bind()方法中,调用了公共类中的 Search()方法返回一个 DataSet 数据集。再把它绑 定到 DataList 控件在页面上显示出来并实现分页功能。同样这里只给出与 5.7.2 节中不同的 部分。 public void bind() { ⋯⋯/ /此处省略 Operation oper=new Operation();//生成Operation类实例 DataSet ds = oper.Search(search); //调用Search()方法返回一个DataSet数据集 if (ds.Tables["tb_Records"].Rows.Count == 0)//判断数据集中有没有记录 { Response.Write(""); } ps.DataSource = ds.Tables["tb_Records"].DefaultView; 313 C H A P T E R 7 第 7 章 企业客户管理系统 ⋯⋯/ /此处省略 } 当单击 DataList1 中 ID 为 lnkbtnTit 的 LinkButton 控件时,触发其 ItemCommand 事件。 在此事件中使用 Redirect 方法跳转到 RecordDetails.aspx,并且向该页面传一个发布信息 ID 的值。详细代码如下。 protected void DataList1_ItemCommand(object source, DataListCommandEventArgs e) { int RecordID = Convert.ToInt32(DataList1.DataKeys[e.Item.ItemIndex]); Response.Redirect("RecordDetails.aspx?RecordID=" + RecordID + ""); } 控制 DataList 控件翻页用到了 4 个 LinkButton 按钮、一个 TextBox 和一个 Button 按钮, 实现分页功能。详细代码请参考 5.7.2 节的关于分页按钮 Click 事件对应的代码: 技术细节 本页主要功能是实现了模糊搜索。 要实现模糊搜索,主要通过 SQL 语句或存储过程来实现。其中存储过程请参考 5.4.3 节中的第三小节名为“Find”存储过程。下面讲一下使用 SQL 语句实现模糊搜索。SQL 语句如下: select * from tb_Records where RecordID like ’%’+@Search+’%’ or RecordTitle like’%’+@Search+’%’ 7.9.4 详细信息显示模块 本页是用来显示发布信息的详细信息。如果此信息有反馈信息则显示反馈内容和时间。 如果没有反馈信息则反馈内容和时间都显示为“无”。回复该发布信息的工程师进入到此页, “修改”按钮就会显示出来,以修改反馈内容。该页设计效果如图 7.15 所示。 图 7.15 详细信息显示页设计效果 314 SQL Server 2005 数据库系统开发案例精选 1.前台页面设计 本页显示了发布信息的详细信息,如果此发布信息已经被回复,则将对应的反馈内容 和反馈时间显示出来。如果没有回复则显示“无”。如果回复该发布信息的工程师进入到此 页,则可修改反馈内容。 主要用到的控件及用途如表 7.10 所示。 表 7.10 详细信息显示模块用到的控件 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 2 布局页面 HTML InPut(Button) 1 返回到上一页 标准 Button 1 执行修改 标准 Lable 5 分别显示发布信息 ID/信息标题/信息内容/ 发布人/处理工程师/回复日期 标准 TextBox 2 分别显示信息描述和显示及修改反馈信息 前台页面中主要控件属性设置如下。 (1)Input(Button)属性设置:该控件是客户端控件,主要是用来返回到上一页,这里设 置了其 Value 值为“重置”。要实现返回到上一页功能,还必须定义它的 Click 事件。双击 Input 按钮,在 Click 事件中加入“history.go(-1);”。 (2)Lable 属性设置:该页面中,用到了 5 个 Lable 控件。其 ID 属性分别为 labID、labTitle、 labUserName、labEngineerName、labDateTime。 (3)TextBox 属性设置:该页面中,用到了两个 TextBox 控件。其 ID 属性分别为 txtRecordContent 和 txtReRecordContent。它们的 TextMode 属性都为 MultiLine,用来显示 多行文本。 2.后台功能代码 该页中,首先需要申明一个全局静态变量,用它来判断反馈信息是否被修改过。具体 代码如下: public static int flag;//值为0时表示修改过,值为1时表示没有被修改过 在该页的页面加载事件中,先判断用户是否登录,如果没有登录则跳转到登录页。然 后判断该发布信息的反馈信息是否被修改过,如果被修改过,则把 ID 为 labDate 的 Lable 控件的 Texts 属性修改为“修改于”,最后绑定 BindReRecordInfo()方法将数据绑定到 Lable 和 TextBox 控件上显示出来。该页 Page_Load 事件代码如下: protected void Page_Load(object sender, EventArgs e) { if (Session["flag"] == null && Session["TypeValues"]==null) { Response.Redirect("../Login.aspx"); } if (!IsPostBack) { if (flag!=0)//如果被修改过 { this.labDate.Text = "修改于"; } this.BindReRecordInfo(); 使用 flag 来判断该记录是否被修改过,把 ID 为 labDate 的 Lable 控件的 Text 属性改为“修 改于”,它默认的 Text 属性为“反馈日期” 315 C H A P T E R 7 第 7 章 企业客户管理系统 } } BindReRecordInfo()方法对应的代码如下。 public void BindReRecordInfo() { int RecordID = Convert.ToInt32(Request["RecordID"]);//用Request方法来接受主页传过来的值 Operation oper = new Operation();//生成Operation类的实例 Records Re = new Records();//生成Records类的实例 ReRecord Red = new ReRecord();//生成ReRecord类的实例 if (oper.SelRecordReRecord(RecordID, Re, Red)) { this.labID.Text = Re.RecordID.ToString(); this.labTitle.Text = Re.RecordTitle; this.txtRecordContent.Text = Re.RecordDetails; this.labUserName.Text = Re.UserName; this.labEngineerName.Text = Re.EngineerName; this.txtReRecordContent.Text = "无"; this.labDateTime.Text = "无"; } else { this.labID.Text = Re.RecordID.ToString(); this.labTitle.Text = Re.RecordTitle; this.txtRecordContent.Text = Re.RecordDetails; this.labUserName.Text = Re.UserName; this.labEngineerName.Text = Re.EngineerName; this.txtReRecordContent.Text = Red.ReReordContent; this.labDateTime.Text = Red.RevertDate.ToString(); flag = int.Parse(Red.Flag.ToString()); int TypeValues = Convert.ToInt32(Session["TypeValues"]);//取得用户登录类型的状态值 if (this.labEngineerName.Text == Session["UserName"].ToString() && TypeValues == 1) { this.btnAmend.Visible = true; } } } 单击【修改】按钮时,将触发 btnAmend_Click 事件。在 btnAmend_Click 事件中调用 了 UpdateReRecordInfo()方法来更新信息反馈表中的“反馈内容”字段。详细代码如下: protected void btnAmend_Click(object sender, EventArgs e) { int RecordID = int.Parse(this.labID.Text);//取得发布信息ID string ReRecordContent = this.txtReRecordContent.Text.Trim(); DateTime dt=DateTime.Now; Operation oper = new Operation(); if (oper.UpdateReRecordInfo(RecordID, ReRecordContent,dt)) { Response.Write(""); this.labDate.Text = "修改于"; } else { Response.Write(""); } } 当对应的管理员修改了 TextBox 的文本内容后,将触发 txtReRecordContent_Text Changed 调用 SelRecordReRecord()方法返回 数据,如果返回值为 True,表示工程 师没有回复,则把反馈日期和反馈内 容都设为“无” 如果该记录的指定工程师和用户登 录类型与工程师的用户名一致,显 示修改按钮 调用 UpdateReRecordInfo () 方法修改反馈内容 316 SQL Server 2005 数据库系统开发案例精选 事件,这时把【修改】按钮由不可用的变为可用的: protected void txtReRecordContent_TextChanged(object sender, EventArgs e) { this.btnAmend.Enabled = true;//如果用户修改了反馈内容,则修改按钮是可用的 } 7.9.5 发布信息添加模块 本页实际上包括两部分:发布信息添加和服务调查信息添加模块。由于这两个部分界 面设计简单、相似,所以就把这两个模块放在同一个页面上。通过 Panel 来控制这两个模 块的显示和隐藏。该页设计效果如图 7.16 所示。 图 7.16 发布信息添加页面设计效果图 1.前台页面设计 主要用到的控件及用途如表 7.11 所示。 表 7.11 发布信息添加模块用到的控件 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 3 布局页面 HTML InPut(Reset) 2 重置 标准 Panel 2 分别实现隐藏/显示发布信息添加模块 和服务调查信息添加模块 标准 TextBox 3 录入发布信息标题/发布内容/评价 标准 Button 2 执行添加 标准 RadioButton 3 选择满意/一般/不满意 317 C H A P T E R 7 第 7 章 企业客户管理系统 前台页面中主要控件属性设置如下。 (1)Input(Reset) 属性设置:该页面中,用到了两个 Input 控件。Input 控件是客户端控 件,主要是用来重置页面中的控件设置,这里设置了其 Value 值都为“重置”。 (2)TextBox 属性设置:该页面中,用到了 3 个 TextBox 控件,其 ID 分别是 txtTitle 、 txtRecordDetails 和 txtyijian,设置 txtRecordDetails 和 txtyijian 的 TextMode 属性为 MultiLine, 用来显示多行文本。 (3)RadioButton 属性设置:在本页中,用到了 3 个 RadioButton 控件,它们 ID 分别为 radButtonmanyi、radButtonyiban 和 radButtonbumanyi。其中 radButtonmanyi 的 Checked 属 性默认为 True。设置它们的 GroupName 属性都为 1。 2.后台功能代码 在该页的页面加载事件中,先判断用户是否登录和用户名是否为空,如果为空则跳转 到登录页。该页 Page_Load 事件代码如下: protected void Page_Load(object sender, EventArgs e) { if (Session["flag"] == null&&Session["UserName"]==null) { Response.Redirect("../Login.aspx"); } if (!IsPostBack) { this.Label1.Text = "请填写下面的信息,我们将及时回复你:";  this.Panel1.Visible = true;//用Panel1控制显示发布信息添加模块 this.Panel2.Visible = false; // 用Panel2控制隐藏服务调查信息添加模块 } } 当填写完发布信息标题和发布内容后,单击【提交】按钮把记录插入到信息发布表中。 详细代码如下: protected void btnClickOK_Click(object sender, EventArgs e) { Operation oper = new Operation();//生成Operation类对象oper Records ds = new Records();//生成Records类对象ds //将txtRecordTitle的文本值绑定到ds的RecordTitle属性字段上 ds.RecordTitle = this.txtRecordTitle.Text.Trim(); //将txtRecordDetails的文本值绑定到ds的RecordDetails属性字段上 ds.RecordDetails = this.txtRecordDetails.Text.Trim(); ds.UserName = Session["UserName"].ToString();//用Session取得当前用户的用户名 ds.Allot = "0";//把指定回复工程师的状态值设为0,(0为未指定工程师,1为指定了)  DateTime dt = DateTime.Now;//取得当前系统时间 ds.CreateDate = dt; if (oper.InsertRecords(ds)) { Response.Write(""); } else { Response.Write(""); } } 在发布信息模块中单击【参加服务调查】,把发布信息模块隐藏,显示调查信息模块。 318 SQL Server 2005 数据库系统开发案例精选 详细代码如下: protected void LinkButton1_Click(object sender, EventArgs e) { this.Panel1.Visible = false;//用Panel1控制隐藏发布信息添加模块 this.Panel2.Visible = true;// 用Panel2控制显示服务调查信息添加模块 } 当填写完调查信息后,单击【提交】按钮,向服务调查表中添加一条记录,详细代码 如下: protected void btnSubmis_Click(object sender, EventArgs e) { Operation ope = new Operation(); Research Research = new Research(); Research.UserName = Session["UserName"].ToString(); DateTime dt = DateTime.Now; Research.ResearchDate = dt; Research.Appraise = this.txtyijian.Text.Trim(); //使用单选按钮控件来判断用户对网站的满意度  if (this.radButtonmanyi.Checked) { Research.ReIdea = 0;//为不满意 } if (this.radButtonyiban.Checked) { Research.ReIdea = 1;//1为满意 } if (this.radButtonbumanyi.Checked) { Research.ReIdea = 2;//2为感觉一般 } if (ope.InsertResearchInfo(Research)) {  Response.Write(""); } else { Response.Write(""); } } }  代码导读  Visible 属性:控制控件的显示和隐藏(为 True 时显示控件,为 False 时隐藏控件)。  Now 函数:根据计算机系统设定的日期和时间返回当前的日期和时间值。  Checked 属性:判断 CheckBox 控件是否被选中。  Write 方法:在 Response 对象中,Write 方法可以说是最普遍、最常用的方法,它 可以把信息从服务器端直接发送给客户端,其实就是在客户端动态显示内容。Write 方法 的功能是很强大的,它可以输出几乎所有的对象和数据。 7.9.6 任务分配模块 在普通用户发布问题之后,管理员需要把这些问题集中起来分发给工程师来解决。由 对应的工程师来回复。该页设计效果如图 7.17 所示。 319 C H A P T E R 7 第 7 章 企业客户管理系统 图 7.17 任务分配页面运行效果 1.前台页面设计 主要用到的控件及用途如表 7.12 所示。 表 7.12 指定工程师模块用到的控件 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 3 布局页面 HTML InPut(Reset) 1 重置 标准 Panel 1 实现隐藏/显示分配工程师模块 标准 Button 1 确定指定工程师 标准 Lable 4 显示发布信息 ID/信息标题/发布人/提交时间 标准 TextBox 1 显示发布内容 标准 DropDownList 1 选择工程师的用户名 数据 GridView 1 显示用户信息表信息 前台页面中主要控件属性设置如下。 (1)Input(Reset)属性设置:Input 控件是客户端控件,主要是用来重置页面中的控件设 置,这里设置了其 Value 值为“重置”。 (2)Lable 属性设置:该页面中,用到了 4 个 Lable 控件。其 ID 属性分别为 labID、labTitle、 labUserName 和 labDateTime。 (3)TextBox 属性设置:该页面中,使用 TextBox 控件显示用户发布内容,其 ID 属性 为 txtContent,设置 TextMode 为 MultiLine 用来显示多行文本。 320 SQL Server 2005 数据库系统开发案例精选 (4)DropDownList 属性设置:该页面中,使用 DropDownList 控件方便管理员添加用 户时选择用户角色。然后通过代码在后台添加项。这里设置了该控件的 ID 属性为 ddlRole。 (5)GridView 属性设置:该页面中,GridView 控件主要 用来显示用户发布信息。其 ID 属性为 gvReRecordInfo,设置 分页属性 AllowPaging 为 True,PageSize 属性设置为 5,然后, 对其进行数据绑定。 单击 GridView 控件右上方的 按钮,在弹出的快捷菜单 中选择“编辑列”选项,如图 7.18 所示。 弹出图 7.19 所示的“字段”对话框。 图 7.19 “字段”对话框 在该对话框中,通过添加“BoundField”控件绑定字段,并将其 DataField 和 HeaderText 属性设置为要绑定的字段名称和该列头标题名。如图 7.19 所示,DataField 和 HeaderText 属性分别为 RecordID 和“序号”。 通过添加一个“CommandField”中的删除按钮来删除对应列中信息,将其 HeaderText 和 DeleteText 属性都设置为删除,如图 7.20 所示。 单击此处添加删除按钮 图 7.20 添加删除按钮 图 7.18 选择“编辑列”选项 321 C H A P T E R 7 第 7 章 企业客户管理系统 通过添加一个“CommandField”中的选择按钮来选择对应列中信息,如图 7.21 所示。 添加选择按钮将其 HeaderText 和 SelectText 属性分别设置为“分配工程师”和“分配”。 单击此处添加选择按钮 图 7.21 添加选择按钮 2.后台功能代码 在该页的页面加载事件中先判断用户是否登录,如果没有则跳转到登录页面。绑定 this.Bindgv()和 this.Bindddl()方法将数据分别显示在 GridView 和 DropDown 控件上。该页 Page_Load 事件代码如下: protected void Page_Load(object sender, EventArgs e) { if (Session["Flag"] == null) { Response.Redirect("../Login.aspx"); } if (!IsPostBack) { this.Bindgv(); this.Bindddl(); this.Panel1.Visible = true; this.Panel2.Visible = false; } } Bindgv()方法将发布信息中没有指定工程师的记录检索出来绑定到 GridView 控件上。 详细代码如下: public void Bindgv() { DataSet ds = Operation.ReDataSet("SelectRecords"); this.gvReRecordInfo.DataSource = ds; this.gvReRecordInfo.DataKeyNames = new string[] { "RecordID" }; this.gvReRecordInfo.DataBind(); } 在 Bindddl()方法中,将用户信息表中的 UserName 字段绑定到 DropDownList 控件上。 详细代码如下: public void Bindddl() { DataSet ds = Operation.ReDataSet("SelRecords"); 322 SQL Server 2005 数据库系统开发案例精选 this.ddlEngineer.DataSource = ds; this.ddlEngineer.DataTextField = "UserName"; this.ddlEngineer.DataBind(); } 在 GridView 控件中实现分页功能的代码如下: protected void gvReRecordInfo_PageIndexChanging(object sender, GridViewPageEventArgs e) { this.gvReRecordInfo.PageIndex = e.NewPageIndex; this.Bindgv(); } 在 GridView 控件中单击【删除】按钮,触发 RowDeleting 事件,在此事件中调用了 Operation 类的静态方法 ExSql()来执行删除命令。详细代码如下: protected void gvReRecordInfo_RowDeleting(object sender, GridViewDeleteEventArgs e) { int ID = Convert.ToInt32(this.gvReRecordInfo.DataKeys[e.RowIndex].Value.ToString());//取得在 GridWiew中选中行的id Operation.ExSql("DelRecords", ID); this.Bindgv(); } 在 GridView 控件中,单击【选择】按钮,将触发 SelectedIndexChanging 事件,在此事件中使 用 Record 类对象 Re 将 GridView 控件中的数据绑定到 Lable 和 TextBox 控件上。详细代码如下: protected void gvReRecordInfo_SelectedIndexChanging(object sender, GridViewSelectEventArgs e) { int ID = Convert.ToInt32 (this.gvReRecordInfo.DataKeys [e.NewSelectedIndex]. Value. ToStri ng()); Records Re = new Records(); if (Operation.ReDataReader(ID, Re)) { this.labID.Text =Convert.ToString(ID); this.labTitle.Text = Re.RecordTitle;//将类对象Re的属性字段绑定到控件上显示出来 this.txtContent.Text = Re.RecordDetails; this.labDateTime.Text = Convert.ToString(Re.CreateDate); this.labUserName.Text = Re.UserName; } } protected void gvReRecordInfo_RowDataBound(object sender, GridViewRowEventArgs e) { if (e.Row.RowType == DataControlRowType.DataRow) { ((LinkButton)(e.Row.Cells[5].Controls[0])).Attributes.Add("onclick", "return confirm(’确定删除吗?’)"); } } 在指定好工程师之后,单击【确定】按钮,将数据更新到信息发布表。详细代码如下: protected void btnClickOK_Click(object sender, EventArgs e) { int ID = Convert.ToInt32(this.labID.Text); string EngineerName = this.ddlEngineer.SelectedValue.ToString(); if (Operation.updateRecords(ID, EngineerName)) { Response.Write(""); } else { Response.Write(""); } } 调用 ReDataReader()方 法将记录显示在页面上 获取发布信息 ID 及工程 师名称,将发布信息分给 不同的工程师处理 323 C H A P T E R 7 第 7 章 企业客户管理系统 7.9.7 用户信息添加模块 本页是管理员用于添加用户的模块,只有管理员才有权限进入。该页设计效果如图7.22 所示。 图 7.22 用户信息添加页面设计效果 1.前台页面设计 主要用到的控件及用途如表 7.13 所示。 表 7.13 用户信息添加模块用到的控件 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 3 布局页面 HTML InPut(Reset) 1 重置 标准 Panel 2 分别实现隐藏/显示发布信息添加模 块和服务调查信息添加模块 标准 Button 1 执行添加 标准 DropDownList 1 选择管理员/工程师/普通用户角色 标准 RadioButton 2 选择男/女 标准 TextBox 4 录入用户名/密码/核对密码/联系电话 验证 RequiredFieldValidator 4 验证 TextBox 的文本是否为空 验证 CompareValidator 1 验证两次输入密码是否一致 数据 GridView 1 显示用户信息表信息 324 SQL Server 2005 数据库系统开发案例精选 前台页面中主要控件属性设置如下。 (1)Input(Reset)属性设置:该页面中,用到了两个 Input 控件。Input 控件是客户端 控件,主要是用来重置页面中的控件设置,这里设置了其 Value 值都为“重置”。 (2)DropDownList 控件属性设置:该页中用到了一个 DropDownList 控件,用来方便 管理员添加用户时选择用户角色。然后通过代码在后台添加项。这里设置了该控件的 ID 属 性为 ddlRole。 (3)RadioButton 属性设置:在本页中,用到了两个 RadioButton 控件,它们的 ID 分别 为 radButtonMan 和 radButtonWoman。其中 radButtonMan 的 Checked 属性默认为 True。设 置它们的 GroupName 都为 1。 (4)TextBox 属性设置:该页面中,用到了 4 个 TextBox 控件,其 ID 分别是 txtUserName、 txtPassword、txtPasswordAgain 和 txtPhone。 (5)RequiredFieldValidator 控件属性设置:该页面中用到了 4 个 RequiredFieldValidator 控件,分别是用来验证控件 txtUserName、txtPassword、txtPasswordAgain、txtPhone 是否 为空。以 RequiredFieldValidator1 控件为例,主要设置了两个属性 ControlToValidate 和 ErrorMessage,其属性值分别为 txtUserName 和“*”。 (6)CompareValidator 控件属性设置:该页面中用到了一个 CompareValidator 控件,用来 验证两次密码输入是否一致。在此主要设置了三个属性 ControlToCompare、ControlToValidate 和 ErrorMessage,其属性值分别为 txtPassword、txtPasswordAgain 及密码不能为空。 2.后台功能代码 该页中,首先需要申明一个全局变量,用它来保存用户身份的值,具体代码如下: public int Type; //定义变量TypeValues来保存代表用户身份的值(0代表管理员,1代表工程师,2代表普通用户) 在该页的页面加载事件中先判断用户是否登录,如果没有则跳转到登录页。然后绑定 Bindgv () 方法将数据绑定 GridView 控件上。并且使用代码添加 DropDownList 控件的子项。 该页 Page_Load 事件代码如下: protected void Page_Load(object sender, EventArgs e) { if (Session["flag"] == null) { Response.Redirect("../Login.aspx"); } if (!IsPostBack) { this.Panel1.Visible = true; this.Panel2.Visible = false; //使用代码添加DropDownList控件的项 this.ddlRole.Items.Add(new ListItem("选择角色")); this.ddlRole.Items.Add(new ListItem("管理员")); this.ddlRole.Items.Add(new ListItem("工程师")); this.ddlRole.Items.Add(new ListItem("普通员工")); this.Bindgv();//绑定Bindgv()方法 } } Bindgv()方法调用了Operation类的ReDataSet()方法返回一个DataSet数据集。详细代码如下: public void Bindgv() { 325 C H A P T E R 7 第 7 章 企业客户管理系统 DataSet ds = Operation.ReDataSet("BindUsersInfo"); this.gvUsersInfo.DataSource = ds; this.gvUsersInfo.DataKeyNames=new string[]{"ID"}; this.gvUsersInfo.DataBind(); } 当填写完调查信息后,单击【添加】按钮,向用户信息表中添加一条记录,详细代码 如下: protected void btnClickOk_Click(object sender, EventArgs e) { string UserName = this.txtUserName.Text.Trim(); string Password = this.txtPassword.Text.Trim(); string Telephone = this.txtPhone.Text.Trim(); int Sex; if (this.rBtnMan.Checked)//使用单选按钮选择性别 { Sex = ’0’;//选择“男”的时候把性别状态值设为0 } else { Sex = ’1’;//选择“女”的时候把性别状态值设为1 } if (this.ddlType.SelectedValue == "管理员") { Type = 0; //当选择管理员时是把用户身份状态值设为0 } if (this.ddlType.SelectedValue == "工程师") { Type = 1; //当选择工程师时是把用户身份状态值设为1 } if (this.ddlType.SelectedValue == "普通员工") { Type = 2; //当选择普通员工时是把用户身份状态值设为2 } if (this.ddlType.SelectedValue == "选择角色") { Response.Write(""); } if(Operation.InsertUserInfo(UserName,Password,Sex,Telephone,Type)) { Response.Write(""); } else { Response.Write(""); } } 由于在数据库中性别和角色信息都是用数字表示(性别用“0”表示男,“1”表示女, 角色用“0”表示管理员,“1”表示工程师,“2”表示普通用户),而在显示时不能显示 “0”, “1”或者“2”,所以必须把其转换成相应的汉字。并且在删除数据时应该给出提 示信息。选中 GridView 控件,显示 GridView 的事件,然后双击 RowDataBound 事件,在 RowDataBound 事件中编写代码。代码如下: protected void gvUsersInfo_RowDataBound(object sender, GridViewRowEventArgs e) { if (e.Row.RowType == DataControlRowType.DataRow) { 调用 InsertUserInfo 方 法来插入用户信息 326 SQL Server 2005 数据库系统开发案例精选 if (e.Row.Cells[2].Text =="0") { e.Row.Cells[2].Text ="男"; } else { e.Row.Cells[2].Text = "女"; } if (e.Row.Cells[4].Text == "0") { e.Row.Cells[4].Text = "管理员"; } if (e.Row.Cells[4].Text == "1") { e.Row.Cells[4].Text = "工程师"; } else { e.Row.Cells[4].Text = "普通员工"; } ((LinkButton)(e.Row.Cells[5].Controls[0])).Attributes.Add("onclick","return comfirm(’你确 定要删除吗?’)"); //确定删除提示信息 } } 在 GridView 控件中单击【删除】按钮时,将触发 gvUsersInfo_RowDeleting 事件,在 此事件中调用了 Operation 类的静态方法 ExSql 来删除记录。选中 GridView 控件,显示 GridView 的事件,然后双击 RowDeleting 事件,在 RowDeleting 事件中编写如下代码: protected void gvUsersInfo_RowDeleting(object sender, GridViewDeleteEventArgs e) { int ID = Convert.ToInt32( this.gvUsersInfo.DataKeys[e.RowIndex].Value.ToString());//取得在GridWiew 中选中行的ID Operation.ExSql("DelUsersInfo", ID); this.Bindgv(); } 选中 GridView 控件,把 AllowPaging 属性设为 True, 双击 PageIndexChanging 事件, 在 PageIndexChanging 事件中编写分页代码。代码如下: protected void gvUsersInfo_PageIndexChanging(object sender, GridViewPageEventArgs e) { this.gvUsersInfo.PageIndex = e.NewPageIndex; this.Bindgv(); } 单击 Text 属性为【检查用户名】的 LinkButton 按钮,触发 Click 事件,在此事件中调 用了 Operation 类中的 CheckUserName()来判断该用户名是否存在。详细代码如下: protected void lnkbtnUserName_Click(object sender, EventArgs e) { string UserName= this.txtUserName.Text.Trim(); Operation oper=new Operation(); if (oper.CheckUserName(UserName)) { Response.Write(""); } else { Response.Write(""); 327 C H A P T E R 7 第 7 章 企业客户管理系统 this.txtUserName.Text="";//清空文本内容 } } 7.9.8 服务调查查看模块 本页是显示服务调查结果的。管理员进入到该页之后能浏览和删除服务调查信息。而 普通用户和工程师只能浏览该信息。该页运行结果如图 7.23 所示。 图 7.23 服务调查页面运行效果 1.前台页面设计 主要用到的控件及用途如表 7.14 所示。 表 7.14 服务调查模块用到的控件 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 3 布局页面 HTML InPut(Button) 1 返回到上一页 标准 Image 1 显示饼图 数据 GridView 1 显示服务调查表数据 (1)Input(Button)属性设置:该控件是客户端控件,主要是用来返回到上一页,这里设 置了其 Value 值为“重置”。它要实现返回到上一页,还必须定义它的 Click 事件。双击 Input 按钮,在它的 Click 事件中加入“history.go(-1);”。 (2)Image 控件属性设置:在页面中,用到了一个 Image 控件,主要用来显示饼图。 在此主要设置了 ImageAlign 属性和 ImageUrl 属性来分别控制显示图片的方式和路径,对 328 SQL Server 2005 数据库系统开发案例精选 应的属性值为 Middle 和“~/tubiao.aspx”。 (3)该页中用到了 1 个 GridView 控件,其属性设置与节中 GridView 控件的设置大致 相同,只是其 ID 属性改为 gvGoodsInfo 并且 不添加选择按钮,把绑定 Appraise 字段的列变 成模板列,然后选中 ID 属性为 gvGoodsInfo 的 GridView 控件,单击 GridView 控件右上方 的“ ”按钮,在弹出的快捷菜单中选择“编 辑模板”选项,弹出编辑模板如图 7.24 所示。 (4)把模板中的 Lable 控件的 Text 及 ToolTip 属性都设置为“<%# Bind("Appraise") %>”。 2.后台功能代码 本页实际上由两页组合而成:在 ShowResearch.aspx 上使用 Image 控件的 ImageUrl 属 性将 tubiao.aspx 作为一张图片显示出来。 首先讲述 tubiao.aspx 后台代码。tubiao.aspx 实际上是一张用代码画的饼图,直观地显 示了服务调查中满意人数、不满意人数和感觉一般的人数。该页中,首先需要引入命名空 间 System.Drawing,用来绘制图形。详细代码如下: protected void Page_Load(object sender, EventArgs e) { this.CreateImage(); } private void CreateImage() { Count cou = new Count(); Operation oper = new Operation(); if (oper.count(cou)) { int All = cou.All;//参加服务调查的总人数 int Good = cou.Good;//满意人数 int Bad = cou.Bad;//不满意人数 int Common = cou.Common;//感觉一般人数 int width = 330, height = 285; Bitmap bitmap = new Bitmap(width, height); Graphics g = Graphics.FromImage(bitmap); try { //清空背景色 g.Clear(Color.White); Pen pen1 = new Pen(Color.Red); Brush brush1 = new SolidBrush(Color.White); Brush brush2 = new SolidBrush(Color.Blue); Brush brush3 = new SolidBrush(Color.Brown); Brush brush4 = new SolidBrush(Color.Green); Brush brush5 = new SolidBrush(Color.CornflowerBlue); Font font1 = new Font("Courier New", 12, FontStyle.Bold); Font font2 = new Font("Courier New", 8); //绘制背景图 g.FillRectangle(brush1, 0, 0, width, height); //书写标题 g.DrawString("服务调查示意图", font1, brush5, new Point(90, 20)); int piex = 80, piey = 50, piew = 150, pieh = 150; 计算得到满意、不满意和感觉一般 的人数在总人数所占比例来画图 图 7.24 编辑模板示意 329 C H A P T E R 7 第 7 章 企业客户管理系统 //满意人数在圆中分配的角度 float angle1 = Convert.ToSingle((360 /Convert.ToSingle(All)) * Convert.ToSingle(Good)); //不满意人数在圆中分配的角度 float angle2 = Convert.ToSingle((360 / Convert.ToSingle(All)) * Convert.ToSingle(Bad)); //感觉一般人数在圆中分配的角度 float angle3 = Convert.ToSingle((360 / Convert.ToSingle(All)) * Convert. ToSingle (Common)); g.FillPie(brush2, piex, piey, piew, pieh, 0, angle1); ///满意人数所占比例 g.FillPie(brush3, piex, piey, piew, pieh, angle1, angle2); //不满意人数所占比例 g.FillPie(brush4, piex, piey, piew, pieh, angle1 + angle2, angle3); //感觉一般人数所占比例 g.DrawRectangle(pen1, 50, 210, 230, 70); //绘制范围框 g.FillRectangle(brush2, 60, 220, 20, 10); //绘制小矩形 g.DrawString("满意总人数比例:" + Convert.ToSingle(Good) * 100 / Convert. To Single(All) + "%", font2, brush2, 90, 220); g.FillRectangle(brush3, 60, 240, 20, 10); g.DrawString("不满意总人数比例:" + Convert.ToSingle(Bad) * 100 / Convert. ToSingle(All) + "%", font2, brush3, 90, 240); g.FillRectangle(brush4, 60, 260, 20, 10); g.DrawString("感觉一般总人数比例:" + Convert.ToSingle(Common) * 100 / Convert. ToSingle(All) + "%", font2, brush4, 90, 260); } catch (Exception md) { Response.Write(md.Message); } System.IO.MemoryStream ms = new System.IO.MemoryStream(); bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); Response.ClearContent(); Response.ContentType = "image/Jpeg"; Response.BinaryWrite(ms.ToArray()); } } 下面再讲述服务调查页的后台代码。 在该页的页面加载事件中先判断用户是否登录,如果没有则跳转到登录页面。绑定 Bind()方法将数据显示在 GridView 控件上。该页 Page_Load 事件代码如下: protected void Page_Load(object sender, EventArgs e) { if (Session["flag"] == null && Session["TypeValues"]==null) { Response. Redirect ("../Login.aspx"); } if (!IsPostBack) { if (Session["TypeValues"].ToString() != "0") { this.gvBind.Columns[4].Visible = false; } this.Bind(); } } 在 Bind()方法中,使用 Operation 类的静态方法 ReDataSet 返回 DataSet 数据集,把它 作为 GridView 的数据源。详细代码如下: public void Bind() { DataSet ds = Operation.ReDataSet("BindResearch"); 330 SQL Server 2005 数据库系统开发案例精选 this.gvBind.DataSource = ds; this.gvBind.DataKeyNames=new string[]{"ID"}; this.gvBind.DataBind(); } 在 GridView 控件中单击【删除】按钮,触发 RowDeleting 事件,在此事件中调用 了 Operation 类的静态方法 ExSql()来执行删除命令。详细代码如下: protected void gvBind_RowDeleting(object sender, GridViewDeleteEventArgs e) {  int ID =int.Parse ( this.gvBind.DataKeys[e.RowIndex].Value.ToString()); Operation.ExSql("DelResearchInfo",ID); this.Bind(); } 由于在数据库中评价信息都是用数字表示(用“0”表示不满意,“1”表示满 意,“2”表示一般),而在显示时不能显示“0”、“1”或者“2”,所以必须把其 转换成相应的汉字。并且在删除数据时应该给出提示信息。选中 GridView 控件,显示 GridView 的事件,然后双击 RowDataBound 事件,在 RowDataBound 事件中编写代码。 代码如下: protected void gvBind_RowDataBound(object sender, GridViewRowEventArgs e) { if (e.Row.RowType == DataControlRowType.DataRow) { string Type=e.Row.Cells[3].Text; switch(Type) { case "0":e.Row.Cells[3].Text="不满意"; break; case "1":e.Row.Cells[3].Text="满意"; break; case "2":e.Row.Cells[3].Text="一般"; break; } ((LinkButton)(e.Row.Cells[4].Controls[0])).Attributes.Add("onclick","return confirm(’你确 定删除吗?’)");  Label l = (Label)e.Row.Cells[4].FindControl("Label1");//找到gvBind控件中的ID为 Lable1的控件  l.Text = l.Text.Substring(0,5) + "⋯";// 只显示Appraise字段的前五个字符及“⋯” } }  代码导读  parse 方法:int.parse()将数字字符串转换为 int 类型的数据。  FindControl 方法:在当前容器中搜索指定 ID 的服务器控件。 Substring 方法:Substring 方法用来截取指定长度的字符串。 7.9.9 反馈信息添加模块 本页是用来处理发布信息的,在普通用户发布信息之后,管理员把处理发布信息的 任务分发给各个工程师。工程师要进入到该页面来处理这些信息。该页设计效果如图 7.25 所示。 331 C H A P T E R 7 第 7 章 企业客户管理系统 图 7.25 反馈信息页面运行效果 1.前台页面设计 主要用到的控件及用途如表 7.15 所示。 表 7.15 指定工程师模块用到的控件 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 3 布局页面 HTML InPut(Reset) 1 重置 标准 Panel 1 实现隐藏/显示分配工程师模块 标准 Button 1 确定指定工程师 标准 Lable 4 显示发布信息 ID/信息标题/发布人/处理工程师 标准 TextBox 2 显示信息内容/反馈信息 数据 GridView 1 显示用户信息表信息 前台页面中主要控件属性设置如下。 (1)Input(Reset) 属性设置:该页面中,用到了一个 Input 控件。Input 控件是客户端控 件,主要是用来重置页面中的控件设置,这里设置了其 Value 值都为“重置”。 (2)Lable 属性设置:该页面中,用到了 4 个 Lable 控件。其 ID 分别为 labID、labTitle、 labUserName 和 labEngineerName。 (3)TextBox 属性设置:该页面中,用到了两个 TextBox 控件,其 ID 属性分别是 txtRecordContent 和 txtReRecordContent,设置它们的 TextMode 属性都为 MultiLine,用来 显示多行文本。 332 SQL Server 2005 数据库系统开发案例精选 该页中用到了 1 个 GridView 控件,其属性设置与节中 GridView 控件的设置大致相同, 将其 ID 属性改为 gvGoodsInfo 并且不添加删除按钮,把选择按钮的 HeaderText 和 SelectText 属性都设置为“回复”。 2.后台功能代码 在该页的页面加载事件中先判断用户是否登录和用户名及用户类型是否为空,只要其 中一个为 null 则跳转到登录页。然后绑定 this.Bind()方法将数据显示在 GridView 控件上。 该页 Page_Load 事件代码如下: protected void Page_Load(object sender, EventArgs e) { if (Session["flag"] == null && Session["UserName"] == null && Session["TypeValues"]==null) { Response. Redirect("../Login.aspx"); } if (Session["TypeValues"].ToString() == "0")//如果用户类型是管理员,则显示“没有要回复的内容” { Response.Write(""); } if (!IsPostBack) { this.Panel1.Visible = false;//隐藏回复信息模块 this.bind(); } } 在 Bind()方法中,调用了 Rever 方法来检索指定了工程师,而且指定工程师的姓名与登录用 户名一致的,且没有反馈信息的发布信息记录。将数据绑定到 GridView 控件上。详细代码如下: public void bind() { string EngineerName = Session["UserName"].ToString(); Operation oper=new Operation(); DataSet ds = oper.Revert(EngineerName); this.gvRevert.DataSource=ds; this.gvRevert.DataKeyNames=new string[]{"RecordID"}; this.gvRevert.DataBind(); } 在 GridView 控件中,单击【回复】按钮时,将触发 GridView 的 SelectedIndexChanging 事件。 在此事件中使用 Records 类对象将选定行记录绑定到 Lable 和 TextBox 控件上。详细代码如下: protected void gvRevert_SelectedIndexChanging(object sender, GridViewSelectEventArgs e) { int RecordID =Convert.ToInt32( this.gvRevert.DataKeys[e.NewSelectedIndex].Value); Operation oper = new Operation(); Records Re = new Records(); if (oper.BindRecords(RecordID,Re)) { this.labID.Text = Re.RecordID.ToString(); this.labTitle.Text = Re.RecordTitle; this.txtRecordContent.Text = Re.RecordDetails; this.labUserName.Text = Re.UserName; this.labEngineerName.Text = Re.EngineerName; } } 单击【确定】按钮时,向信息反馈表插入一条记录。详细代码如下: 333 C H A P T E R 7 第 7 章 企业客户管理系统 protected void btnOK_Click(object sender, EventArgs e) { Operation oper = new Operation();//生成Operation类对象oper ReRecord myre = new ReRecord();//生成ReRecord类对象myre myre.RecordID = this.labID.Text; myre.ReReordContent = this.txtReRecordContent.Text.Trim(); myre.EngineerName = this.labEngineerName.Text; DateTime dt=DateTime.Now; //取得当前系统时间 myre.RevertDate = dt; if (oper.InsertReRecordInfo(myre)) { Response.Write(""); this.bind(); } else { Response.Write(""); } } 在 GridView 控件中实现了分页功能。详细代码如下: protected void gvRevert_PageIndexChanging(object sender, GridViewPageEventArgs e) { this.gvRevert.PageIndex = e.NewPageIndex; this.bind(); } 7.9.10 修改密码模块 本页是用来修改用户密码的,用户进入到该页面后输入旧密码和新密码,只有原密码 正确才能将新密码更新到数据库中。该页运行结果如图 7.26 所示。 图 7.26 修改密码运行效果图 1.前台页面设计 主要用到的控件及用途如表 7.16 所示。 334 SQL Server 2005 数据库系统开发案例精选 表 7.16 修改密码模块用到的控件 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 3 布局页面 HTML InPut(Button) 1 返回到上一页 标准 Button 1 确定修改密码 标准 TextBox 3 录入旧密码/新密码/确认新密码 验证 CompareValidator 1 用于比较两次输入新密码是否一致 验证 RequiredFieldValidator 3 判断 TextBox 的文本是否为空 前台页面中主要控件属性设置如下。 (1)Input 属性设置:该控件是客户端控件,主要是用来返回到上一页,这里设置了其 Value 值为“重置”。如果要实现返回到上一页,还必须定义它的单击事件。双击 Input 按 钮,在它的单击事件中加入“history.go(-1);”这行代码。 (2)TextBox 属性设置:该页面中,用到了 3 个 TextBox 控件,其 ID 分别是 txtOldPassword、txtNewPassword 和 txtAgain,设置它们的 TextMode 属性都为 Password。 (3)RequiredFieldValidator 属性设置:该页面中,用到了 3 个 RequiredFieldValidator 控件,分别用来验证控件 txtOldPassword、txtNewPassword 和 txtAgain 是否为空,它们的 属性设置大致相同,这里以 RequiredFieldValidator1 为例,RequiredFieldValidator1 控件主要 设置了 3 个属性,分别为 ControlToValidate、ErrorMessage 和 Text,其属性值分别为 txtOldPassword、“密码不能为空”和“*”。 (4) CompareValidator 控件属性设置:该页面中,用到了一个该控件用来验证两个 Text Box 的文本内容是否一致,主要设置 3 个属性,分别为 ControlToCompare、ControlToValidate 和 ErrorMessage 属性,对应值分别为 txtNewPassword、txtAgain 和“密码不一致”。 2.后台功能代码 在该页的页面加载事件中,先判断用户是否登录和用户名 ID 是否为空,只要其中一个 为 null 则跳转到登录页。该页 Page_Load 事件代码如下: if (Session["flag"] == null&&Session["UserID"]==null) { Response.Redirect("../Login.aspx"); } 在按规定填写完所有数据后,单击【确定】按钮,触发 Click 事件,在此事件中使用 Session 方法获得用户 ID,再根据用户 ID 更新密码。详细代码如下: protected void btnClickOK_Click(object sender, EventArgs e) { int ID = Convert.ToInt32(Session["UserID"]); string OldPassWord=this.txtOldPassword.Text.Trim(); string NewPassWord = this.txtNewPassword.Text.Trim(); if (Operation.UpdateUsers(ID, OldPassWord, NewPassWord)) { Response.Write(""); } else { Response.Write(""); } } 通过调用 UpdateUsers()方法判 断用户原密码是否正确,如果 正确则修改新密码存入数据库 335 C H A P T E R 7 第 7 章 企业客户管理系统 7.10 疑难问题解析 在本系统中使用了编程的方式实现了动态生成饼图的功能。根据数据库中数据动态生 成图表,可以更直观地将数据分布显示出来,例如显示男女比例、产品销售情况、商品价 格走势等。 下面列出了几种典型图表用代码是怎么实现的(在下面的例中并没有连接数据库,关 于用编程的方式动态生成图表的方法可参考 6.9.8 节)。 从简单的讲起,先看看画直线、矩形和多边形。首先需要引入命名空间 System.Drawing, 用来绘制图形。代码如下: protected void Page_Load(object sender, EventArgs e) { this. GraphicsImage(); } private void GraphicsImage() { int width = 440, hight = 200; Bitmap image = new Bitmap(width, hight); Graphics g = Graphics.FromImage(image); //创建画布 try { g.Clear(Color.White); //设置画布颜色 Font font1 = new Font("新宋体", 12); //设置字体类型和大小 Brush brush = new SolidBrush(Color. Blue); //设置画刷颜色 Pen pen = new Pen(Color. Red,1); //创建画笔对象 g.DrawString("GDI+绘制直线、矩形和多边形", font1, brush, 100, 20); g.DrawLine(pen, 40, 80, 100, 80); //绘制直线 g.DrawRectangle(pen, 130, 60, 100, 40); //绘制矩形 Point[] points = new Point[6]; points[0].X=300;points[0].Y=60; points[1].X=250;points[1].Y=80; points[2].X=300;points[2].Y=100; points[3].X=350;points[3].Y=100; points[4].X=400;points[4].Y=80; points[5].X=350;points[5].Y=60; g.DrawPolygon(pen, points); //绘制多边形 System.IO.MemoryStream ms = new System.IO.MemoryStream(); image.Save(ms, System.Drawing.Imaging.ImageFormat.Gif); Response.ClearContent(); Response.ContentType = "image/Gif";//图片以Gif格式保存 Response.BinaryWrite(ms.ToArray());//在页面上显示图片 } catch(Exception ms) { Response.Write(ms.Message); } } 其运行效果如图 7.27 所示。 使用 6 个点的坐标来确定一个六边形 336 SQL Server 2005 数据库系统开发案例精选 图 7.27 GDI+绘制的直线、矩形和多边型 下面看看画比较复杂的图形如圆形、椭圆和扇形用代码是怎样实现的。代码如下: protected void Page_Load(object sender, EventArgs e) { GraphicsImage(); } private void GraphicsImage() { int width = 400, hight = 250; Bitmap image = new Bitmap(width, hight); Graphics g = Graphics.FromImage(image); //创建画布 try { g.Clear(Color.White); //清空背景色 Font font1 = new Font("新宋体", 12); //设置字体类型和大小 Brush brush = new SolidBrush(Color.Blue); //设置画刷颜色 Pen pen = new Pen(Color.Red, 1); //创建画笔对象 g.DrawString("GDI+绘制圆形、椭圆形和扇形", font1, brush, 80, 20); g.DrawEllipse(pen, 50, 60, 80, 80); //绘制圆形 g.DrawEllipse(pen, 150, 80, 100, 40); //绘制椭圆 g.DrawPie(pen, 270, 60, 100, 100, 180, 130);//绘制扇形 System.IO.MemoryStream ms = new System.IO.MemoryStream(); image.Save(ms, System.Drawing.Imaging.ImageFormat.Gif); Response.ClearContent(); Response.ContentType = "image/Gif";//图片以Gif格式保存 Response.BinaryWrite(ms.ToArray());//在页面上显示图片 } catch (Exception ms) { Response.Write(ms.Message); } } 其运行效果如图 7.28 所示。 图 7.28 GDI+绘制的圆形、椭圆和扇形 7.11 程序调试与错误处理 在本系统中,用到了大量的存储过程。在使用存储过程时,会出现这样或那样的错误, 337 C H A P T E R 7 第 7 章 企业客户管理系统 这些错误有可能是存储过程本身的错误或调用存储过程时出现了错误。由于不能在源程序 中直观的看到存储过程,在使用存储过程之前最好要测试其是否正确。下面就讲讲如何在 程序之外来测试存储过程是否正确。首先,打开 SQL Server 2005 数据库主界面,找到存储 过程所在的数据库,打开该数据库,展开“可编程性”,然后找到要测试的存储过程。选中 该存储过程,单击右键选择“执行存储过程”选项卡。弹出图 7.29 所示的对话框。在对话 框中,列出了存储过程的所有参数。在该参数列表中,在列名为“值”的单元格中输入该 参数对应的值。输出参数是存储过程执行后返回的值。不需要输入值。 图 7.29 执行参数显示框 填写了输入参数后,单击【确定】按钮,弹出图 7.30 所示的对话框。 图 7.30 存储过程运行结果 338 SQL Server 2005 数据库系统开发案例精选 对话框中显示了存储过程执行的结果,如果用户得到了正确的运行结果,就说明该存 储过程是正确的。否则就要修改该存储过程。使用这种方法对改正存储过程中的错误能达 到事半功倍的效果。 8 学生管理系统 开发导读 实例说明  实例名称:学生管理系统。  实例路径:光盘\学生管理系统  实例运行文件:光盘\mingris- oft\学生管理系统\Index\ Default.aspx  用户名:mr。  密码:mrsoft。  用户在使用本实例前,请仔细阅 读光盘中的光盘使用说明、程序 界面修改配置说明书、安装说明 书、使用说明书,这样可以使您 更好地学习和使用本实例。 在计算机中使用本章实例的源程序,用户需安装 Microsoft Visual Studio 2005 或其他网页开发工具。 本实例需要配置 IIS,配置说明详见光盘使用 说明。 本实例数据库为 SQL Server 2005,使用本实例 前,请安装 SQL Server 2005。安装时,验证模式为 混合模式,用户名为 sa,密码为空。 本实例提供了 5 套程序背景和素材,有些格式需 要使用特殊软件处理。 JPG/GIF 文件,如要修改其文件,需要安装 Photoshop 编辑软件。 340 SQL Server 2005 数据库系统开发案例精选 本案例由多个网络程序界面组成,下面仅列出几个典型界面,其他界面请参见光盘中 的源程序。 首页 公告管理页面 发布信息管理页面 学生信息显示页面 添加学生信息页面 添加系信息页面 添加班级信息显示页面 学生详细信息显示页面 341 C H A P T E R 8 第 8 章 学生管理系统 8.1 概 述 学生管理系统主要对学生的个人信息、班级信息、留言信息进行管理。由于学校学生 多,对每个学生的管理单凭人工操作来完成,不仅费时费力,而且还不易管理,所以制作 一个优秀的学生管理系统就可以将繁复的工作变得简单,易管理,大大减轻了学校管理人 员的工作量。本章所要开发的学生管理系统只对比较普遍的那些功能进行介绍,读者可以 结合此实例将功能和界面进行完善与优化,使其符合本校的实际情况。 8.2 系 统 分 析 8.2.1 需求分析 通过调查,要求系统具有以下功能。  由于操作人员的计算机知识普遍较差,要求有良好的人机界面。  管理系统用户,由于该系统的使用对象多,要求有较好的权限管理。  在相应的权限下,删除数据方便简单,数据稳定性好。  数据计算自动完成,尽量减少人工干预。  对学校公告信息进行管理。  对系信息进行添加与删除。  对班级信息进行添加与删除。  对学生基本信息进行管理。  对留言信息进行管理。  对学生信息实现模糊搜索功能。  实现留言及回复功能。 8.2.2 可行性分析  经济性 通过网站对学生信息进行全面的、自动化的管理,大大提高了学校的办公效率。通过 系统对学校运行过程中的数据进行全面记录,避免人为处理各类数据时所产生的各种问题, 并且缩减了学校管理人员的维护成本和维护周期,提高了学校的办公效率。  技术性 网络化的办公管理,使学校管理更加规范。信息维护基本上基于远程登录、远程维护 的方式,实现了对学生信息的便捷化、无纸化管理。 8.3 总 体 设 计 8.3.1 项目规划 学生管理系统是一个典型的数据库开发应用程序,主要由学生基本信息管理、留言信 342 SQL Server 2005 数据库系统开发案例精选 息管理、学生信息搜索及公告管理模块组成,规划系统功能模块如下。  学生基本信息管理模块 该模块由系信息管理模块、班级信息管理模块和学生个人信息管理模块组成。  留言信息管理模块 该模块由留言信息模块、留言信息回复模块及留言信息删除模块组成。  学生信息搜索模块 该模块实现了对学生基本信息的模糊搜索。  公告管理模块 该模块包括发布公告模块及公告信息添加和删除模块。 8.3.2 系统功能结构图 学生管理系统功能结构如图 8.1 所示。 图 8.1 系统功能结构图 8.4 系 统 设 计 8.4.1 设计目标 本系统是针对学校学生管理的要求进行设计的,主要实现如下目标。  系统采用人机对话方式,界面清晰、信息查询灵活、方便、快捷、准确、数据存 储安全可靠。  键盘操作,快速响应。  实现了学生信息的快速保存和搜索。  发布学校公告,和对公告实现添加、删除等操作。  发布留言信息,并对留言信息进行方便地管理。  为了加强数据保密性,为每个用户设置权限级别。  系统最大限度地实现了易安装性、易维护性和易操作性。  系统运行稳定、安全可靠。 8.4.2 开发及运行环境 硬件平台:  CPU:P4 1.8GHz; 普 通 343 C H A P T E R 8 第 8 章 学生管理系统  内存:512MB 以上。 软件平台:  操作系统:Windows XP/ Windows 2000。  数据库:SQL Server 2005。  浏览器:IE 5.0,推荐使用 IE 6.0。  Web 服务器:IIS 5.0。  分辨率:最佳效果 1024×768 像素。 8.5 数据库设计 本系统采用 SQL Server 2005 数据库,系统数据库名称为 db_StudentManager。数据库 db_Student Manager 中包含 7 张表。下面分别给出数据表的实体 E-R 图、主要数据表的结 构、数据表概要说明等。 8.5.1 数据表的实体 E-R 图 根据数据表结构的设计,规划出相应的实体 E-R 图,这些实体中包含各种具体信息, 并通过相互之间的作用形成数据的流动。具体数据表的实体 E-R 图描述如下。 图 8.2 为留言信息实体 E-R 图。 图 8.3 为回复留言信息的实体 E-R 图。  留言人 留言板信息实体 主题 留言时间留言ID 留言内容 回复留言ID 回复内容 回复留言信息实体 回复时间 回复主题 图 8.2 留言信息表的实体 E-R 图 图 8.3 回复留言信息表的实体 E-R 图 8.5.2 主要数据表的结构 由于文章的篇幅所限,笔者在此只给出较为重要的数据表结构,其他数据表请参见本 书附带的光盘。  tb_Student(学生信息表) 学生信息表主要用于保存学生信息。学生信息表结构如表 8.1 所示。 表 8.1 tb_Student 的结构 字 段 名 数 据 类 型 长 度 主 键 否 描 述 StudentID int 4 主键 学生编号(自动编号) ClassID int 4 班级表的外键 Name varchar 50 学生姓名 Age int 4 年龄 留言信息实体 344 SQL Server 2005 数据库系统开发案例精选 续表 字 段 名 数 据 类 型 长 度 主 键 否 描 述 Sex varchar 50 性别 StudyDate datetime 8 入学时间 Address varchar 50 家庭地址 Phone varchar 50 家庭电话 DorPhone varchar 50 宿舍电话 IdCard varchar 50 身份证编号  tb_Info(留言信息表) 留言信息表主要用于保存留言信息。留言信息表结构如表 8.2 所示。 表 8.2 tb_Info 的结构 字 段 名 数 据 类 型 长 度 主 键 否 描 述 ID int 4 主键 留言 ID(自动编号) Title varchar 50 留言标题 Name varchar 50 留言人 Letter varchar 200 留言信息 IssueDate varchar 50 发布日期  tb_AnswerInfo(回复留言信息表) 回复留言信息表主要用于回复留言信息。回复留言信息表结构如表 8.3 所示。 表 8.3 tb_AnswerInfo 的结构 字 段 名 数 据 类 型 长 度 主 键 否 描 述 ID int 4 主键 回复留言 ID(自动增长) AnswerID int 4 留言信息表外键 Name varchar 50 回复人 Letter varchar 50 回复内容 RevertDate datetime 8 回复日期 8.5.3 数据表概要说明 从读者角度出发,为了使读者对本系统后台数据库中数据表有一个清晰的认识,笔者 在此特设计一个数据表树型结构图,该图包含系统所有数据表,如图 8.4 所示。 图 8.4 数据表树型结构图 345 C H A P T E R 8 第 8 章 学生管理系统 8.6 网站总体架构 8.6.1 模块功能介绍 系统主要包括以下功能模块。  用户登录模块:主要用于用户登录管理,登录角色分为管理员和普通会员登录。  学生信息管理模块:主要包括系信息管理、班级信息管理、学生个人信息管理 3 部分。  留言信息管理模块:主要包括发布留言信息、回复留言信息和留言信息删除 3 部分。  公告管理模块:主要包括发布公告和公告管理两部分。 8.6.2 文件夹及文件架构布局 在开发.NET 程序时,首先要创建很多 Web 页、用户控件以及类,来完成基本的功能操作。 不过,在编写代码之前,可以先把网站中可能用到的文件夹创建出来(例如创建一个名为 Image 的文件夹,用于保存网站中需要的图片),这样可以方便以后的开发工作,也可以规范网站的整 体架构。在开发论坛系统前,首先设计图 8.5 所示的文件夹及文件架构图,在开发时只需将相应 文件保存到对应文件夹下即可。 图 8.5 学生管理系统 ASP.NET 页文件夹及文件架构图 8.6.3 文件架构 学生信息管理系统文件架构布局图,如图 8.6 所示。 图 8.6 学生信息管理系统文件架构图 346 SQL Server 2005 数据库系统开发案例精选 8.7 公共模块设计 8.7.1 Web.Config 文件设计 在本网站中,Web.Config 文件主要配置参数是连接数据库的字符串,配置好之后,就省略 了在其他页面一遍又一遍的写连接数据库的字符串。要设置它,需要在 add 标记内编写如下代码: ⋯⋯此处省略 8.7.2 DB(数据库操作)类 公共类的编写可以减少重复代码,并且有利于代码维护。 1.全局变量 全局变量用于保存数据,供页面内和页面间传递数据时使用。声明全局变量的代码如下: //用于保存用户登录时使用的账号 public static string Name = string.Empty; //用于保存用户角色 public static string Role = string.Empty; //搜索学生信息时,保存搜索条件 public static string cmdText = string.Empty; 2.GetCon()方法 GetCon 方法取得 Web.Config 中连接数据库的字符串,返回一个 SqlConnection 对象。 代码如下: public static SqlConnection GetCon() { return new SqlConnection(ConfigurationManager.AppSettings["DNS"]); } 3.ExSql)()方法 ExSql()方法需要获取 SQL 语句即 string 类型字符串,然后连接数据库,对数据库进行 操作之后,再返回到数据库。代码如下: public static bool ExSql(string str) { SqlConnection conn = DB.GetCon();//连接上数据库,并打开了连接 347 C H A P T E R 8 第 8 章 学生管理系统 SqlCommand com = new SqlCommand(str,conn); com.ExecuteNonQuery();//返回受影响的行数 return true; conn.Close();//关闭连接 } 4.ReDs()方法 reDs 方法用于返回一个 DataSet 对象,使用它的时候传入一个 SQL 语句作为参数,根 据参数返回对应的数据集。代码如下: public static DataSet reDs(string str) { SqlConnection conn = DB.GetCon();//连接上数据库,并打开了连接 SqlDataAdapter da = new SqlDataAdapter (str, conn); DataSet ds = new DataSet(); da.Fill(ds); return ds;//返回DataSet对象 } 5.ReDr()方法 reDr 方法返回一个 SqlDataReader 对象,根据输入的参数以 SqlDataReader 对象返回检 索到的符合条件的一组数据。代码如下: public static SqlDataReader reDr(string str) { SqlConnection conn = DB.GetCon(); SqlCommand com = new SqlCommand(str, conn); SqlDataReader dr = com.ExecuteReader(); return dr;//返回SqlDataReader对象dr conn.Close();//关闭连接 } 8.7.3 网站样式、外观和主题 本网站使用了样式、外观和主题来定义网站的“风格”,它们为显示网站的属性和信息 提供了方法。可以节省重复性的格式及样式的设定,还可以统一网站的风格。使用样式、 外观和主题可以很方便地修改网站的所有页面或整个 Web 应用程序的界面。 主题定义了一组属性,这些属性又定义了网站页面 和 Web 服务器控件的外观。本网站使用的主题包含了样 式表(文件 StyleSheet.css)和外观文件(StyleSheet.skin)。 主题默认放在网站系统文件夹 App_Themes 中,在此文 件夹下,把网站的各个主题按子文件夹的形式存放, 如图 8.7 所示。 在 Default 主题文件夹下建立样式表 StyleSheet.Css 和 外观 SkinFile.skin 文件。关于它们的描述请参考源程序。 建立主题之后,就可以在页面中使用该主题了。 注意在一个页面中只能应用一个主题,例如在本网站 首页使用该主题的 HTML 代码为: 图 8.7 主题文件夹 348 SQL Server 2005 数据库系统开发案例精选 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" StylesheetTheme="Default" %> 8.7.4 用户控件设计 创建 Web 用户控件主要是方便重复使用及修改,当某个模块要被多次用到时,可以把 这个模块创建成 Web 用户控件。在本系统中主要使用了用于实现用户登录、学生信息搜索、 网站 Banner、管理员及普通用户控制面板。设计效果如图 8.8~图 8.12 所示。 图 8.8 用户登录模块 图 8.9 学生信息搜索模块 图 8.10 网站 banner 图 8.11 管理页控制面板 图 8.12 普通会员控制面板 1.用户登录模块设计 系统登录模块用于验证用户登录系统时输入的用户名和密码,只有合法的用户才可以 进入系统。 该模块中主要使用的控件及控件用途如表 8.4 所示。 表 8.4 系统登录模块控件列表 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 1 布局页面 HTML Input(Reset) 1 重置 349 C H A P T E R 8 第 8 章 学生管理系统 续表 控 件 类 型 控 件 名 称 数 量 用 途 标准 Lable 1 显示登录提示信息 标准 TextBox 2 输入用户名/密码 标准 Button 1 提交输入信息 标准 CheckBox 1 选择登录身份 标准 PlaceHolder 1 在运行时动态添加用户控件 验证 RequiredFieldValidator 2 验证输入条件 前台页面中主要控件属性设置如下。 (1)Lable 控件属性设置:该页面中用到了一个 Lable 控件,当用户没有登录时,显示 登录提示信息。这里设置其 Text 属性为“学生登录请使用你的姓名和身份证号码的后 4 位 登录”,Visible 属性为 False。 (2)TextBox 控件属性设置:该页面中用到了两个 TextBox 控件,其中输入用户名和 输入密码的 TextBox 控件的 ID 属性分别为 txtUserName、txtPassword。设置 ID 属性为 txtPassword 的 TextBox 控件的 TextMode 属性为 PassWord。 (3)CheckBox 控件属性设置:页面中的 CheckBox 控件主要用来选择用户身份,当 CheckBox 的 Checked 属性为 true 时,用户登录身份为管理员。否则默认为普通用户登录。 其 ID 及 Text 属性分别为 CheckBox1 和管理员登录。 (4)PlaceHolder 控件属性设置:该页面中用到了 PlaceHolder 控件来动态向用户登录 模块加载用户控件。其 ID 属性为 PlaceHolder1。 (5)RequiredFieldValidator 控件属性设置:该页面中用到了两个 RequiredFieldValidator 控件,分别用来验证控件 txtUserName 和控件 txtPwd 是否为空,由于这两个控件属性设置 基本相同,这里以 RequiredFieldValidator1 为例。RequiredFieldValidator1 控件主要设置了 3 个属性,即 ControlToValidate、ErrorMessage 和 Text 属性,其属性值分别为 txtUserName、 “用户名不能为空”和“*”。 该用户控件的后台代码如下。 首先引入命名空间 using System.Data.SqlClient; 在该页的页面加载事件中判断用户是否登录,再根据用户类型利用 PlaceHolder 控件加 载不同的用户控制模板。该页 Page_Load 事件代码如下: protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { if (Session["flag"] != null)//先判断用户是否登录 { //如果管理员已经登录,使用PlaceHokder控件来加载管理员控制面板 if (DB.Role == "管理员") { //隐藏用户登录页面,加载管理员控制面板 this.TABLE1.Visible = false; Control myControl = Page.LoadControl("Controls/AdminPanel.ascx"); PlaceHolder1.Controls.Add(myControl); } //如果是普通会员登录,使用PlaceHokder控件来加载普通会员控制面板 if (DB.Role == "普通会员") 隐藏用户登录页面, 加载管理员控制面板 350 SQL Server 2005 数据库系统开发案例精选 { //隐藏用户登录页面,加载普通会员控制面板 this.TABLE1.Visible = false; Control myControl = Page.LoadControl("Controls/MemberPanel.ascx"); PlaceHolder1.Controls.Add(myControl); } } //当用户没有登录时,显示登录提示信息 this.Label1.Visible = true; } } 用户输入完相关信息,并选择登录身份后,单击【确定】按钮,系统验证用户名密码 是否合法,如果用户名和密码合法,用户将成功进入系统。详细代码如下: protected void btnLogin_Click(object sender, EventArgs e) { //当CheckBox1的Checked属性为true时,表示管理员登录。否则为普通会员登录 if (this.CheckBox1.Checked) { SqlConnection con = DB.GetCon(); con.Open(); string cmdText="select * from tb_UserInfo where UserName=’" + this.txtUsername.Text. Trim() + "’"; cmdText+="and Password=’" + this.txtpwd.Text.Trim() + "’"; SqlCommand com = new SqlCommand(cmdText, con); SqlDataReader sdr = com.ExecuteReader(); //判断该用户是否存在,如果存在则记录下用户信息及加载管理员控制面板  if (sdr.HasRows) {  Session["flag"] =true; //标记登录成功 //使用全局变量Role记录用户的登录角色 DB.Role= "管理员"; //使用全局变量Name记录用户的登录角色 DB.Name = this.txtUsername.Text.ToString(); Session["UserName"] = this.txtUsername.ToString(); //隐藏登录界面 this.TABLE1.Visible = false; Control myControl = Page.LoadControl("Controls/AdminPanel.ascx"); PlaceHolder1.Controls.Add(myControl); } else {  Response.Write(""); } } else { SqlConnection con = DB.GetCon(); con.Open(); string cmdText="select * from tb_Student where Name=’" + this.txtUsername.Text.Trim() + "’"; cmdText += "and substring(IdCard,15,18)=’" + this.txtpwd.Text.Trim() + "’"; SqlCommand com = new SqlCommand( cmdText,con); SqlDataReader sdr = com.ExecuteReader(); if (sdr.HasRows) { Session["flag"] =true; 隐藏用户登录页面,加 载普通会员控制面板 判断该用户是否存在,如果存在则记 录下用户信息及加载管理员控制面板 判断该用户是否存在,如果存在则记 录用户信息及加载普通用户控制面板 351 C H A P T E R 8 第 8 章 学生管理系统 Session["Role"] = "普通会员"; DB.Role = "普通会员"; DB.Name=this.txtUsername.ToString(); Session["UserName"] = this.txtUsername.Text.ToString(); this.TABLE1.Visible = false; Control myControl = Page.LoadControl("Controls/MemberPanel.ascx"); PlaceHolder1.Controls.Add(myControl); } else { Response.Write(""); } } }  链接 管理员控制面板(MemberPanel.ascx)和普通会员控制面板(MemberPanel.ascx)主 要用于链接到其他功能页面。详细代码请参阅本书附赠光盘。 技术细节 在用户控件中,使用了 PlaceHolder 控件,PlaceHolder 控件本身不能输出任何东西, 仅用作 Web 页上其他控件的容器,该控件的语法格式如下。 通过调用 PlaceHolder 控件的 Add 方法可以将其他的控件添加到 PlaceHolder 控件, 成为其子控件。 下面的代码演示了如何使用 PlaceHolder 控件。 Control myControl = Page.LoadControl("Controls/AdminPanel.ascx"); PlaceHolder1.Controls.Add(myControl); 在上面的代码中首先使用 Page.LoadControl()方法取得 AdminPanel.ascx 用户控件(该 方法的参数是用户控件在服务器上的相对地址)。然后使用 Add 方法将 AdminPanel.ascx 用户控件添加到 PlaceHolder 控件中。  代码导读  HasRows 方法:使用该方法判断 SqlDataReader 结果集中是否有记录。  Session 变量:Session 对象可以存储特定的用户会话所需的信息。当用户在应用程 序的不同页面之间切换时,存储在 Session 对象中的变量不被清除。其主要用于在给定的 应用程序中所有用户之间共享信息,并在服务器运行期间持久地保存数据。当一个用户第 一次访问站点中的 ASP 文件时,将为其创建一个 Session 对象,并一直保存到用户连接超 时或中断连接时,才释放该 Session 对象。 Response.write 方法:用于向页面输出一个字符数组。 2.学生信息搜索模块设计 学生信息搜索模块用于搜索学生信息,可以根据学生的姓名、班级及性别等基本信息 进行模糊搜索。 该模块中主要使用的控件及控件用途如表 8.5 所示。 352 SQL Server 2005 数据库系统开发案例精选 表 8.5 学生信息搜索模块控件列表 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 1 布局页面 标准 TextBox 2 输入用户名/密码 标准 Button 1 提交查询信息 标准 DropDownList 2 选择系名/班级 前台页面中主要控件属性设置如下。 (1)TextBox 控件属性设置:该页面中用到了两个 TextBox 控件,其中要输入用户名 和输入密码的 TextBox 控件的 ID 属性分别为 txtUserName、txtPassword。设置 ID 属性为 txtPassword 的 TextBox 控件的 TextMode 属性为 PassWord。 (2)DropDownList 控件属性设置:该页面中用到了两个 DropDownList 控件来供用户 选择系名和班级名,在本页实现了这两个 DropDownList 控件的联动。其 ID 属性分别为 ddlDepartment 和 ddlClass。其中 ID 属性为 ddlDepartment 的 DropDownList 控件的 AutoPostBack 属性为 True。 该用户控件的后台代码如下。 在该页的页面加载事件中,将系名绑定到 ID 为 ddlDepartment 的 DropDownList 控件 上。该页 Page_Load 事件代码如下: protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { //绑定ID属性为ddlDepartment的DropDownList控件 DataSet ds1 = DB.reDs("select Name from tb_Department "); this.ddlDepartment.DataSource = ds1; this.ddlDepartment.DataTextField = "Name"; this.ddlDepartment.DataBind(); } } 单击【搜索】按钮时,将搜索条件保存到全局变量 cmdText 上,然后跳转到搜索页, 将搜索到的信息显示在该页面上。详细代码如下: protected void btnSearch_Click(object sender, EventArgs e) { int flag = 0;//判断变量,判断该用户是否第一次输入搜索条件 string Sqlstr = ""; if (this.ddlDepartment.SelectedValue != "-全部-") { if (flag == 0) { Sqlstr = Sqlstr + " where " + "B.Department=’" + this.ddlDepartment.SelectedValue.ToString() + "’"; } else { Sqlstr = Sqlstr + " and " + "B.Department=’" + this.ddlDepartment.SelectedValue.ToString() + "’"; } flag = 1; } if (this.ddlClass.SelectedValue != "-全部-") { 当 flag 为零时表示第一 次输入,在搜索条件前 加上关键字 where,否 则加上关键字 and,然 后把 flag 置为 1 353 C H A P T E R 8 第 8 章 学生管理系统 if (flag == 0) { Sqlstr = Sqlstr + " where " + "B.Name=’" + this.ddlClass.SelectedValue.ToString() + "’"; } else { Sqlstr = Sqlstr + " and " + "B.Name=’" + this.ddlClass.SelectedValue.ToString() + "’"; } flag = 1; } if (this.txtkeyword.Text != "") { string keyword = this.txtkeyword.Text.Trim(); if (flag == 0) { Sqlstr = Sqlstr + " where " + "A.Name like ’%" + keyword + "%’" + " or "; Sqlstr+="" + "A.Sex like ’%" + keyword + "%’" + "or" + " A.StudentID like ’%" + keyword + "%’"; } else { Sqlstr = Sqlstr + " and " + "A.Name like ’%" + keyword + "%’" + " or "; Sqlstr+="" + " A.Sex like ’%" + keyword + "%’" + "or" + " A.StudentID like ’%" + keyword + "%’"; } flag = 1; } //使用DB类中的cmdText字段来保存搜索条件 DB.cmdText = "select * from tb_Student as A inner join tb_Class as B on A.ClassID=B.ClassID" + Sqlstr; //跳转到搜索页,显示搜索信息 Response.Redirect("Pages/Search/Search.aspx"); } 当用户使用DropDownList控件选择不同的系时,将DropDownList控件的AutoPostBack 属性设置为 True。当该控件的选定项改变时,触发该控件的 SelectedIndexChanged 事件。 在该事件中编写代码实现用户选择不同的系时,筛选出与该系对应的班级。详细代码 如下: protected void ddlDepartment_SelectedIndexChanged(object sender, EventArgs e) { //清空ID属性为ddlClass控件的子项 ddlClass.Items.Clear(); //在ID属性为ddlDepartment控件中选择不同的系时,根据该系筛选出对应的班级显示在ID 属性为ddlClass的控件中 if (ddlDepartment.SelectedValue != "-全部-") { DataSet ds = DB.reDs("select Name from tb_Class where Department=’" + ddlDepartment. Selected Value + "’"); this.ddlClass.DataSource = ds; this.ddlClass.DataTextField = "Name"; this.ddlClass.DataBind(); } else { ddlClass.Items.Add(new ListItem("-全部-")); } } 354 SQL Server 2005 数据库系统开发案例精选 8.8 网 站 开 发 8.8.1 网站首页设计 网站首页包括用户登录、学生信息搜索、显示公告信息及显示最新留言等 4 部分。其 中用户登录及学生信息搜索模块是用户控件组成的。首页运行效果如图 8.13 所示。 图 8.13 首页运行效果图 1.前台页面设计 首页中主要使用的控件及控件用途如表 8.6 所示。 表 8.6 首页控件列表 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 3 布局页面 数据 DataList 2 显示公告/最新的留言信息 前台页面中主要使用的控件是 DataList,该页面中使用了两个 DataList 控件,ID 属性分别 为 DataList1 和 DataList2,其中 DataList1 用来显示公告,DataList2 用来显示最新的 5 条留言 信息。由于 DataList2 的功能比较复杂,这里仅以 DataList1 为例讲解 DataList 的使用方法。 用户从 Visual Studio 2005 工具箱的“数据”栏中拖曳出 DataList 控件放置到页面中, 单击其右上角的“ ”图标按钮,在快捷菜单(如图 8.14)中选择“编辑模板”或是右键 单击 DataList,选择快捷菜单中“编辑模板”中“项模板(ItemTemplate)”,即可在 DataList 的项模板(ItemTemplate)中进行编辑。本页面中 DataList 控件项模板编辑如图 8.15 所示。 DataList2 控件项模板中用到的控件如表 8.7 所示。 355 C H A P T E R 8 第 8 章 学生管理系统 图 8.14 DataList 快捷菜单 图 8.15 DataList2 项模板布局 表 8.7 DataList 项模板布局控件列表 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 1 布局页面 标准 Lable 1 显示留言人姓名 标准 LinkButton 2 显示留言信息 表 8.7 中主要控件属性设置如下。 (1)Label 控件属性设置:DataList 控件中的 Label 控件是用来绑定数据库中相关字段, 并显示相关数据信息的。DataList 控件中用到了一个 Lable 控件,该控件的 ID 属性为 labName。其绑定字段代码如下: ’ >’> (2)LinkButton 控件属性设置:DataList 控件中的 LinkButton 控件实现了绑定数据库 中相关字段和单击跳转到目标页的功能。例如设置 LinkButton 控件的 Text 属性就可以绑定 数据库中相关字段。把 LinkButton 控件的 CommandName 设置为 select,当单击 LinkButton 时将触发 DataList 控件的 ItemCommand 事件。在此事件中可以编写跳转页面的代码。 2.后台功能代码 在该页的页面加载事件中判断用户是否登录,然后根据用户类型利用 PlaceHolder 控件 加载不同的用户控制模板。该页 Page_Load 事件代码如下: protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { DataSet ds1 = DB.reDs("select * from tb_Inform order by IssueDate Desc"); this.DataList1.DataSource = ds1; this.DataList1.DataBind(); DataSet ds2 = DB.reDs("Select * from tb_Info order by issueDate Desc"); this.DataList2.DataSource = ds2; this.DataList2.DataKeyField = "ID"; this.DataList2.DataBind(); } } 在 DataList2 绑定数据源时将触发其 ItemDataBind 事件,在此事件中规定了留言信息 显示的格式。详细代码如下: protected void DataList2_ItemDataBound(object sender, DataListItemEventArgs e) { //取得ID属性为lnkbtnMessage的LinkButton控件的对象li  LinkButton li = (LinkButton)e.Item.FindControl("lnkbtnMessage"); //如果li的文本值的长度大于5时,只显示前五个字符,其余用省略号代替 if (li.Text.Length > 5) { li.Text = li.Text.Substring(0, 5) + "⋯"; } } 356 SQL Server 2005 数据库系统开发案例精选 单击 DataList2 中 ID 属性为 lnkbtnMessage 的 LinkButton 控件时,触发 DataList 控件 的 ItemCommand 事件,在此事件中取得该行记录的主键值,并跳转到留言信息回复页上。 详细代码如下: protected void DataList2_ItemCommand(object source, DataListCommandEventArgs e) { //取得该行的主键值 int ID = int.Parse(this.DataList1.DataKeys[e.Item.ItemIndex].ToString()); //跳转到Answer.aspx页  Response.Redirect("~/Pages/Message/Answer.aspx?ID=" + ID); }  代码导读  findControl 方法:在当前的命名容器中搜索指定的服务器控件。  Response.Redirect 方法:实现从当前页跳转到目标页。 技术细节 在使用 DataList 控件显示数据时,我们用到了 DataBinder.Eval()方法来绑定数据源中 的某一个字段。DataBinder.Eval()方法具有 3 个参数。表示格式如下。 <%# DataBinder.Eval(Container.DataItem,"字段名","{0:d}")%> 也可以写成这样: <%# DataBinder.Eval(Container," DataItem.字段名","{0:d}")%>它们是等价的 这 3 个参数分别是数据项的命名容器、数据字段名和格式字符串。其中第 3 个参数可 以不提供。只有当需要格式转换时才使用它。例如用户需要把数据库中长日期格式转换成 短日期格式时,才需要使用它。 8.8.2 学生基本信息显示模块 学生信息显示模块显示了搜索模块搜索到的学生基本信息。基本信息显示模块运行效 果如图 8.16 所示。 图 8.16 学生基本信息显示模块运行效果 357 C H A P T E R 8 第 8 章 学生管理系统 1.前台页面设计 该页面中主要使用的控件及控件用途如表 8.8 所示。 表 8.8 学生基本信息显示模块控件列表 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 1 布局页面 标准 Lable 2 显示当前页数/总页数 标准 LinkButton 2 显示上一页/下一页 标准 PlaceHolder 1 输入用户名/密码 数据 DataList 1 提交输入信息 前台页面中主要控件属性设置如下。 (1)Lable 属性设置:该页面中,在 DataList 外部主要用到了两个 Label 控件,其 ID 属性分别为 labCount 和 labNowPage,两个控件属性设置基本相同,它们的 ForeColor 属性 设置都为 Red,只是 labNowPage 控件的 Text 属性初始值为 1。 (2)LinkButton 属性设置:该页面中,在 DataList 外部主要用到了两个 LinkButton 控 件,其 ID 属性分别为 lnkbtnFront 和 lnkbtnNext,这两个控件的 ForeColor 属性设置都为 Black,Text 属性值分别为“上一页”和“下一页”。 (3)PlaceHolder 控件属性设置:该页面中用到了 PlaceHolder 控件来动态向用户登录 模块加载用户控件。其 ID 属性为 PlaceHolder1。 (4)DataList 控件属性设置:在该 DataList 控件的项模板中使用了 3 个 Lable 控件和一 个 LinkButton 控件,分别用来显示学生 ID、姓名、性别和入学时间。其中设置 LinkButton 控件的 CommandName 属性为 select。关于在 DataList 控件中绑定数据的方法可参考 7.8.1 节。 2.后台功能代码 在该页的页面加载事件中根据用户登录状态来加载不同的用户控件。该页 Page_Load 事件代码如下: protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { //判断该用户是否登录 if (DB.Role != "") { //如果登录角色为管理员,则利用PlaceHolder控件加载管理员控制面板 if (DB.Role == "管理员") { Control myControl = Page.LoadControl("~/Controls/AdminPanel.ascx"); PlaceHolder1.Controls.Add(myControl); } //如果登录角色为普通会员,则利用PlaceHolder控件加载普通会员控制面板 if (DB.Role == "普通会员") { Control myControl = Page.LoadControl("~/Controls/MemberPanel.ascx"); PlaceHolder1.Controls.Add(myControl); } } 358 SQL Server 2005 数据库系统开发案例精选 else//没有登录则加载用户登录模块 { Control myControl = Page.LoadControl("~/Controls/Login.ascx"); PlaceHolder1.Controls.Add(myControl); } this.bind();//绑定ID为DataList1的DataList控件 } } bind()方法将符合搜索条件的记录显示在 DataList 控件上,并实现了分页功能。详细代 码如下: public void bind() { //获取当前页数 int CurrentPage = Convert.ToInt32(labNowPage.Text); PagedDataSource ps = new PagedDataSource(); DataSet ds = DB.reDs(DB.cmdText); //判断当前页的URL是否为学生信息显示页 if (Request.RawUrl == "/Search/Search.aspx") { this.DataList1.Visible = false;//隐藏DataList控件 this.labErrorMessage.Visible = true; //显示提示用户没有搜索到结果的信息 } else//如果不是学生信息显示页,则返回到原始请求页面 { Response.Write(""); } ps.DataSource = ds.Tables[0].DefaultView; ps.AllowPaging = true; ps.PageSize = 4; ps.CurrentPageIndex = CurrentPage - 1; //取得当前页的页码 lnkbtnFront.Enabled = true; lnkbtnNext.Enabled = true; if (CurrentPage == 1) { lnkbtnFront.Enabled = false;//不显示上一页按钮 } if (CurrentPage == ps.PageCount) { lnkbtnNext.Enabled = false;//不显示下一页 } this.labCount.Text = Convert.ToString(ps.PageCount); this.DataList1.DataSource = ps; this.DataList1.DataKeyField = "StudentID"; this.DataList1.DataBind(); } 控制 DataList 控件翻页主要用到 LinkButton 控件。详细代码如下: //上一页 protected void lnkbtnPrve_Click(object sender, EventArgs e) { this.labNowPage.Text = Convert.ToString(Convert.ToInt32(this.labNowPage.Text) - 1); this.bind(); } 当前页为第一页 当前页为最后一页 单击【上一页】 按钮时,把当前 页文本值减 1 得 到当前页文本值 使用 PagedDataSource 类实现 DataList 控件的分页功能 359 C H A P T E R 8 第 8 章 学生管理系统 //下一页 protected void lnkbtnNext_Click(object sender, EventArgs e) { this.labNowPage.Text = Convert.ToString(Convert.ToInt32(this.labNowPage.Text) + 1); this.bind(); } 当单击 DataLis1 中 ID 属性为 lnkbtnTit 的 LinkButton 控件时,将触发 DataList1 的 ItemCommand 事件,在此事件中使用 Redirect 方法跳转到 RecordDetails.aspx,并且向该页 面传一个发布信息 ID 的值。详细代码如下: protected void DataList1_ItemCommand(object source, DataListCommandEventArgs e) { int StudentID = Convert.ToInt32(DataList1.DataKeys[e.Item.ItemIndex]); Response.Redirect("StudentDetails.aspx? StudentID =" + StudentID + ""); } 技术细节 使用 DataList 控件实现分页时,由于 DataList 控件本身不带与分页相关的属性。不能 像在 GridView 控件中利用其本身的分页属性比较简单的实现分页功能。 在 DataList 中,通过 PageDataSource 类来实现分页功能。该类封装了 DataGrid 控件 的分页属性。下面演示该类的用法。 PagedDataSource ps = new PagedDataSource();//实例化 PagedDataSource 类 DataSet ds = DB.reDs(DB.cmdText);//生成数据集 ps.DataSource = ds.Tables[0].DefaultView;//获取绑定 DataList 的数据源 ps.AllowPaging = true; //是否可以分页 ps.PageSize = 4; //显示的数量 8.8.3 学生详细信息显示模块 详细信息显示页主要用于显示学生详细信息,如图 8.17 所示。 图 8.17 详细信息显示页运行效果 单击【下一页】按钮时,把当前 页文本值加 1 得到当前页文本值 360 SQL Server 2005 数据库系统开发案例精选 当使用 GridView 控件来显示某个表的数据时,会遇到由于表的字段太多或者某个字段 内容太长的情况。这样如果绑定所有的字段会使 GridView 变得很长,不利于页面布局。一 般的解决方法是在 GridView 控件中加一个超链接按钮,单击它时就跳转到显示这条记录的 详细信息的页面上。 1.前台页面设计 学生详细信息显示页面中主要使用的控件及控件用途如表 8.9 所示。 表 8.9 详细信息显示页面中主要使用控件及控件用途 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 1 布局页面 HTML Input(Button) 1 返回到上一页 标准 Lable 4 显示数据 标准 TextBox 6 显示数据 前台页面中主要控件属性设置如下。 (1)Input 控件是客户端控件,主要用来返回到上一页,这里设置其 Value 值为“重置”。 它要实现返回到上一页,还必须定义它的事件。双击 Input 按钮,在它的事件过程中加入 “history.go(-1);”这行代码。 (2)在本页中用到的 TextBox 控件,主要用于显示学生信息的详细信息。其中把显示 家庭地址字段的 TextBox 控件的 TextMode 属性设置为 MultiLine,以显示多行文本。 2.后台功能代码 在命名空间区域中,引用 using System.Data.SqlClient 命名空间。 在 Page_Load 页装载事件中,实现了用 Request 方法接收到发布信息 ID 的值。通过 ID 检索到该记录,然后将该记录的详细内容显示在页面上。代码如下: protected void Page_Load(object sender, EventArgs e) { if (DB.Role != "") { //如果登录角色为管理员,则利用PlaceHolder控件加载管理员控制面板 if (DB.Role == "管理员") { Control myControl = Page.LoadControl("~/Controls/AdminPanel.ascx"); PlaceHolder1.Controls.Add(myControl); } //如果登录角色为普通会员,则利用PlaceHolder控件加载普通会员控制面板 if (DB.Role == "普通会员") { Control myControl = Page.LoadControl("~/Controls/MemberPanel.ascx"); PlaceHolder1.Controls.Add(myControl); } } else//没有登录则加载用户登录模块 { Control myControl = Page.LoadControl("~/Controls/Login.ascx"); PlaceHolder1.Controls.Add(myControl); } int StudentID =int.Parse(Request["StudentID"].ToString()); 361 C H A P T E R 8 第 8 章 学生管理系统 SqlDataReader sdr = DB.reDr("select * from tb_Student where StudentID="+StudentID); string cmdText = "select A.Name From tb_Class As A inner join tb_Student As B "; cmdText += "ON A.ClassID=B.ClassID where B.StudentID=" + StudentID; SqlDataReader sdr1 = DB.reDr(cmdText); sdr.Read(); sdr1.Read(); this.labID.Text = Request["StudentID"].ToString(); this.labName.Text =sdr["Name"].ToString(); this.txtClass.Text = sdr1["Name"].ToString(); this.labSex.Text = sdr["Sex"].ToString(); this.txtAge.Text = sdr["Age"].ToString(); this.txtPhone.Text=sdr["Phone"].ToString(); this.txtIdCard.Text = sdr["IdCard"].ToString(); ; this.txtDorPhone.Text=sdr["DorPhone"].ToString(); this.txtAddress.Text=sdr["Address"].ToString(); DateTime dt; dt = DateTime.Parse(sdr["StudyDate"].ToString()); this.labStudyDate.Text =dt.ToShortDateString(); } 8.8.4 留言信息模块设计 留言信息模块主要分为留言信息显示和发布留言两部分,当用户登录后才能发布留言。 当管理员进入该页面时,可以对留言信息进行删除操作。留言信息页的运行效果如图 8.18 所示。 图 8.18 留言信息页面运行效果 将 SqlDataReader 对象中的记 录绑定到控件上并显示出来 362 SQL Server 2005 数据库系统开发案例精选 1.前台页面设计 该模块中主要使用的控件及控件用途如表 8.10 所示。 表 8.10 留言信息模块中的控件 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 1 布局页面 HTML Input(Reset) 1 重置 标准 TextBox 2 输入留言主题/留言内容 标准 Button 1 提交输入信息 标准 CheckBox 1 选择登录身份 验证 RequiredFieldValidator 2 验证留言主题和留言内容 是否为空 数据 DataList 1 显示留言信息 前台页面中主要控件属性设置如下。 (1)Input(Reset)控件是客户端控件,主要是用来重置页面中的控件设置,这里设置其 Value 值为“重置”。 (2)页面中用到了两个 TextBox 控件,其中输入留言主题和输入留言内容的 TextBox 控件的 ID 属性分别为 txtTitle、txtLetter。设置 ID 属性为 txtLetter 的 TextBox 控件的 TextMode 属性为 MultiLine。 (3)页面中用到了两个 RequiredFieldValidator 控件,分别用来验证控件 txtTitle 和控件 txtLetter 是否为空,由于这两个控件属性设置基本相同,这里仅以 RequiredFieldValidator1 为例。RequiredFieldValidator1 控件主要设置了三个属性:ControlToValidate、ErrorMessage 和 Text,其属性值分别为 txtTitle、“用户名不能为空”和“*”。 (4)页面中使用 DataList 控件显示留言信息。该控件的 ID 属性为 DataList1,在 DataList1 的模板中主要使用的控件及控件用途如表 8.11 所示。 表 8.11 DataList 中的控件 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 1 布局页面 标准 Lable 2 显示留言人/留言时间 标准 LinkButton 2 分别显示留言主题并实现页 面跳转功能和实现删除功能 标准 CheckBox 1 判断该条记录是否被选中 删除 前台页面中主要控件属性设置如下。 (1)在 DataList 的项模板中主要用到了两个 Label 控件,其 ID 属性分别为 labUserName 和 labTime,分别显示留言人姓名和留言时间。在 HTML 中绑定字段代码如下: ’> ’> (2)在 DataList 项模板和页脚模板中各用到了一个 LinkButton 控件,其 ID 属性分别 为 lnkbtnTitle 和 lnkbtnDetele,把 lnkbtnDetele 的 Command 属性设置为 Delete,当单击该按 363 C H A P T E R 8 第 8 章 学生管理系统 钮时将触发 DataList 的 DeteleCommand 事件。LnkbtnTitle 用来显示留言标题内容,这里把 Command 属性设置为 Edit。其 HTML 代码如下: ’ CommandName="Edit" CausesValidation="False" > (3)在 DataList 项模板中使用 CheckBox 控件来标记该行记录是否要删除,这里设置 该控件的 Text 属性为“删除”。如果该控件的 Checked 属性为 True,则单击 DataList 页脚 模板中的【删除】按钮时将删除该行记录。 2.后台功能代码 在该页的页面加载事件中绑定了 DataList 控件,显示已发布的留言信息。该页 Page_Load 事件代码如下: protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { Bind(); } } Bind()方法将留言信息绑定到 DataList 控件显示在页面上。详细代码如下: public void Bind() { SqlDataReader sdr = DB.reDr("select * from tb_Info "); this.DataList1.DataSource = sdr; //设置该DataList主键 this.DataList1.DataKeyField = "ID"; this.DataList1.DataBind(); } 单击 ID 属性为 lnkbtnTitle 的 LinkButton 按钮,触发 DataList1 的 EditCommand 事件, 在此事件中编写如下代码: protected void DataList1_EditCommand(object source, DataListCommandEventArgs e) { //获取该条记录的主键,跳转到Answer.aspx,并把主键值传到Answer.aspx上 int ID = Convert.ToInt32(DataList1.DataKeys[e.Item.ItemIndex]); Response.Redirect("Answer.aspx?ID=" + ID); } 在 DataList1 创建项时,将触发 DataList1 的 ItemCreate 事件,在此事件中根据用户登 录身份决定是否隐藏该页中删除留言的功能。详细代码如下: protected void DataList1_ItemCreated(object sender, DataListItemEventArgs e) { //在DataList创建项时判断当前用户是否是管理员 if (DB.Role != "管理员") { //如果不是则隐藏DataList1的页脚和项模板中的CheckBox  this.DataList1.ShowFooter = false;  for (int i = 0; i <=DataList1.Items.Count-1; i++) { CheckBox cb = (CheckBox)DataList1.Items[i].FindControl("CheckBox1"); cb.Visible = false; } } } 364 SQL Server 2005 数据库系统开发案例精选 单击 ID 属性为 lnkbtnDelete 的 LinkButton 控件,将触发 DataList1 的 DeleteCammand 事件,在此事件中实现删除选中行记录的功能。详细代码如下: protected void DataList1_DeleteCommand(object source, DataListCommandEventArgs e) { //遍历DataList中所有行,把选中了CheckBox控件的行从数据库中删除 for (int i = 0; i <=DataList1.Items.Count-1; i++) { CheckBox cb = (CheckBox)DataList1.Items[i].FindControl("CheckBox1"); if (cb.Checked == true) { string sqlstr = "delete from tb_Info where id=’" + DataList1.DataKeys[i].ToString() + "’"; DB.ExSql(sqlstr); } } //重新绑定DataList1 Bind(); } 当用户单击【提交】按钮时,将留言信息插入到数据库中。详细代码如下: protected void btn_cilckok_Click(object sender, EventArgs e) { if (Session["UserName"] == null) { Response.Write(""); } else {  DateTime dt = DateTime.Now;//取得系统时间 try { //判断留言内容是否超过200字 if (this.txtLetter.Text.Length < 200) { //用Session["userName"]取得用户名 string cmdText = "insert into tb_Info values(’" + this.txtTitle.Text.Trim() + "’,’" + Session["UserName"].ToString() + "’,"; cmdText += "’" + this.txtLetter.Text.Trim() + "’,’" + dt.ToShortDateString() + "’)"; DB.ExSql(cmdText); Response.Write(""); //重新绑定DataList1 Bind(); //清空TextBox this.txtTitle.Text = ""; this.txtLetter.Text = ""; } else { Response.Write(""); } } catch { Response.Write(""); } } } 通过 Session["UserName"来 判断当前用户是否已经登录 365 C H A P T E R 8 第 8 章 学生管理系统  代码导读  ShowFooter 方法:该方法获取一个值,指示是否显示 DataList 的注脚部分。  Count 函数:对象通过使用该方法,返回该对象的个数。  now 函数:根据计算机系统设定的日期和时间返回当前的日期和时间值。 8.8.5 回复留言信息模块设计 回复留言信息模块主要分为 3 部分:留言详细信息显示、回复留言信息显示和回复留 言信息模块。查看留言和回复留言都不需要用户登录,在回复留言时可以匿名回复。回复 留言信息页的运行效果如图 8.19 所示。 图 8.19 回复留言信息页 1.前台页面设计 该模块中主要使用的控件及控件用途如表 8.12 所示。 表 8.12 回复留言信息模块中的控件 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 4 布局页面 标准 Lable 2 显示当前页数/总页数 标准 LinkButton 2 显示上一页/下一页 标准 TextBox 1 输入回复内容 标准 Button 1 提交回复内容 标准 CheckBox 1 选择是否匿名回复 验证 RequiredFieldValidator 2 验证回复内容是否为空 数据 DataList 1 显示留言信息 366 SQL Server 2005 数据库系统开发案例精选 前台页面中主要控件属性设置如下。 (1)在页面中使用 CheckBox 控件判断用户是否匿名回复。设置其 ID 属性为 CheckBox1,Text 属性为“匿名回复”。 (2)在页面中使用 TextBox 控件输入回复内容。设置其 ID 属性为 txtAnsLetter。这里 设置它的 TextMode 属性为 MultiLine,以显示多行文本。 (3)在页面中使用一个 RequiredFieldValidator 控件,用来验证控件 txtAnsLetter 是否为 空 , 该 控 件 的 ID 属 性 为 RequiredFieldValidator1。 在 这 里主 要 设 置 了 3 个 属 性 : ControlToValidate、ErrorMessage 和 Text,其属性值分别为 txtAnsLetter、“不能为空”和“*”。 (4)页面中使用 DataList 控件回复留言信息。该控件的 ID 属性为 DataList1,在 DataList1 中使用到了 3 个 Lable 控件,ID 分别为 labAnsLetter、labName、labRevertDate。分别用来显 示回复内容、回复人和回复日期。以 labAnsLetter 为例,绑定 Letter 字段的 HTML 代码如下: ’> 2.后台功能代码 在该页的页面加载事件中,主要显示了留言信息的详细内容及回复留言信息。该页 Page_Load 事件代码如下: protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { //判断当前用户有没有登录 if (Session["UserName"] == null) { //没有登录则把CheckBox1的属性设为True,默认为匿名回复 this.CheckBox1.Checked = true; } //获取从Message.aspx传过来的主键值  int ID =Convert.ToInt32(Request.QueryString["ID"].ToString()); //通过该主键值筛选出该条记录,使用Lable控件显示出来 DataSet ds = DB.reDs("select * from tb_Info where ID="+ID); labTitle.Text = ds.Tables[0].Rows[0][1].ToString(); labLetter.Text = ds.Tables[0].Rows[0][3].ToString(); LabName.Text = ds.Tables[0].Rows[0][2].ToString(); labIssueDate.Text = ds.Tables[0].Rows[0][4].ToString(); //绑定DataList1控件,将该留言信息的所有回复信息显示出来 bind(); } } bind()方法用于把该留言信息的所有回复信息绑定到 DataList1 上,并实现了分页功能。 关于分页的功能实现可参考 7.8.2 节。这里只提供绑定数据源的代码,代码如下: public void bind() { ⋯⋯此处代码省略 string cmdText = "select * from tb_AnswerInfo where AnswerID=" + ID; DataSet ds = DB.reDs(cmdText); ps.DataSource = ds.Tables[0].DefaultView; ⋯⋯此处代码省略 } 把留言信息绑定到 Lable 控件上显示出来 367 C H A P T E R 8 第 8 章 学生管理系统 单击【提交】按钮,将触发其 Click 事件,在此事件中将回复内容插入到数据库中, 详细代码如下: protected void btnOK_click_Click(object sender, EventArgs e) { //如果该页面通过了验证控件验证并且回复内容不超过200字,将回复信息插入到数据库中 if (Page.IsValid&&this.txtAnsLetter.Text.Length<200) { //取得当前系统时间 DateTime dt=DateTime.Now; //判断是否匿名回复 if (this.CheckBox1.Checked) { string cmdText = "insert into tb_AnswerInfo values";  cmdText+=(’" + int.Parse(Request["ID"].ToString()) + "’, ’" + this.CheckBox1.Text + "’,";  cmdText+="’" + this.txtAnsLetter.Text + "’,’" + dt.ToShortDateString() + "’)"; DB.ExSql(cmdText); bind(); } else { string cmdText = "insert into tb_AnswerInfovalues (’"+int.Parse (Request["ID"].ToString())+"’,"; cmdText+="’"+Session["UserName"].ToString()+"’,"; cmdText+="’"+this.txtAnsLetter.Text+"’,’"+dt.ToShortDateString()+"’)"; DB.ExSql(cmdText); bind(); } } }  代码导读  Convert 方法:将一个基本类型转换为另一个基本类型。  int.Parse:将 String 类型的字符串转换为 int 类型的数据。  ToShortDateString 方法:该方法将长日期格式转换为短日期格式。 8.8.6 公告管理模块设计 公告管理模块主要分为两部分:发布公告和显示公告模块。发布公告主要是将管理员 写好的公告插入到数据库中保存起来。而显示公告主要是使用一个 DataList 控件将数据库 中公告记录显示在页面上,管理员还可以对公告执行删除的功能。公告管理页面运行效果 如图 8.20 所示。 1.前台页面设计 在发布公告模块中使用到了 FreeTextBox 组件,它是一个免费的.NET 在线文本编辑器, 以.dll 文件格式封装起来,以供用户使用。右键单击项目名称,在弹出的快捷菜单中选择“添 加引用”命令,在“添加引用”对话框中选择“浏览”选项卡,在磁盘中找到存放的 FreeTextBox 组件,将其添加到项目中,“添加引用”完成后,将 FreeTextBox 组件所需要的资源文件复 制到项目中,这些资源文件包括图片、脚本和配置文件等,本实例中放置资源文件的文件 夹为 FreeTextBox。将 FreeTextBox 组件引用到项目中后,在需要该组件的页面中进行注册 使用,注册该组件时的代码如下: 匿名回复时,把 CheckBox 控件的 Text 文 本作为当前用户的用户名插入到数据库中 不匿名回复时,取得当前用 户的用户名插入到数据库中 368 SQL Server 2005 数据库系统开发案例精选 图 8.20 公告管理页面运行效果 <%@ Register TagPrefix="FTB" Namespace="FreeTextBoxControls" Assembly="FreeTextBox" %> 注册组件完成后,需要在合适的位置显示组件,显示组件时编写如下代码: 显示公告模块中,使用到了 DataList 控件来显示公告记录。在 DataList 控件模板中主 要使用的控件及控件用途如表 8.13 所示。 表 8.13 DataList 中的控件 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 1 布局页面 标准 LinkButton 1 实现删除功能 标准 CheckBox 1 判断该条记录是否被选中删除 前台页面中主要控件属性设置如下。 (1)在 DataList 的项模板添加一个 Table控件,在 TabLe 控件的单元格内加入如下 HTML 代码: <%# DataBinder.Eval(Container.DataItem,"Inform") %> 上述代码用来绑定公告信息表中的 Inform 字段,将公告内容显示出来。 (2)在 DataList 页脚模板中添加一个 LinkButton 控件,其 ID 属性为 lnkbtnDetele,把 lnkbtn Detele 的 Command 属性设置为 Delete,当单击该按钮时将触发 DataList 的 DeteleCommand 事件。 (3)在 DataList 项模板中添加 CheckBox 控件,用来标记指定行的记录是否要删除, 369 C H A P T E R 8 第 8 章 学生管理系统 这里设置该控件的 Text 属性为“删除”。如果该 CheckBox 控件的 Checked 属性为 True,则 单击 DataList 页脚模板中的【删除】按钮时将删除指定行的记录。 2.后台功能代码 在该页的页面加载事件中调用 Bind()方法绑定 DataList1,将公告信息显示在页面上。 该页 Page_Load 事件代码如下: protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { this.Bind(); } } Bind()方法将公告信息绑定到 DataList1 显示在页面上,详细代码如下: public void Bind() { DataSet ds = DB.reDs("select * from tb_Inform order by IssueDate Desc"); this.DataList1.DataSource = ds; this.DataList1.DataKeyField ="ID"; this.DataList1.DataBind(); } 当单击【删除】按钮时,将触发 DataList1 的 DeteleCommand 事件,在此事件中实现 删除选中行记录的功能。详细代码如下: protected void DataList1_DeleteCommand(object source, DataListCommandEventArgs e) { //遍历DataList中所有行,把选中了CheckBox控件的行从数据库中删除 for (int i = 0; i <= DataList1.Items.Count - 1; i++) { CheckBox cb = (CheckBox)DataList1.Items[i].FindControl("CheckBox1"); if (cb.Checked == true) { string sqlstr = "delete from tb_Inform where ID=’" + DataList1.DataKeys[i].ToString() + "’"; DB.ExSql(sqlstr); } } //重新绑定DataList1 Bind(); } 当用户单击【添加】按钮时,将触发其 Click 事件,在此事件中将 FreeTextBox1 的 Text 的文本值保持到数据库中。详细代码如下: protected void btnInsert_Click(object sender, EventArgs e) { //取得当前系统时间 DateTime dt = DateTime.Now; string cmdtxt = " insert into tb_Inform values(’"+this.FreeTextBox1.Text+"’,’"+dt+"’)"; //执行SQL语句,将公告保存到数据库中 DB.ExSql(cmdtxt); //重新绑定DataList1,将更新的数据显示在页面上 this.Bind(); //插入记录后清空FreeTextBox1 this.FreeTextBox1.Text = ""; } 当用户单击【添加】按钮时,将触发其 Click 事件,在此事件中将 FreeTextBox1 的 Text 370 SQL Server 2005 数据库系统开发案例精选 的文本值保持到数据库中。详细代码如下: protected void btnInsert_Click(object sender, EventArgs e) { //取得当前系统时间 DateTime dt = DateTime.Now; string cmdtxt = " insert into tb_Inform values(’"+this.FreeTextBox1.Text+"’,’"+dt+"’)"; //执行SQL语句,将公告保存到数据库中 DB.ExSql(cmdtxt); //重新绑定DataList1,将更新的数据显示在页面上 this.Bind(); //插入记录后清空FreeTextBox1 this.FreeTextBox1.Text = ""; } 当用户单击【重置】按钮时,清空 FreeTextBox1。详细代码如下: protected void btnClear_Click(object sender, EventArgs e) { //清空FreeTextBox1 this.FreeTextBox1.Text = ""; }  注意 在将 FreeTextBox 中的文本写入到数据库中时,可能提示数据插入时存在危险字符的错 误,只需要在 Web.config 配置文件中的节中添加如下代码即可解决该问题。 8.8.7 学生基本信息管理模块 学生基本信息主要包括 3 部分:系信息管理、班级信息管理和学生基本信息管理。其 中系包含班级,班级又包含学生。它们在范围上是从属关系。这样记录学生信息的好处是 方便了查找和添加学生信息。系信息和班级信息管理分别实现了对系信息和班级信息的添 加与删除。学生基本信息管理实现了对学生信息的添加与删除。由于这 3 个部分代码都比 较多。在一个页面上实现这些功能很复杂。所以这 3 个部分分别在 3 个页面上实现。为了 统一这 3 个页面的风格,这里使用了模板页。模板页是 ASP.NET 2.0 中新加的技术,使用 它可以定义一组页面的外观和通用功能。使得开发人员不必在每个页面中编写重复的代码, 并且在需要修改页面布局时只要修改模板页即可。系信息管理页面、班级管理页面和学生 基本信息管理页的运行效果如图 7-21 所示。 右键单击项目名称,在弹出的快捷菜单中选择“添加新项”一项,从弹出的“添加新 项”对话框中选中模板页,默认名称为 MasterPage.master,单击【确定】按钮,生成模板 页。在模板页上自带了一个命名为 ContentPlaceHolder 的控件。该控件是一个容器控件, 可以装载多个内容页。在模板页上显示的内容,将会和内容页的内容一起显示在内容页上。 模板页的设计效果如图 8.21 所示。 该模板页界面设计简单,只要在 ContentPlaceHolder 控件外加 3 个按钮,分别链接到系 信息管理页、班级信息管理页和学生信息管理页即可。下面就开始讲解该模板页的内容页。 1.内容页(Department.aspx) 选中模板页单击鼠标右键,在快捷菜单中选“添加内容页”项。添加成功后,把内容 371 C H A P T E R 8 第 8 章 学生管理系统 页默认的名称改为 Department.aspx。该页面主要实现了对系信息的添加和删除。该内容页 的设计效果如图 8.22 所示。 图 8.21 模板页的设计效果 图 8.22 系信息管理页设计效果 图中灰色的区域代表模板页的区域,在内容页中是不可以对它进行编译的。用户只有 在 Content 控件中添加内容页的内容。  前台页面设计 系信息管理模块中主要使用的控件及控件用途如表 8.14 所示。 表 8.14 系信息管理模块用到的控件 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 1 布局页面 标准 Button 2 执行添加/删除 标准 TextBox 1 录入数据 验证 RequiredFieldValidator 2 验证回复内容是否为空 数据 ListBox 1 显示信息 前台页面中主要控件属性设置如下。 372 SQL Server 2005 数据库系统开发案例精选 (1)TextBox 属性设置:该页面中,使用 TextBox 控件录入系别名称,其 ID 属性为 txtDepartment。 (2)ListBox 属性设置:该页面中,ListBox 控件主要用来显示系名称。其ID 属性为ListBox1。 (3)RequiredFieldValidator 控件属性设置:该页面中用到了一个 RequiredFieldValidator 控件,用来验证控件 txtDepartment 是否为空,该控件的 ID 属性为 RequiredFieldValidator1。 在这里主要设置了 3 个属性,即 ControlToValidate、ErrorMessage 和 Text,其属性值分别为 txtAnsLetter、“不能为空”和“*”。  后台功能代码 在该页的页面加载事件中主要绑定 ListBox1,将系信息显示在页面上。该页 Page_Load 事件代码如下: protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { //实现单击【删除】按钮时,弹出警告信息  btnDelete.Attributes["onclick"] = "javascript:return confirm(’你确认要删除选中项吗?’)"; bind();//调用bind方法绑定LIstBox } } bind()方法将系信息绑定到 ListBox 上,在页面上显示。详细代码如下: public void bind() { DataSet ds = DB.reDs("select * from tb_Department "); //清空ListBox1中的记录  ListBox1.Items.Clear(); foreach(DataRow dr in ds.Tables[0].Rows) { ListItem li=new ListItem(); li.Text=dr["DepartmentID"].ToString()+"——"+dr["Name"].ToString(); li.Value=dr["DepartmentID"].ToString(); ListBox1.Items.Add(li); } } 先在 ListBox1 中选中某一项,然后单击【删除】按钮,将触发该按钮的 Click 事件, 在此事件中,将删除 ListBox1 中选中的记录。详细代码如下: protected void btnDelete_Click(object sender, EventArgs e) { //取得ListBox中选定的记录的主键 string cmdText = "delete from tb_Department where DepartmentID=’" + this.ListBox1.SelectedValue + "’"; DB.ExSql(cmdText); //重新绑定ListBox bind(); } 单击【添加】按钮,将触发其 Click 事件,在此事件中编写代码向数据库中插入一条 记录。详细代码如下: protected void btnInsert_Click(object sender, EventArgs e) { SqlConnection conn = DB.GetCon(); conn.Open(); SqlCommand com = new SqlCommand("select count(*) from tb_Department", conn); //获取tb_Department表中记录条数 通过 foreach()方法遍历数据集中的行, 将记录读入到 ListBox 中显示出来 373 C H A P T E R 8 第 8 章 学生管理系统  int Count = Convert.ToInt32(com.ExecuteScalar()); string DepartmentID= "00"+Convert.ToString(Count + 1); DataSet ds=DB.reDs("select * from tb_Department where Name=’"+txtDepartment.Text.Trim()+"’"); if (ds.Tables[0].Rows.Count == 0) { string cmdText = "insert tb_Department values"; cmdText+= "(’" + DepartmentID + "’, ’" + txtDepartment.Text.Trim() + "’)"; DB.ExSql(cmdText); bind();//重新绑定ListBox this.txtDepartment.Text = ""; } else { Response.Write(""); this.txtDepartment.Text = ""; } }  代码导读  Attributes 方法:用于添加与该控件不对应的任意属性。 Clear 方法:用于清空控件中的数据。  ExecuteScalar 方法:返回表中记录的条数。 2.内容页(Class.aspx) 选中模板页单击鼠标右键,在快捷菜单中选“添加内容页”项。添加成功后,把内容 页默认的名称改为 Class.aspx。该页面主要实现了对班级信息的添加和删除。该内容页的设 计效果如图 8.23 所示。 图 8.23 班级管理页设计效果  前台页面设计 班级信息管理模块中主要使用的控件及控件用途如表 8.15 所示。 表 8.15 班级信息管理模块控件列表 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 1 布局页面 标准 TextBox 1 输入班级名称 判断用户输入的系名是否 与数据库中的系名重复 374 SQL Server 2005 数据库系统开发案例精选 续表 控 件 类 型 控 件 名 称 数 量 用 途 标准 Button 1 添加班级信息 验证 RequiredFieldValidator 1 验证班级名称是否为空 数据 GridView 2 显示系信息/班级信息 前台页面中主要控件属性设置如下。 (1)RequiredFieldValidator 控件属性设置:该页面中用到了一个 RequiredFieldValidator 控件,用来验证控件 txtClass 是否为空,该控件的 ID 属性为 RequiredFieldValidator1。在这 里主要设置了 3 个属性,即 ControlToValidate、ErrorMessage 和 Text,其属性值分别为 txtAnsLetter、“不能为空”和“*”。 (2)GridView 属性设置:该页面中,用到了两个 GridView 控件,其 ID 属性分别为 gvDepartment 和 gvClass,分别显示系信息和该系对应的班级。在 gvDepartment 和 gvClass 中都分别添加了一个模板列。在 gvDepartment 的模板列中添加了一个实现选择功能的 LinkButton 按钮,设置其 CommandName 为 select。在 gvClass 的模板列中添加了一个实现 删除功能的 LinkButton 按钮,同样设置其 CommandName 属性为 select。  后台功能代码 首先设一个全局变量来存储系名称。以便用户选择不同的系时,筛选出该系对应的班级。 public static string department; 在该页的页面加载事件中分别在 ID 为 gvDepartment 和 gvClass 的 GridView 控件中显 示了系信息及第一条系信息对应的班级。该页 Page_Load 事件代码如下: protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { DataSet ds1 = DB.reDs("select * from tb_Department "); gvDepartment.DataSource = ds1; gvDepartment.DataBind(); //获取gvDepartment控件中第一行中系名称(name)字段 department = ds1.Tables[0].Rows[0]["Name"].ToString(); //根据department来查询该系对应的班级 DataSet ds2 = DB.reDs("select * from tb_Class where Department=’" + department + "’"); gvClass.DataSource = ds2; gvClass.DataBind(); } } 在用户单击【删除】按钮时,弹出警告提示框。实现该功能的详细代码如下: protected void lnkButtonDelete_Load(object sender, EventArgs e) { //在页面加载时,给ID属性为lnkButtonDelete的LinkButton控件加上onclick事件,弹出警告对话框 ((LinkButton)sender).Attributes["onclick"] = "javascript:return confirm(’你确认要删除选中项吗?’)"; } 为了规范和统一,在显示班级 ID 时,在班级 ID 前加上“00”,实现该功能的代码需 要在 GridView 控件的 RowDataBound 事件下编写,详细代码如下: protected void gvClass_RowDataBound(object sender, GridViewRowEventArgs e) { 375 C H A P T E R 8 第 8 章 学生管理系统 //显示班级ID时在班级ID前加上00 e.Row.Cells[0].Text = "00" + e.Row.Cells[0].Text; } 当用户单击 ID 属性为 gvDepartment 的 GridView 控件中【选择】按钮,查看该系对应 的班级时,将触发 gvDepartment 的 SelectedIndexChanging 事件。在此事件中根据系名筛选 对应的班级信息。详细代码如下: protected void gvDepartment_SelectedIndexChanging(object sender, GridViewSelectEventArgs e) { //取得系名称 string Department=gvDepartment.Rows[e.NewSelectedIndex].Cells[2].Text.Trim(); //把系名称保存到全局变量department department = Department; //根据系名称筛选对应的班级 DataSet ds = DB.reDs("select * from tb_Class where Department=’" + Department + "’"); gvClass.DataSource = ds; gvClass.DataBind(); } 当用户单击 ID 属性为 gvClass 的 GridView 控件时,将触发 gvclass 的 SelectedIndex Changing 事件,在该事件中删除当前行。详细代码如下: protected void gvClass_SelectedIndexChanging(object sender, GridViewSelectEventArgs e) { //取得班级ID int ClassID = int.Parse(gvClass.Rows[e.NewSelectedIndex].Cells[0].Text.Trim()); //根据班级ID删除班级信息 DB.ExSql("delete from tb_Class where ClassID=" + ClassID); //重新绑定班级信息,显示更新信息 DataSet ds = DB.reDs("select * from tb_Class where Department=’"+department+"’"); gvClass.DataSource = ds; gvClass.DataBind(); } 当用户单击【添加】按钮时,将触发其 Click 事件,在此事件中把班级信息添加到数 据库中。并重新绑定班级信息,显示更新信息。详细代码如下: protected void btnInsert_Click(object sender, EventArgs e) { string cmdText = "insert tb_Class ( Name, Department ) "; cmdText+="values ( ’" + txtClass.Text.Trim() + "’,’" + department + "’)"; DB.ExSql(cmdText); gvClass.DataSource = DB.reDs("select * from tb_Class where Department=’" + department + "’"); gvClass.DataBind(); } 8.8.8 内容页(Student.aspx) 选中模板页单击右键,在快捷菜单中选择“添加内容页”项。添加成功后,把内容页 默认的名称改为 Student.aspx。该页面主要实现了对学生信息的添加和删除。该内容页设计 效果如图 8.24 所示。 1.前台页面设计 学生信息管理模块中主要使用的控件及控件用途如表 8.16 所示。 376 SQL Server 2005 数据库系统开发案例精选 图 8.24 学生信息管理页设计效果 表 8.16 学生信息管理模块中的控件 控 件 类 型 控 件 名 称 数 量 用 途 HTML Table 1 布局页面 HTML Input(Reset) 1 重置 标准 TextBox 8 输入学生信息 标准 Button 1 添加学生信息 验证 RequiredFieldValidator 7 验证学生信息必添项是否为空 验证 RangeValidator 1 验证年龄是否在有效范围内 验证 RegularExpressionValidator 1 验证是否有效的身份证号码 验证 CompareValidator 1 验证是否有效的日期格式 数据 GridView 3 显示系信息/班级信息/学生基 本信息 前台页面中主要控件属性设置如下。 (1)在页面中添加 7 个 RequiredFieldValidator 控件,用来验证 TextBox 控件是否为空, 以 ID 属性为 RequiredFieldValidator1 的验证控件为例。在这里主要设置了两个属性: ControlToValidate 和 ErrorMessag,其属性值分别为 txtName 和“*”。 (2)在页面中添加一个 RangeValidator,用来验证用户输入的学生年龄是否在有效的范 围内。这里主要设置了 6 个属性:ControlToValidate、ErrorMessage、Text、Type、Maximum Value、 MinimumValue(其中 Type 用于比较值的类型、MaximumValue 是所验证控件的最大值、 MinimumValue 是所验证控件的最小值)。对应的属性值分别是:txtAge、*、格式不对、Integer、 99 和 1。 (3)RegularExpressionValidator 控件属性设置:该页面用到了一个 RegularExpression Validator 控件。使用正则表达式来验证用户输入的身份证编号是否有效。这里主要设置其 4 个属性,即 ControlToValidate、ErrorMessage、Text、ValidationExpression(ValidationExpression 用于确定有效性的正则表达式)。对应的属性值分别是 txtIdCard、*、格式不对、\d {17} [\d] [X] |d{15}。 (4)CompareValidator 控件属性设置:CompareValidator 控件可以对用户输入的值按照 一定的规则与其他控件的数据进行比较。该页面使用了一个 CompareValidator,用来验证用 户输入的日期格式是否合法。这里设置了五个属性,即 ControlToValidate、ErrorMessage、 Text、Operator 和 Type(Operator 的默认值为 Equal,表示比较两个控件的数据是否相等。 377 C H A P T E R 8 第 8 章 学生管理系统 如果把 Operator 的属性值设为 DataTypeCheck,则该控件只验证输入控件的的值是否可以 转换为 Type 属性指定的数据类型)。对应的值分别为 txtStudyDate、*、格式不对、Data TypeCheck、Date。 (5)GridView 属性设置:该页面中,用到了 3 个 GridView 控件,其 ID 属性分别为 gvDepartment、gvClass 和 gvStudent,分别显示系信息、该系对应的班级和该班级对应的学 生信息。在 gvDepartment、gvClass 和 gvStudent 中都分别添加了一个模板列。在 gvDepartment 和 GVCalss 的模板列中分别添加了一个实现选择功能的 LinkButton 按钮,设置其 CommandName 为 select。在 gvStudent 的模板列中添加了一个实现删除功能的 LinkButton 按钮,设置其 CommandName 属性为 delete。 2.后台功能代码 首先在该页中设一个全局变量,用来保存班级 ID。添加学生信息时,需要根据班级 ID 加入到某一个班级内。 public static int classID; 在该页的页面加载事件中将显示系信息和排在第一位的系对应的班级及该班级中学生 信息。该页 Page_Load 事件代码如下: protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { //设置txtAmount的输入文本只能为数字 txtAge.Attributes["onkeyup"] = "value=value.replace(/[^\\d]/g,’’)"; Bind(); bind(); } } bind()方法将系信息和班级信息分别绑定到 gvDepartment 和 gvClass 控件,在页面上显 示。详细代码如下: public void Bind() { DataSet ds1 = DB.reDs("select distinct * from tb_Department"); gvDepartment.DataSource = ds1; gvDepartment.DataBind(); DataSet ds2 = DB.reDs("select * from tb_Class where Department=’" + ds1.Tables[0].Rows[0] [1].ToString() + "’"); classID = int.Parse(ds2.Tables[0].Rows[0]["ClassID"].ToString()); gvClass.DataSource = ds2; gvClass.DataBind(); } bind()方法根据班级 ID,把该班级的学生信息绑定 gvStudent 控件,在页面上显示。详 细代码如下: public void bind() { DataSet ds3 = DB.reDs("select * from tb_Student where ClassID=’" + classID + "’"); gvStudent.DataSource = ds3; gvClass.DataKeyNames =new string[] { "StudentID" };//设置主键 gvStudent.DataBind(); } 当用户单击 gvDepartment 控件中的【选择】按钮时,将触发 gvDepartment 控件的 378 SQL Server 2005 数据库系统开发案例精选 SelectedIndexChanging 事件。在此事件中编写代码显示该系对应的班级及排在第一位的班 级对应的学生信息。详细代码如下: protected void gvDepartment_SelectedIndexChanging(object sender, GridViewSelectEventArgs e) { //取得当前行的系名 string Department = this.gvDepartment.Rows[e.NewSelectedIndex].Cells[2].Text.ToString(); //根据系名筛选出该系对应的班级 DataSet ds1 = DB.reDs("select * from tb_Class where Department=’" + Department + "’ "); ; gvClass.DataSource = ds1; gvClass.DataBind(); //判断该班级是否有学生 if (ds1.Tables[0].Rows.Count != 0) { //如果有学生,则显示ID属性为gvStudent的GridView控件,默认为不显示 this.gvStudent.Visible = true; //取得在gvClass中排为第一的班级ID classID =int.Parse( ds1.Tables[0].Rows[0]["classID"].ToString()); //根据上面的ClassID筛选出学生信息显示在gvStudent中 bind(); } else { //如果没有学生,则隐藏gvStudent this.gvStudent.Visible = false; } } 当用户单击 gvClass 控件中的【选择】按钮时,将触发 gvClass 控件的 SelectedIndexChanging 事件。在此事件中编写代码显示该班级对应的学生信息。详细代码如下: protected void gvClass_SelectedIndexChanging(object sender, GridViewSelectEventArgs e) { //取得当前行的班级ID,赋给全局变量classID classID = int.Parse(this.gvClass.Rows[e.NewSelectedIndex].Cells[1].Text.ToString()); //根据上面取得的班级ID,筛选出学生信息显示在gvStudent中 bind(); } 当用户单击 gvStudent 控件中的【删除】按钮时,将触发 gvStudent 控件的 RowDelete 事件。在该事件中编写代码删除当前选中的行记录。详细代码如下: protected void gvStudent_RowDeleting(object sender, GridViewDeleteEventArgs e) { //获取当前行的StudentID int StudentID =int.Parse(this.gvStudent.Rows[e.RowIndex].Cells[1].Text.ToString()); //执行删除操作 DB.ExSql("delete from tb_Student where StudentID=’" + StudentID + "’"); //重新绑定学生信息 bind(); } 当用户单击 gvStudent 控件中的【删除】按钮时,将触发 Load 事件,弹出警告对话框。 实现该功能的代码如下: protected void lbtnDelete_Load(object sender, EventArgs e) { //在页面加载时,给ID属性为lbtnDelete的LinkButton控件加上onclick事件,弹出警告对话框 ((LinkButton)sender).Attributes["onclick"] = "javascript:return confirm(’你确认要删除选中项吗?’)"; } 379 C H A P T E R 8 第 8 章 学生管理系统 gvStudent 控件实现了分页功能,详细代码如下: protected void gvStudent_PageIndexChanging(object sender, GridViewPageEventArgs e) { this.gvStudent.PageIndex = e.NewPageIndex; bind(); } 当用户单击【添加】按钮时,将触发其 Click 事件,在该事中编写代码将学生信息添 加到数据库中。详细代码如下: protected void btnInsert_Click(object sender, EventArgs e) { string Name = txtName.Text.Trim();//取得学生姓名 string Age = txtAge.Text.Trim();//取得学生年龄 string Sex = ddlSex.SelectedValue;//取得学生性别 //取得入学时间 DateTime StudyDate =DateTime.Parse(txtStudyDate.Text.Trim()); string Address = txtAddress.Text.Trim();//取得家庭地址 string Phone = txtPhone.Text.Trim();//取得家庭电话 string DorPhone = txtDorPhone.Text.Trim();//取得宿舍电话 string IdCard = txtIdCard.Text.Trim();//取得身份证ID string cmdText = "insert into tb_Student values (’" + classID + "’,’" + Name + "’,"; cmdText+= "’" + Age + "’,’" + Sex + "’,’" + StudyDate.ToShortDateString() + "’,"; cmdText+="’" + Address + "’,’" + Phone + "’,’" + DorPhone + "’,’" + IdCard + "’)"; //执行添加命令 DB.ExSql(cmdText); //重新绑定gvStudent,显示更新 bind(); } 8.9 疑难问题分析解决 8.9.1 DataList 控件绑定数据的几种方法 在使用 DataList 控件显示数据时,需要在 HTML 中绑定数据源中的字段。通常使用下 面几种代码来实现此功能。 (1)使用 DataBind.Eval 方法获得参数(Name)。 ’ >’> (2)除了使用 DataBind.Eval 外,还可以使用 ItemDataBound 事件来绑定字段。 ’ >’> (3)当数据源为 DataReader 时,可以使用下面的方法来绑定字段。 ’ >’> ’ >’> 上面介绍的 3 种方法都可以用来绑定数据源中的字段,在这里推荐读者使用第(2)和 第(3)中方法。因为这两种方法的代码执行效率比第一种方法要高。 380 SQL Server 2005 数据库系统开发案例精选 8.9.2 如何实现多个 DropDownList 控件的联动 在本例中,编写学生信息搜索模块时,使用了两个 DropDownList 的联动。即用户在第 一个 DropDownList 控件中选择系名称时,第二个 DropDownList 中就显示该系对应的班级。 两 个 DropDownList 的联动是最简单的联动方式。当然,读者只要学会了这两个 DropDownList 的联动,也就学会了多个 DropDownList 的联动。 先把第一个 DropDownList 控件的 AutoPostBack 属性设置为 True,然后在第一个 DropDownList 控件的 SelectedIndexChanged 事件中编写如下代码: //根据ID为ddlDepartment的DropDrowList控件的选择项的值,从数据库中筛选该系对应的班级 DataSet ds = DB.reDs("select Name from tb_Class where Department=’" + ddlDepartment.SelectedValue + "’"); //将返回的DataSet作为ID为ddlClass的DropDrowList控件的数据源 this.ddlClass.DataSource = ds; this.ddlClass.DataTextField = "Name"; this.ddlClass.DataBind(); 8.10 程序调试及错误处理 在本系统开发过程中,曾经遇到用户自定义控件在系统主页上使用时,控件的背景图 片不能显示出来的情况(如图 8.25 所示)。笔者为了解决这个问题花费了一些不必要的时 间。为了使得读者在遇到这类问题时,不再浪费时间。下面介绍如何解决这类问题。 图 8.25 控件背景图不显示 笔者遇到上述问题时,首先检查了在此用户控件上的图片路径是否正确。在检查无误 后,又在主页上重新导入用户控件。发现用户控件的背景图片还是不能显示出来。于是, 笔者在源程序根目录下新建了一个 Index 文件夹,将主页页面文件放在了该文件夹下,如 图 8.26 和图 8.27 所示。再运行程序发现原来不显示的背景图片居然都显示出来了。 381 C H A P T E R 8 第 8 章 学生管理系统 图 8.26 修改前的系统文件架构 图 8.27 修改后的系统文件架构 9 图书综合管理系统 开发导读 实例说明  实例名称:图书综合管理系统。  实例路径:光盘\mingrisoft\ 图书综合管理系统\Program。  实例执行文件:光盘\ mingrisoft\图书综合管理系 统 \Program\ExeFile\ 图 书 综 合管理系统.exe。  实例工程文件:光盘\ mingrisoft 图书综合管理系 统 \Program\FormFile\图书综 合管理系统.vbp。  用户名:mr。  密码:mrsoft。  用户在使用本实例前,请仔细 阅读光盘中的光盘使用说明、 程序界面修改配置说明书、安 装说明书、使用说明书,这样 可以使您更好地学习和使用本 软件。 在计算机中使用本实例的源程序时,用户需要安 装 Visual Basic 6.0。 本实例数据库为 SQL Server 2005,使用本实例 前,需要安装 SQL Server 2005,并将光盘中提供的 数据库文件附加到 SQL Server 2005 中。安装时,SQL Server 2005 的验证模式设置为混合模式,用户名为 sa,密码为空。 本实例提供了 5 套不同界面风格的程序,其中一 些素材的格式需要使用特殊软件处理。 如果修改 Ico 文件,则需要安装 Ico 编辑软件。 384 SQL Server 2005 数据库系统开发案例精选 图书综合管理系统共有窗体界面近 30 个,下面只给出主窗体、系统登录、读者基本信 息、图书入库、关于等界面,其他界面请参见光盘中的源程序。 主窗体 系统登录 读者基本信息 图书入库 关于 图书借阅分析 添加操作员 385 C H A P T E R 9 第 9 章 图书综合管理系统 9.1 概 述 传统的手工管理图书,图书管理人员的工作内容重复、工作量大,特别是在图书的 借阅与归还管理时,需要先查询借书单,然后填写还书单,并查询借阅图书是否按时归 还等一系列操作,既费时又费力,工作效率低。随着信息技术的不断发展,计算机应用 的日益广泛,传统的手工图书管理方式必然被以计算机为基础的图书综合管理系统所 取代。 通过使用图书综合管理系统,可以大大提高图书的进销存、借阅等相关操作的工作 效率。 9.2 系 统 分 析 9.2.1 需求分析 通过市场调查,要求本系统具有以下功能。  系统使用人员较多,需要较好的权限管理设置。  批量填写图书入库单、图书销售单、图书借阅单、图书归还单。  灵活的报表设计及打印功能。  图书库存查询及图书库存预警。  读者信息与图书分类管理。  图书信息查询。  完善的权限管理,增强系统的安全性。  数据备份及恢复功能,保证系统数据的安全性。 9.2.2 可行性分析 复杂的图书综合管理软件对于用户而言太庞大、太复杂,所以应用效果并不是很好。 这就需要程序员开发出一套即操作简便,功能又强大的图书综合管理软件来管理图书的相 关信息。 本图书综合管理系统,包括对图书作者和出版社等在内的基础数据管理、图书进销存 管理、图书借阅管理、图书归还管理、读者管理、统计打印和系统管理等几部分。 9.3 总 体 设 计 9.3.1 项目规划 图书综合管理系统是一个以 SQL Server 2005 为数据库的管理系统,系统由基本信息设 置、图书销售管理、图书入库管理、借书管理、还书管理、决策分析、系统管理及系统维 护等模块组成,规划系统功能模块如下。 386 SQL Server 2005 数据库系统开发案例精选  基本信息管理模块 该模块主要完成图书类别信息设置、图书存放位置信息设置、读者类别信息设置、读 者信息设置。  图书销售管理模块 该模块主要由图书销售及图书销售查询组成。  图书入库管理 该模块由图书入库、图书入库查询、图书库存上下限设置、图书库存查询、图书库存 预警组成。  借书管理模块 该模块包括借书登记、借书查询、书证到期提醒 3 部分。  还书管理模块 该模块包括还书登记、还书查询两部分。  决策分析模块 该模块包括图书销量分析、图书借阅分析、库存分析 3 部分。  系统管理模块 该模块包括操作员信息设置、操作员密码设置、操作员级别设置、操作员权限设置 4 部分。  系统维护模块 该模块包括图书综合系统初始化、数据库备份及恢复 3 部分。 9.3.2 系统功能结构图 图书综合管理系统的功能结构如图 9.1 所示。 图 9.1 系统功能结构图 操 作 员 权 限 设 置 387 C H A P T E R 9 第 9 章 图书综合管理系统 9.4 系 统 设 计 9.4.1 设计目标 面对企业信息化发展过程中出现的各种情况,并根据书店的业务需求,本系统在设计 的时候应该满足以下几个目标。  利用条形码扫描器进书、售书、借书、还书,使信息传递准确、顺畅。  灵活的运用表格批量输入数据,使信息传递更快捷。  在操作时响应热键。  系统采用人机对话方式,界面美观友好、信息查询灵活、方便、快捷、准确、数 据存储安全可靠,实现了售书、借书,加强了图书流通管理。  在进行数据查询时,采用模糊查询方式。  图书类别分类详细、层次清晰,并以树状形式浏览。  管理员可以设置操作员的权限。  完善的读者资料库,使借书更安全。  分类详细的图书目录,使读者查询更方便。  快速借书、还书,提高日常工作效率。  强大的库存预警功能,尽可量地减少商家不必要的损失。  对用户输入的数据系统将进行严格的数据检验,尽可能排除人为的错误。  数据保密性强,为每个用户设置权限级别。  系统最大限度地实现了易安装性、易维护性和易操作性。  系统运行稳定、安全可靠。 9.4.2 开发及运行环境 系统开发平台:Visual Basic 6.0(SP5)。 数据库管理系统软件:SQL Server 2005。 运行平台:Windows XP/ Windows 2000/Windows 2003。 分辨率:最佳效果 1024×768 像素。 9.4.3 编码设计 本系统内部信息编码方式情况如下。 (1)书证号编号为 1 位字符与 5 位数字编码的组合。其首字符与读者类别名称相关, 例如读者类别名称为“年卡”,编号为“年 00001”。 (2)图书类别编号为数字编码的组合。根据图书类别名称所处级别不同,编号长度也 不相同。例如一级类别名称为“01”、二级类别名称为“001”、三级类别名称为“0001”, 依此类推。 (3)图书存放位置编号为大写字母“P”和 5 位数字编码的组合。例如:P00001。 (4)图书入库票号编号为系统当前日期与小写字母“rk”和 4 位数字编码的组合。例 如:2006-10-7rk0001。 388 SQL Server 2005 数据库系统开发案例精选 (5)图书销售票号编号为系统当前日期与小写字母“xs”和 4 位数字编码的组合。例 如:2006-10-7xs0001。 (6)图书借书票号编号为系统当前日期与小写字母“js”和 4 位数字编码的组合。例 如:2006-10-7js0001。 (7)图书还书票号编号为系统当前日期与小写字母“hs”和 4 位数字编码的组合。例 如:2006-10-7hs0001。 9.5 数据库设计 9.5.1 数据表的实体 E-R 图 E-R 图是根据用户的需求,设计各种实体以及它们之间的关系,为后面的逻辑结构设计 打下基础。根据分析设计的结果,进行部分实体设计。部分实体的 E-R 图及其关系描述如下。 图 9.2 为图书类别实体 E-R 图。 图 9.3 为读者类别实体 E-R 图。 图 9.2 图书类别实体 E-R 图 图 9.3 读者类别实体 E-R 图 9.5.2 主要数据表的结构 由于文章的篇幅所限,在此只给出较为重要的数据表,其他数据表请参见本书附带的 光盘。  dzlbb(读者类别表) 读者类别表主要用来保存读者类别信息。读者类别表的结构如表 9.1 所示。 表 9.1 读者类别表的结构 字 段 名 称 数 据 类 型 字 段 大 小 类别名称 nvarchar 4 收费标准 money 8 期限 nvarchar 6 备注 nvarchar 200  reads(读者信息表) 读者信息表主要用来保存读者基础信息。读者信息表的结构如表 9.2 所示。 表 9.2 读者信息表的结构 字 段 名 称 数 据 类 型 字 段 大 小 书证号 nvarchar 20 姓名 nvarchar 10 389 C H A P T E R 9 第 9 章 图书综合管理系统 续表 字 段 名 称 数 据 类 型 字 段 大 小 性别 nvarchar 2 身份证 nvarchar 25 单位 nvarchar 30 家庭住址 nvarchar 30 联系电话 nvarchar 40 读者类别 nvarchar 4 办证价格 money 8 期限 nvarchar 6 办证日期 datetime 8 已借书数 smallint 2 相片路径 image 200 收费标准 money 8 到期日期 datetime 8  rkb(入库表) 入库表主要用来保存图书入库信息。入库表的结构如表 9.3 所示。 表 9.3 入库表的结构 字 段 名 称 数 据 类 型 字 段 大 小 书号 nvarchar 30 条形码 nvarchar 20 书名 nvarchar 200 作者 nvarchar 20 出版社 nvarchar 30 版次 nvarchar 50 图书类别 nvarchar 20 存放位置 nvarchar 20 单价 money 8 入库数量 smallint 2 金额 money 8 经手人 nvarchar 10 票号 nvarchar 30 操作员 nvarchar 10 日期 datetime 8  rkph(入库票号表) 入库票号表主要用来保存图书入库的票据信息。入库票号表的结构如表 9.4 所示。 表 9.4 入库票号表的结构 字 段 名 称 数 据 类 型 字 段 大 小 票号 nvarchar 30 入库品种 nvarchar 10 390 SQL Server 2005 数据库系统开发案例精选 续表 字 段 名 称 数 据 类 型 字 段 大 小 入库数量 smallint 2 合计金额 money 8 经手人 nvarchar 10 操作员 nvarchar 10 日期 datetime 8  kcb(库存表) 库存表用来保存库存图书信息。库存表的结构如表 9.5 所示。 表 9.5 库存表的结构 字 段 名 称 数 据 类 型 字 段 大 小 书号 nvarchar 30 条形码 nvarchar 20 书名 nvarchar 200 作者 nvarchar 20 出版社 nvarchar 30 图书类别 nvarchar 20 存放位置 nvarchar 20 图书总数 smallint 2 单价 money 8 现存数量 smallint 2 金额 money 8 借出次数 smallint 2 库存上限 smallint 2 库存下限 smallint 2  xsb(销售表) 销售表用来保存图书销售信息。销售表的结构如表 9.6 所示。 表 9.6 销售表的结构 字 段 名 称 数 据 类 型 字 段 大 小 书号 nvarchar 30 条形码 nvarchar 20 书名 nvarchar 200 作者 nvarchar 20 出版社 nvarchar 30 图书类别 nvarchar 20 存放位置 nvarchar 20 单价 money 8 销售数量 smallint 2 金额 money 8 391 C H A P T E R 9 第 9 章 图书综合管理系统 续表 字 段 名 称 数 据 类 型 字 段 大 小 经手人 nvarchar 10 票号 nvarchar 30 操作员 nvarchar 10 日期 datetime 8 9.5.3 概念结构设计 为了使读者对本系统后台数据库中数据表有一个更清晰的认识,在此笔者为读者设计 了数据表树型结构图,如图 9.4 所示,其中包含了对系统所有数据表的相关描述。 图 9.4 数据表树型结构图 9.6 技 术 准 备 9.6.1 函数准备 在开发图书综合管理系统时需要用到一些常用的函数,只有灵活运用这些函数,才能 开发出功能强大的应用程序,下面给出程序中用到相关函数的语法结构及用途。  Len 函数 用途:返回 Long,用于返回字符串内字符的数目,或是存储变量所需的字节数。 语法:Len(string) 参数说明: string:任何有效的字符串表达式。如果 string 包含 Null,会返回 Null。  Trim 函数 用途:返回字符串中前端和后端的空格。 392 SQL Server 2005 数据库系统开发案例精选 语法:LTrim(string) 参数说明: string:该参数可以是任何有效的字符串表达式。如果 string 包含 Null,将返回 Null。  Val 函数 用途:将字符数据转换为数值数据。 语法:Val(string) 参数说明: string:该参数可以是任何有效的字符串表达式。  Str 函数 用途:将数值型数据转换为字符类型的数据。 语法:Str(number) 参数说明: number:参数类型为 Long,其中可包含任何有效的数值表达式。  Format 函数 用途:返回一个字符串表达式,它根据格式表达式中的指令来格式化字符串。 语法:Format(expression[,format[,firstdayofweek[,firstweekofyear]]]) 参数说明如表 9.7 所示。 表 9.7 Format 函数的参数说明 部 分 说 明 expression 必要参数。任何有效的表达式 format 可选参数。有效的命名表达式或用户自定义格式表达式 firstdayofweek 可选参数。常数,表示一星期的第一天 firstweekofyear 可选参数。常数,表示一年的第一周 9.6.2 控件准备 在开发图书综合管理系统时需要添加一些 Active 控件。这些控件是通过“工程”\“部 件”菜单项添加的,在所添加的选项当中,有的选项包含多个控件,为使读者方便添加控件, 下面给出图书综合管理系统程序中需要添加的选项和需要使用的对应控件,如图 9.5 所示。 图 9.5 部件选项卡 393 C H A P T E R 9 第 9 章 图书综合管理系统  注意 如果想在控件列表中只显示选定项,只需选中“只显示选定项”复选框;若要显示所 有项,取消选中“只显示选定项”复选框即可。 9.7 主要功能模块设计 9.7.1 系统架构设计 文件夹架构说明如图 9.6 所示。 图 9.6 系统文件夹架构图 为了使读者能够对系统文件有更清晰的认识,笔者在此设计了文件架构图。 主文件架构如图 9.7 所示。 图 9.7 主文件架构图 基础信息管理文件架构如图 9.8 所示。 图 9.8 基础信息管理文件架构图 图书管理架构如图 9.9 所示。 394 SQL Server 2005 数据库系统开发案例精选 图 9.9 图书管理架构图 借阅管理文件架构与决策分析文件架构如图 9.10 与图 9.11 所示。 图 9.10 借阅管理文件架构图 图 9.11 决策分析文件架构图 系统管理文件架构如图 9.12 所示。 系统维护文件架构与帮助文件架构如图 9.13 所示。 图 9.12 系统管理文件架构图 图 9.13 系统维护文件架构图与帮助文件架构图 9.7.2 公共模块设计 将一些公用的数据信息放到模块中可以节省系统资源,实现代码重用,提高程序运行 395 C H A P T E R 9 第 9 章 图书综合管理系统 速度,本系统中用到了 Module1 模块。 在公共模块(Module1)中创建一个连接函数 cnn(),可用来执行 SQL 语句,并可以在 程序中使用 Recordset 对象连接数据源,从而优化了 ADO+SQL Server 2005 数据库的连接: //…………………………………………………例程8-1…………………………………………………// Public adoCon As New ADODB.Connection Public adoRs As New ADODB.Recordset Public Sub main() Dim temp As String temp = "DSN=NBooks" adoCon.Open (temp) End Sub Public Function Cnn() As ADODB.Connection ’声明函数 ’创建连接 Set Cnn = New ADODB.Connection ’打开连接 Cnn.Open "DSN=NBooks" End Function 9.7.3 系统登录设计 系统登录主要用于对登录图书综合管理系统的用户进行安全性检查,以防止非法用户 登录该系统。管理员可以给用户分配权限, 用户登录时根据所具有的权限操作系统中相 应的功能。 在登录系统时验证操作员及其密码,主 要通过 ADO 控件中记录集(RecordSet)对 象结合 If 语句判断用户选定的操作员及其输 入的密码与数据库中的操作员和密码是否相 同来实现,如果相同,则允许登录,并给予 相应的权限,否则将不允许用户登录。 系统登录的运行结果如图 9.14 所示。 1.窗体设计 (1)在工程中新建一个窗体,将窗体的名称设置为“main_mm”,BorderStyle 属性设 置为“main_mm”,通过添加 Image 控件 设置其 Picture 属性添加图片。 (2)在窗体上添加 Adodc 控件 ,由于该控件属于 ActiveX 控件,在使用之前必须从 “部件”对话框中添加到工具箱。添加方法如下。 在“工程”/“部件”对话框中勾选“Microsoft Ado Data Controls 6.0(SP4)”列表项, 单击【确定】按钮之后即可将 Adodc 控件添加到工具箱当中。 (3)在窗体中添加一个 ListView 控件 和文本框控件 。 (4)在窗体中添加 5 个 Label 控件 ,设置前两个 Label 控件的 Caption 属性为“确定” 和“退出”,设置后 3 个 Label 控件的 Caption 属性为空。 (5)在窗体中添加一个 ImageList 控件 。 (6)在窗体上添加一个 ImageList 控件,在控件上单击鼠标右键,选择“属性”项,然 后在弹出的“属性页”对话框中选择“通用”选项卡,在该选项卡中设置向控件添加图片 图 9.14 系统登录窗体的运行结果 396 SQL Server 2005 数据库系统开发案例精选 的大小,如图 9.15 所示。 在此选择图像的高度和宽 度,设置图像的大小 图 9.15 设置添加图片的大小 (7)在 ImageList 控件的“属性页”对话框中选择“图像”选项卡,通过单击【插入图 片】按钮添加图片,如图 9.16 所示。 单击此按钮,向控 件中添加图片 图 9.16 向控件中添加图片 登录窗体的设计结果如图 9.17 所示。 图 9.17 系统登录窗体的设计界面 2.代码设计 在代码窗口的声明部分定义如下变量: //…………………………………………………例程8-2…………………………………………………// Dim itmX As ListItem ’声明一个ListItem对象 397 C H A P T E R 9 第 9 章 图书综合管理系统 Dim MyIcon As Integer ’声明一个整型变量 Dim text, MyMsg As String ’声明字符串变量 在窗体装载事件中,通过 ADO 控件的 ConnectionString 属性建立数据库连接,同时将 所有操作员的名称及头像添加到 ListView 控件当中,代码如下: //…………………………………………………例程8-3…………………………………………………// Private Sub Form_Load() Adodc1.ConnectionString = "DSN=NBooks" Adodc1.RecordSource = "select * from qxb" Adodc1.Refresh If Adodc1.Recordset.RecordCount > 0 Then With Adodc1.Recordset .MoveFirst czy.Caption = .Fields("操作员") bh.Caption = .Fields("编号") jb.Caption = .Fields("操作员级别") ’添加操作员 Do While .EOF = False text = .Fields("操作员") MyIcon = Val(Right(.Fields("头像"), Val(Len(.Fields("头像")) - 2))) Set itmX = ListView1.ListItems.Add(, , text, MyIcon) .MoveNext Loop End With End If End Sub 单击【确认】按钮,如果输入的操作员姓名和口令正确,则通过身份验证,登录到系 统当中,并根据权限分配相应的操作功能。通过 SQL 语句查询输入的用户名和密码信息在 数据库中是否存在,如果查询到符合条件的记录信息则显示系统主窗体,登录到系统当中, 实现的程序代码如下: //…………………………………………………例程8-4…………………………………………………// Private Sub Label1_Click() ’确认 Adodc1.RecordSource = "select * from qxb where 操作员 = ’" + Trim(czy.Caption) + "’" ’Trim 函数返回 Variant (String),其中包含指定字符串的拷贝,没有前导和尾随空白。 Adodc1.Refresh If Adodc1.Recordset.RecordCount > 0 Then ’如果记录数大于零 With Adodc1.Recordset  frm_main.jcxxgl.Enabled = .Fields("基础信息管理") frm_main.Toolbar1.Buttons(1).Enabled = .Fields("基础信息管理") frm_main.tsgl.Enabled = .Fields("图书管理") frm_main.Toolbar1.Buttons(3).Enabled = .Fields("图书管理") frm_main.Toolbar1.Buttons(9).Enabled = .Fields("图书管理") frm_main.Label1.Enabled = .Fields("图书管理") frm_main.Label2.Enabled = .Fields("图书管理") frm_main.Label3.Enabled = .Fields("图书管理") frm_main.Label9.Enabled = .Fields("图书管理") frm_main.jygl.Enabled = .Fields("借阅管理") frm_main.Toolbar1.Buttons(5).Enabled = .Fields("借阅管理") frm_main.Toolbar1.Buttons(7).Enabled = .Fields("借阅管理") frm_main.Label4.Enabled = .Fields("借阅管理") frm_main.Label5.Enabled = .Fields("借阅管理") frm_main.Label10.Enabled = .Fields("借阅管理") 398 SQL Server 2005 数据库系统开发案例精选 frm_main.jcfx.Enabled = .Fields("决策分析") frm_main.Label6.Enabled = .Fields("决策分析") frm_main.Label7.Enabled = .Fields("决策分析") frm_main.Label8.Enabled = .Fields("决策分析") frm_main.xtwh.Enabled = .Fields("系统维护") frm_main.xtgl.Enabled = .Fields("系统管理") frm_main.Toolbar1.Buttons(11).Enabled = .Fields("系统管理") End With ’验证操作员及密码 If Text1.text = Adodc1.Recordset.Fields("密码") Then Load frm_main  frm_main.Show frm_main.St1.Panels(3).text = czy.Caption  Unload Me Else If czy.Caption = "" Then  MsgBox "请选择操作员!", "图书综合管理系统" ListView1.SetFocus Else If Text1.text <> Adodc1.Recordset.Fields("密码") Then MsgBox "密码错误,请重新输入密码!", "图书综合管理系统" Txttime.text = Val(Txttime.text) + 1 Text1.SetFocus End If End If If Txttime.text = "3" Then ’密码错误3次,退出系统 MyMsg = MsgBox("密码输入错误,请向系统管理员查询!", "图书综合管理系统") If MyMsg = vbOK Then End End If End If End If End Sub  代码导读  获取字段值的几种方法。 frm_main.jcxxgl.Enabled = Adodc1.Recordset.Fields("基础信息管理") ’取名为"基础 信息管理"字段的值 frm_main.jcxxgl.Enabled = Adodc1![基础信息管理] ’字段值两端不必加双引号 frm_main.jcxxgl.Enabled = Adodc1.Recordset.Fields(0) ’0 为字段索引号 上面这种方法引用的是字段的索引值,如果字段顺序改变,一定要改变引用字段的索 引值,否则会产生错误。  Show:用于显示 MDIForm 或 Form 对象。  Unload Me:从内存中卸载窗体或控件。  MsgBox:在对话框中显示消息,等待用户单击按钮,并返回一个 Integer 告诉用户 单击哪一个按钮。 9.7.4 程序主窗体 程序主窗体是图书综合管理系统的交互控制平台,实现给予操作员不同的使用权限。 程序主窗体运行界面如图 9.18 所示。 399 C H A P T E R 9 第 9 章 图书综合管理系统 图 9.18 程序主窗体运行界面 1.窗体设计 (1)在工程中新建一个窗体,将窗体的名称设置为“Frm_main”,BorderStyle 属性设 置为“1-Fixed Single”,MaxButton 属性设置为 False,并向 Picture 属性中加载一幅图片。 (2)单击【工具】菜单下的【菜单编辑器】子菜单项。 (3)在弹出的【菜单编辑器】对话框中,在【标题】输入栏中输入显示的菜单名;在 【名称】输入栏中输入代码中使用的菜单名。 (4)完成主菜单后,可以运用下箭头把选定的菜单项在同级菜单内向下移动一个位置, 以完成子菜单的设计。 (5)工具栏主要运用 ToolBar 控件 与 ImageList 控件 完成。它由 8 个功能按钮以及 9 个分割按钮的分割条组成。 (6)向窗体中添加 StatusBar 控件 、CommonDialog 控件 等。 程序主窗体的设计结果如图 9.19 所示。 图 9.19 程序主窗体的设计结果 400 SQL Server 2005 数据库系统开发案例精选 2.代码设计 通过程序主窗体加载其他管理模块窗体,代码如下: //………………………………………………例程8-5……………………………………………………// Private Sub tslb_Click() ’加载图书类别设置窗体 Load main_jcxx_tslbsz main_jcxx_tslbsz.Show frm_main.Enabled = False End Sub Private Sub place_Click() ’加载图书存放位置窗体 Load main_jcxx_tswzsz main_jcxx_tswzsz.Show frm_main.Enabled = False End Sub Private Sub rlbsz_Click() ’加载读者类别设置窗体 Load main_jcxx_dzlbsz main_jcxx_dzlbsz.Show frm_main.Enabled = False End Sub Private Sub reads_Click() ’加载读者信息设置窗体 Load main_jcxx_dzxxsz main_jcxx_dzxxsz.Show frm_main.Enabled = False End Sub Private Sub xztsrk_Click() ’加载图书入库窗体 Load main_rcyw_tsrk main_rcyw_tsrk.Show frm_main.Enabled = False End Sub Private Sub rkcx_Click() ’加载入库查询窗体 Load main_rcyw_rkcx main_rcyw_rkcx.Show frm_main.Enabled = False End Sub Private Sub tsxs_Click() ’加载图书销售窗体 Load main_rcyw_tsxs main_rcyw_tsxs.Show frm_main.Enabled = False End Sub Private Sub xscx_Click() ’加载销售查询窗体 Load main_rcyw_xscx main_rcyw_xscx.Show frm_main.Enabled = False End Sub Private Sub kccx_Click() ’加载库存查询窗体 Load main_rcyw_kccx main_rcyw_kccx.Show frm_main.Enabled = False End Sub Private Sub kcsxx_Click() ’加载库存上限、下限设置窗体 Load main_rcyw_kcsxx 401 C H A P T E R 9 第 9 章 图书综合管理系统 main_rcyw_kcsxx.Show frm_main.Enabled = False End Sub Private Sub kcyj_Click() ’加载库存预警窗体 Load main_rcyw_kcyj main_rcyw_kcyj.Show frm_main.Enabled = False End Sub Private Sub js_Click() ’加载借书窗体 Load main_jygl_js main_jygl_js.Show frm_main.Enabled = False End Sub Private Sub hs_Click() ’加载还书窗体 Load main_jygl_hs main_jygl_hs.Show frm_main.Enabled = False End Sub Private Sub jscx_Click() ’加载借书查询窗体 Load main_jygl_jscx main_jygl_jscx.Show frm_main.Enabled = False End Sub Private Sub hscx_Click() ’加载还书查询窗体 Load main_jygl_hscx main_jygl_hscx.Show frm_main.Enabled = False End Sub Private Sub jscq_Click() ’加载借书超期窗体 Load main_jygl_szdqtx main_jygl_szdqtx.Show frm_main.Enabled = False End Sub Private Sub xlfx_Click() ’加载销量分析窗体 Load main_jcfx_xlfx main_jcfx_xlfx.Show frm_main.Enabled = False End Sub Private Sub jyfx_Click() ’加载借阅分析窗体 Load main_jcfx_jyfx main_jcfx_jyfx.Show frm_main.Enabled = False End Sub Private Sub kcfx_Click() ’加载库存分析窗体 Load main_jcfx_kcfx main_jcfx_kcfx.Show frm_main.Enabled = False End Sub Private Sub czy_Click() ’加载操作员设置窗体 Load main_xtgl_czysz main_xtgl_czysz.Show frm_main.Enabled = False 402 SQL Server 2005 数据库系统开发案例精选 End Sub Private Sub mmsz_Click() ’加载密码设置窗体 Load main_xtgl_mmsz main_xtgl_mmsz.Show frm_main.Enabled = False End Sub Private Sub czyjbsz_Click() ’加载操作员级别设置窗体 Load main_xtgl_czyjbsz main_xtgl_czyjbsz.Show frm_main.Enabled = False End Sub Private Sub qxsz_Click() ’加载权限管理窗体 Load main_xtgl_qxgl main_xtgl_qxgl.Show frm_main.Enabled = False End Sub Private Sub xtcsh_Click() ’加载系统初始化窗体 Load main_xtwh_xtcsh main_xtwh_xtcsh.Show frm_main.Enabled = False End Sub 9.7.5 图书类别管理 图书的内容包罗万象,涉及的信息很广泛,需要将图书分类进行管理。图书类别管理中 记录着各图书类别及联系,在窗体下拉列表框中选择添加图书类别的级别,单击工具栏中的 【添加】按钮,此时【保存】按钮变为可用状态。然后在窗体的文本框中输入图书类别的信 息,最后单击【保存】按钮保存所编辑的信息。 图书类别管理模块的运行结果如图 9.20 所示。 1.窗体设计 (1)在工程中新建一个窗体,将窗体的名称设置为“main_jcxx_tslbsz”,BorderStyle 属性设置为“1-Fixed Single”,MaxButton 属性设置为 False。 (2)在窗体上添加 TreeView 控件 ,由于该控件属于 ActiveX 控件,在使用之前必须 从“部件”对话框中添加到工具箱。添加方法如下。 在“工程”→“部件”对话框中勾选“Microsoft Windows Common Controls6.0”列表 项,单击【确定】按钮后即可将 TreeView 控件添加到工具箱当中。 (3)在窗体上添加 Adodc 控件 。 (4)在窗体上添加一个 ImageList 控件 ,并向控件内插入图片。 (5)在窗体上添加 6 个按钮控件 ,并设置 Caption 属性分别为“添加”、“修改”、“保 存”、“取消”、“删除”、“退出”。 (6)在窗体中添加一个 Frame 控件 ,在 Frame 控件上添加一个 ComboBox 控件 与 一个文本框控件 数组,通过粘贴复制的方式在 Frame 控件上添加 3 个文本框控件,名称 为 Text1(0)~Text1(2),为文本框控件与 ComboBox 控件配置标签控件,并且设置相应 的 Caption 属性值。 图书类别管理窗体的设计结果如图 9.21 所示。 403 C H A P T E R 9 第 9 章 图书综合管理系统 图 9.20 图书类别管理模块运行结果 图 9.21 图书类别管理窗体的设计结果 2.代码设计 在代码窗口的声明部分定义如下变量: //…………………………………………………例程8-6…………………………………………………// Dim i As Integer ’定义整型变量 Dim rs1 As New ADODB.Recordset ’定义数据集对象 Dim SQL As String ’定义字符串变量 在窗体启动时,除了【保存】和【取消】按钮不可用,其他按钮均可用。下面的代码 是在窗体激活时 Activate 事件过程,实现窗体在启动时加载数据、控制按钮状态的功能。 窗体激活时的事件代码: //…………………………………………………例程8-7…………………………………………………// Private Sub Form_Activate() ’添加级别列表 For i = 1 To 5 Combo1.AddItem (i) & "级" 技术细节 ComboBox 控件 ComboBox 控件将 TextBox 控件和 ListBox 控件的特性结合在一起,该控件既可以在 控件的文本框部分输入信息,也可以在控件的列表框部分选择一项。 为了添加或删除 ComboBox 控件中的项目,需要使用 AddItem 或 RemoveItem 方法。 设置 List、ListCount、和 ListIndex 属性,使访问 ComboBox 中的项目成为可能。也可以 在设计时使用 List 属性将项目添加到列表中。 1.AddItem 方法,用于向 ComboBox 控件中添加项目 语法:object.AddItem item, index 2.Clear 方法,用于清除 ComboBox 控件中的项目 语法:object.Clear 3.RemoveItem 方法,用于从 ComboBox 控件中删除一项 语法:object.RemoveItem index 4.ListCount 属性,用于返回控件的列表部分项目的个数。 语法:object.ListCount 5.ListIndex 属性,返回或设置控件中当前选择项目的索引在设计时不可用。 语法:object.ListIndex [= index] 404 SQL Server 2005 数据库系统开发案例精选 Next i Combo1.ListIndex = 0 ’打开表 rs1.Open "select * from tslbb order by 类别编号", Cnn, adOpenKeyset, adLockOptimistic If rs1.RecordCount > 0 Then For i = 1 To 3 If rs1.Fields(i) <> "" Then Text1(i).text = rs1.Fields(i) ’将字段值赋给Text1控件数组 Text1(i).Enabled = False Next i Combo1.text = rs1.Fields("级别") End If rs1.Close ’关闭表 Call Tree_change ’调用显示数据过程 CmdSave.Enabled = False CmdEsc.Enabled = False End Sub 窗体激活时调用过程 Tree_change 的事件用来显示树状数据,代码如下: //…………………………………………………例程8-8…………………………………………………// Public Sub Tree_change() ’声明一个树状显示数据的过程 On Error Resume Next Dim key, text As String rs1.Open "select * from tslbb order by 类别编号", Cnn, adOpenKeyset, adLockOptimistic If rs1.RecordCount > 0 Then  With rs1 .MoveFirst Do While .EOF = False  If Len(.Fields("类别编号")) = 2 Then  key = Trim(.Fields("类别名称")) text = "(" & Trim(.Fields("类别编号")) & ")" & Trim(.Fields("类别名称")) Set Node1 = TreeView1.Nodes.Add(, , key, text, Val(.Fields("级别"))) 技术细节 Nodes 集合中的 Add 方法: 该方法用于在 Treeview 控件的 Nodes 集合中添加一个 Node 对象。 语法: object.Add(relative, relationship, key, text, image, selectedimage) Add 方法的语法包含以下部分。 object:必需的。对象表达式,其值是“应用于”列表中的一个对象 relative:可选的。已存在的 Node 对象的索引号或键值。新节点与已存在的节点间的 关系,可在下一个参数 relationship 中找到。 relationship:可选的。指定的 Node 对象的相对位置。 key:可选的。惟一的字符串,可用于用 Item 方法检索 Node。 text:必须的。在 Node 中出现的字符串。 image:可选的。在关联的 ImageList 控件中图像的索引。 selectedimage:可选的。在关联的 ImageList 控件中图像的索引,在 Node 被选中时 显示。 relationship 的设置值如下。 tvwFirst:0 首节点。该 Node 和在 relative 中被命名的节点位于同一层,并位于所有 同层节点之前。 405 C H A P T E R 9 第 9 章 图书综合管理系统 tvwLast:1 最后的节点。该 Node 和在 relative 中被命名的节点位于同一层,并位于 所有同层节点之后。任何连续地添加的节点可能位于最后添加的节点之后 tvwNext:2(缺省)下一个节点。该 Node 位于 relative 中被命名的节点之后。 tvwPrevious:3 前一个节点。该 Node 位于 relative 中被命名的节点之前。 tvwChild:4(缺省)子节点。该 Node 成为 relative 中被命名的节点的子节点。 注意:如果在 relative 中没有被命名的 Node 对象,则新节点被放在节点顶层的最后。 End If If Len(.Fields("类别编号")) = 5 Then key = Trim(.Fields("类别名称")) text = "(" & Trim(.Fields("类别编号")) & ")" & Trim(.Fields("类别名称")) Set Node2 = TreeView1.Nodes.Add(Node1.Index, tvwChild, key, text, Val(.Fields("级别"))) End If If Len(.Fields("类别编号")) = 9 Then key = Trim(.Fields("类别名称")) text = "(" & Trim(.Fields("类别编号")) & ")" & Trim(.Fields("类别名称")) Set Node3 = TreeView1.Nodes.Add(Node2.Index, tvwChild, key, text, Val(.Fields("级别"))) End If If Len(.Fields("类别编号")) = 14 Then key = Trim(.Fields("类别名称")) text = "(" & Trim(.Fields("类别编号")) & ")" & Trim(.Fields("类别名称")) Set Node4 = TreeView1.Nodes.Add(Node3.Index, tvwChild, key, text, Val(.Fields("级别"))) End If If Len(.Fields("类别编号")) = 20 Then key = Trim(.Fields("类别名称")) text = "(" & Trim(.Fields("类别编号")) & ")" & Trim(.Fields("类别名称")) Set Node5 = TreeView1.Nodes.Add(Node4.Index, tvwChild, key, text, Val(.Fields("级别"))) End If .MoveNext Loop End With End If rs1.Close End Sub  代码导读  With 语句:用于在 rs1 对象上执行一系列语句。  Len 函数:返回 Long 型的值,其中包含字符串内字符的数目,或是存储一变量所 需的字节数。  Trim 函数:返回 Variant(String) 型的值,其中包含指定字符串的拷贝, 没有前导 和尾随空白。 单击【保存】按钮,通过 CmdSave_Click 事件过程,完成添加或修改的信息保存操作, 实现的代码如下: //…………………………………………………例程8-9…………………………………………………// Private Sub CmdSave_Click() ’保存图书类别信息 If Combo1.text = "" Then MsgBox "系统不允许【级别】为空!" 406 SQL Server 2005 数据库系统开发案例精选 Exit Sub End If If Text1(1).text = "" Then MsgBox "系统不允许【本级编号】为空!" Exit Sub End If If Text1(2).text = "" Then MsgBox "系统不允许【类别编号】为空!" Exit Sub End If If Text1(3).text = "" Then MsgBox "系统不允许【类别名称】为空!" Exit Sub End If Adodc2.RecordSource = "select * from tslbb where 类别编号=’" + Text1(2).text + "’" Adodc2.Refresh If Adodc2.Recordset.RecordCount > 0 Then ’修改原有数据 Cnn.Execute ("update tslbb set 类别名称=’" + Text1(3).text + "’ where 类别编号=’" + Text1(2). text + "’") Else ’添加图书类别信息 Adodc2.Recordset.AddNew For i = 1 To 3 Adodc2.Recordset.Fields(i) = Trim(Text1(i).text) Text1(i).Enabled = False Next i Adodc2.Recordset.Fields("级别") = Combo1.text Adodc2.Recordset.Update ’更新数据库 End If Adodc2.Recordset.Close ’关闭数据集对象 TreeView1.Nodes.Clear Call Tree_change ’调用函数 ’设置控件状态 CmdSave.Enabled = False CmdEsc.Enabled = False CmdAdd.Enabled = True CmdDelete.Enabled = True End Sub 通过公共模块(Module1)中声明的 cnn()函数执行 SQL 语句删除相应类别,代码 如下: //………………………………………………例程8-10………………………………………………// Private Sub CmdDelete_Click() ’删除图书类别信息 Dim rs2 As New ADODB.Recordset rs1.Open "select * from tslbb where 类别名称=’" + Text1(3).text + "’order by 类别编号", Cnn rs2.Open "select * from tslbb where 类别编号 like ’" + Text1(2).text + "’+’0%’ order by 类别编号 ", Cnn, adOpenKeyset, adLockOptimistic Dim con As New ADODB.Connection If rs2.RecordCount > 1 Then MsgBox "请先删除其子类,再删除该父类", , "图书综合管理系统" Else con.ConnectionString = Cnn With rs1 If .RecordCount > 0 Then a = MsgBox("您确实要删除这条数据吗?", vbYesNo) 407 C H A P T E R 9 第 9 章 图书综合管理系统 If a = vbYes Then con.Open con.Execute "delete from tslbb where 类别名称=’" + Text1(3).text + "’" con.Close Adodc1.RecordSource = "select * from tslbb order by 类别编号" Adodc1.Refresh For i = 1 To 3 Text1(i).text = Adodc1.Recordset.Fields(i) ’将字段值赋给Text1控件数组 Next i Combo1.text = Adodc1.Recordset.Fields("级别") ’设置按钮有效或无效 CmdSave.Enabled = False CmdEsc.Enabled = False CmdAdd.Enabled = True CmdDelete.Enabled = True End If Else MsgBox ("没有要删除的数据!") End If End With End If rs1.Close rs2.Close TreeView1.Nodes.Clear ’清空TreeView中的数据 Call Tree_change ’调用过程 End Sub 9.7.6 读者信息管理 读者信息管理主要完成读者信息的添加、修改、删除与查询等操作。 读者信息管理模块的运行结果如图 9.22 所示。 图 9.22 读者信息管理模块运行结果 1.窗体设计 (1)在工程中新建一个窗体,将窗体的名称设置为“main_jcxx_dzxxsz”,BorderStyle 属性设置为“1-Fixed Single”,MaxButton 属性设置为 False。 (2)在窗体上添加一个 Adodc 控件 、一个 CommonDialog 控件 、一个 SSTab 控件 。主要控件对象的属性如表 9.8 所示。 408 SQL Server 2005 数据库系统开发案例精选 表 9.8 主要控件对象的属性列表 对 象 属 性 值 DataGrid1 DataSource Adodc1 Caption 读者基本信息、读者列表 Tab 0、1 Tabs 2 SSTab1 TabsPerRow 2 名称 CmdMD Command1 Index 0-3 名称 CmdAdd Command2 Caption 添加 名称 CmdDelete Command3 Caption 删除 名称 CmdSave Command4 Caption 保存 名称 CmdEsc Command5 Caption 取消 名称 CmdExit Command6 Caption 退出 (3)在窗体中添加的控件如图 9.23 所示。 图 9.23 读者信息管理的设计界面 2.代码设计 在代码窗口的声明部分定义如下变量: //…………………………………………………例程8-11…………………………………………………// Dim i, a, Mat As Integer ’声明整型变量 Dim rs1 As New ADODB.Recordset ’声明数据集对象 Dim mst As New ADODB.Stream Dim con As New ADODB.Connection 在窗体加载时,使用数据集对象的 cnn()函数连接到数据库上。将数据表中相应字 段的数据添加到 ComboBox 控件中。 409 C H A P T E R 9 第 9 章 图书综合管理系统 窗体加载时的事件代码如下: //…………………………………………………例程8-12…………………………………………………// Private Sub Form_Load() Adodc1.ConnectionString = Cnn ’添加读者类别列表 rs1.Open "select 类别名称 from dzlbb ", Cnn, adOpenKeyset, adLockOptimistic If rs1.RecordCount > 0 Then If rs1.BOF = False Then rs1.MoveFirst For i = 0 To rs1.RecordCount - 1 Combo2.AddItem (Trim(rs1.Fields("类别名称"))) rs1.MoveNext Next i End If rs1.Close If Combo2.ListCount > 0 Then Combo2.ListIndex = 0 ’添加性别列表 Combo1.AddItem ("男") Combo1.AddItem ("女") Combo1.ListIndex = 1 ’添加查询字段列表 Combo3.AddItem ("书证号") Combo3.AddItem ("姓名") Combo3.AddItem ("身份证") Combo3.AddItem ("单位") Combo3.AddItem ("读者类别") Combo3.AddItem ("期限") Combo3.ListIndex = 0 ’添加借书期限列表 Combo4.AddItem ("一年") Combo4.AddItem ("半年") Combo4.AddItem ("三个月") Adodc1.RecordSource = "select * from reads" Adodc1.Refresh If Adodc1.Recordset.RecordCount > 0 Then Call view_data ’调用函数 End If End Sub 在窗体加载中调用的 view_data 函数用来显示读者信息数据,函数代码如下: //…………………………………………………例程8-13…………………………………………………// Private Sub view_data() ’声明一个显示reads表中数据的过程 With Adodc1.Recordset ’将reads数据表中各字段的值赋给对应的控件 If .RecordCount > 0 Then If .Fields("书证号") <> "" Then Text1.text = .Fields("书证号") If .Fields("姓名") <> "" Then Text2.text = .Fields("姓名") If .Fields("性别") <> "" Then Combo1.text = .Fields("性别") If .Fields("身份证") <> "" Then Text3.text = .Fields("身份证") If .Fields("单位") <> "" Then Text4.text = .Fields("单位") If .Fields("家庭住址") <> "" Then Text5.text = .Fields("家庭住址") Else Text5.text = "" If .Fields("联系电话") <> "" Then Text6.text = .Fields("联系电话") Else Text6.text = "" If .Fields("读者类别") <> "" Then Combo2.text = .Fields("读者类别") If .Fields("收费标准") <> "" Then Label3.Caption = .Fields("收费标准") If .Fields("期限") <> "" Then Combo4.text = .Fields("期限") 410 SQL Server 2005 数据库系统开发案例精选 If .Fields("办证价格") <> "" Then Label4.Caption = .Fields("办证价格") If .Fields("办证日期") <> "" Then DTPicker1.Value = .Fields("办证日期") If .Fields("到期日期") <> "" Then DTPicker2.Value = .Fields("到期日期") If .Fields("已借书数") <> "" Then jss.Caption = .Fields("已借书数") ’显示数据库中的相片 Set Picture1.DataSource = Adodc1 Picture1.DataField = "相片路径" Image1.Picture = Picture1.Picture If .Fields("相片路径") Is Nothing Then Picture1.Picture = LoadPicture() MsgBox "此读者相片错误,请更改!" Picture1.Picture = LoadPicture("") End If End If End With End Sub 单击【保存】按钮,则调用【保存】按钮的单击事件过程保存录入的读者基本数据信 息,在保存信息的时候,首先要判断是添加信息的保存还是修改信息的保存,代码如下: //…………………………………………………例程8-14…………………………………………………// Private Sub CmdSave_Click() If a = 0 Then ’判断是添加信息的保存还是修改信息的保存。当变量a=0时为添加信息的保存 ’判断是否有填写不完整的读者信息项 If Text2.text = "" And Combo1.text ="And Text3.text =""And Text4.text = "" And Combo2.text = "" Then 技术细节 If…Then 语句 If…Then 语句表示“如果⋯就”,是条件转移语句,根据条件测试后的结果,决 定程序的下一步。 语法 If 条件 Then 语句 或者: If 条件 Then 语句块 End If 其中,条件(表达式)的值应为 Boolean(布尔型)。若条件为 True,则执行 Then 关键字后的语句块;否则,直接执行下一条语句或“End If”的下一条语句。若条件的值 为数值,则当值为零是 False,而任何非零数值看作 True。 MsgBox ("请输入读者详细信息!") Exit Sub End If  If Picture1.Picture = LoadPicture("") Then MsgBox ("请输入读者相片!")  Exit Sub End If With Adodc1.Recordset ’添加读者信息到reads表中 .AddNew mst.Type = adTypeBinary mst.Open 411 C H A P T E R 9 第 9 章 图书综合管理系统  mst.LoadFromFile CDialog1.FileName .Fields("书证号") = Text1.text .Fields("姓名") = Text2.text .Fields("性别") = Combo1.text .Fields("身份证") = Text3.text .Fields("单位") = Text4.text .Fields("家庭住址") = Text5.text .Fields("联系电话") = Text6.text .Fields("读者类别") = Combo2.text .Fields("收费标准") = Val(Label3.Caption) .Fields("期限") = Combo4.text .Fields("办证价格") = Val(Label4.Caption) .Fields("办证日期") = DTPicker1.Value .Fields("到期日期") = DTPicker2.Value ’保存相片数据 .Fields("相片路径") = mst.Read .Fields("已借书数") = 0 mst.Close .Update ’更新数据表 End With a = 2 ’设置变量a=2  Call Ena ’调用设置控件有效或无效的过程 ElseIf a = 1 Then ’当变量a=1时为修改信息的保存 Adodc1.Recordset.Close Adodc1.Recordset.Open "select * from reads where 书证号=’" + Text1.text + "’", Cnn, adOpenKeyset, adLockOptimistic Myval = MsgBox("是否要修改此记录?", vbYesNo, "修改窗口") If Myval = vbYes Then With Adodc1.Recordset .Fields("书证号") = Text1.text .Fields("姓名") = Text2.text .Fields("性别") = Combo1.text .Fields("身份证") = Text3.text .Fields("单位") = Text4.text .Fields("家庭住址") = Text5.text .Fields("联系电话") = Text6.text .Fields("读者类别") = Combo2.text .Fields("收费标准") = Val(Label3.Caption) .Fields("期限") = Combo4.text .Fields("办证价格") = Val(Label4.Caption) .Fields("办证日期") = DTPicker1.Value .Fields("到期日期") = DTPicker2.Value mst.Type = adTypeBinary mst.Open ’更新相片 If CDialog1.FileName <> "" Then mst.LoadFromFile CDialog1.FileName .Fields("相片路径") = mst.Read End If .Update ’更新数据库 End With MsgBox "修改数据成功!" Adodc1.Refresh a = 2 412 SQL Server 2005 数据库系统开发案例精选 Call Ena End If mst.Close End If End Sub  代码导读  LoadPicture 函数:将图形载入到 Picture1 的 Picture 属性。  Exit Sub:立即从 CmdSave_Click()过程中退出。程序会从 CmdSave_Click()过程语 句之后的语句继续执行。  FileName 属性:返回所选文件的路径和文件名。  Call 语句:将控制权转移到 Ena 过程。 单击【删除】按钮,则调用【删除】按钮单击事件过程删除相应的读者数据信息,代 码如下: //…………………………………………………例程8-15………………………………………………// Private Sub CmdDelete_Click() ’删除读者信息 If Adodc1.Recordset.RecordCount > 0 Then a = MsgBox("您确实要删除这条数据吗?", vbYesNo) If a = vbYes Then ’删除当前记录 Adodc1.Recordset.Delete Adodc1.Recordset.Update If Adodc1.Recordset.EOF = False Then Adodc1.Recordset.MoveNext Else Adodc1.Recordset.MoveFirst End If Call view_data ’调用显示reads表中数据的过程 ’设置按钮有效或无效 CmdSave.Enabled = False CmdEsc.Enabled = False CmdAdd.Enabled = True CmdModify.Enabled = True For i = 0 To 3 CmdMD(i).Enabled = True Next i End If End If End Sub 9.7.7 入库管理 通过入库管理向数据库中添加新的图书信息,并将图书入库。一般情况下在进行图 书入库时,都会同时有几十种或更多的图书同时入库,若每次只能进行一种图书的入库, 显然会影响工作效率,而本模块在设计时充分考虑到这点,采用了批量入库的方式进行 设计。 并且提供了图书的筛选功能,即输入相应书号返回与该书号相同的图书,以供操作员 选择,大大提高了图书入库的效率。 入库管理模块的运行结果如图 9.24 所示。 413 C H A P T E R 9 第 9 章 图书综合管理系统 图 9.24 入库管理窗体的运行结果 1.窗体设计 (1)在工程中新建一个窗体,将窗体的名称设置为“main_rcyw_tsrk”,BorderStyle 属 性设置为“1-Fixed Single”,MaxButton 属性设置为 False。 (2)在窗体上添加 MSFlexGrid 控件 ,由于该控件属于 ActiveX 控件,在使用之前必 须从“部件”对话框中添加到工具箱。添加方法如下。 在“工程”→“部件”对话框中勾选“Microsoft FlexGrid Control 6.0 (SP3)”列表项, 单击【确定】按钮之后即可将 Adodc 控件添加到工具箱当中。 (3)在 main_rcyw_tsrk 窗体中放置 Adodc、DataGrid、MSFlexGrid、ComboBox、Label、 TextBox 和 CommandButton 等控件。主要控件对象的属性如表 9.9 所示。 表 9.9 主要控件对象的属性列表 对 象 属 性 值 ConnectionString DSN=NBooks RecordSource select * from kcb Adodc1 Visible False ConnectionString DSN=NBooks RecordSource select * from rkb Adodc2 Visible False ConnectionString DSN=NBooks RecordSource select * from kcb Adodc3 Visible False 名称 Grid DataGrid1 DataSource Adodc1 MSFlexGrid1 名称 MS1 Text1 Enabled False Text2 名称 jsr Label5 名称 PH Label6 名称 rq Label7 名称 pz 414 SQL Server 2005 数据库系统开发案例精选 续表 对 象 属 性 值 Label8 名称 hjsl Label9 名称 hjje 名称 CmdReg Command1 Caption &D 登记 名称 CmdSave Command2 Caption &S 保存 名称 CmdEsc Command3 Caption &C 取消 名称 CmdEnd Command4 Caption &E 退出 入库管理窗体的设计结果如图 9.25 所示。 图 9.25 入库管理窗体的设计结果 2.代码设计 在代码窗口的声明部分定义如下变量。 //…………………………………………………例程8-16…………………………………………………// Dim s, Y, i ’声明变量 ’声明数据集对象 Dim rs1 As New ADODB.Recordset Dim rs2 As New ADODB.Recordset Dim rs3 As New ADODB.Recordset Dim lsph As Integer ’声明一个整型变量 图书入库采取表格进行多行数据添加,在添加数据之前,需要设置 MSFlexGrid 表格的 列宽、表头信息等,通过窗体加载时的事件实现,具体代码如下: //…………………………………………………例程8-17…………………………………………………// Private Sub Form_Load() ’定义连接 Adodc1.ConnectionString = "DSN=NBooks" Adodc1.RecordSource = "select * from kcb" Adodc1.Refresh Adodc2.ConnectionString = "DSN=NBooks" 415 C H A P T E R 9 第 9 章 图书综合管理系统 Adodc2.RecordSource = "select * from rkb" Adodc2.Refresh Adodc3.ConnectionString = "DSN=NBooks" Adodc3.RecordSource = "select * from kcb" Adodc3.Refresh ’定义MS1表的行数、列数 MS1.Rows = 102 MS1.Cols = 12 ’定义MS1表的列宽和表头信息 s = Array("300", "800", "700", "2600", "800", "700", "1000", "800", "800", "600", "800", "800", "800") Y = Array("xh", "书号", "条形码", "书名", "作者", "出版社", "版 次", "类别", "存放位置", "单 价", "入库数量", "金额") For i = 0 To 11 MS1.ColWidth(i) = s(i) MS1.TextMatrix(0, i) = Y(i) Next i ’定义MS1表的行号 For i = 1 To 101 MS1.TextMatrix(i, 0) = i Next i rq.Caption = Date ’设置入库日期 ’添加图书类别列表 Set rs1 = New ADODB.Recordset ’ 打开连接对象 rs1.Open "select 类别名称 from tslbb group by 类别名称", Cnn, adOpenKeyset, adLockOptimistic If rs1.BOF = False Then rs1.MoveFirst For i = 0 To rs1.RecordCount - 1 Combo1.AddItem (Trim(rs1.Fields("类别名称"))) ’Trim 函数返回 Variant (String),其中包含指定字符串的拷贝,没有前导和尾随空白 rs1.MoveNext Next i rs1.Close ’关闭对象 ’添加图书存放位置列表 Set rs2 = New ADODB.Recordset ’打开对象连接 rs2.Open "select 存放位置 from tswzb group by 存放位置", Cnn, adOpenKeyset, adLockOptimistic If rs2.BOF = False Then rs2.MoveFirst For i = 0 To rs2.RecordCount - 1 Combo2.AddItem (Trim(rs2.Fields("存放位置"))) rs2.MoveNext Next i rs2.Close ’关闭对象 jsr.Enabled = False MS1.Enabled = False End Sub 技术细节 MSFlexGrid 控件是一种 Active 控件。它具有只读数据绑定、对表格数据进行显示和操 作、数据分组排序、Data 控件赋值、文本自动换行等功能。MsflexGrid 控件的常用属性: MSFlexGrid1.Text 设置一个单元或一定范围单元的文本内容。 MSFlexGrid1.Rows 设置 MSFlexGrid1 的行数 MSFlexGrid1.Cols 设置 MSFlexGrid1 的列数 MSFlexGrid1.ColWidth(i) 设置 MSFlexGrid1 的第 i 列列宽 416 SQL Server 2005 数据库系统开发案例精选 MSFlexGrid1.FixedRows 设置 MSFlexGrid1 的固定行数 MSFlexGrid1.FixedCols 设置 MSFlexGrid1 的固定列数 MSFlexGrid1.TextMatrix(i, j) 设置 MSFlexGrid1 第 i 行第 j 列的单元格 MSFlexGrid1.ColPos(MSFlexGrid1.col) 光标所在单元格 查询书号类似的图书信息过程事件的代码如下: //…………………………………………………例程8-18………………………………………………// Private Sub Text1_Change() MS1.text = text1.text ’赋值给MS1.text If MS1.Col = 1 Then ’按书号查询库存图书信息 Adodc1.RecordSource = "select * from kcb where 书号 like +’" + text1.text + "’+’%’" Adodc1.Refresh If text1.text = "" Then ’当text1.text为空时 Grid1.Visible = False ’Grid1不可见 Else If Adodc1.Recordset.RecordCount > 0 Then ’当记录大于零时 Grid1.Visible = True ’Grid1可见 text1.Visible = True text1.SetFocus Else Grid1.Visible = False End If End If End If If MS1.Col = 9 Then MS1.TextMatrix(MS1.Row, 11) = Val(MS1.TextMatrix(MS1.Row, 9)) * Val(MS1. TextMatrix(MS1.Row, 10)) ’Val 函数返回包含于字符串内的数字,字符串中是一个适当类型的数值。 If MS1.Col = 10 Then MS1.TextMatrix(MS1.Row, 11) = Val(MS1.TextMatrix(MS1.Row, 9)) * Val(MS1. TextMatrix(MS1.Row, 10)) If MS1.Col = 7 Then text1.Visible = False Combo1.Visible = True Combo1.Width = MS1.CellWidth Combo1.Left = MS1.CellLeft + MS1.Left Combo1.Top = MS1.CellTop + MS1.Top Combo1.SetFocus End If Dim a, B As Single For i = 1 To 101 a = Val(MS1.TextMatrix(i, 11)) + a B = Val(MS1.TextMatrix(i, 10)) + B If MS1.TextMatrix(i, 1) <> "" And MS1.TextMatrix(i, 10) <> "" Then pz.Caption = i Next i ’计算合计金额,合计数量 hjje.Caption = a ’计算合计金额 hjsl.Caption = B ’计算合计数量 End Sub 将所查询到的图书信息添加到 MSFlexGrid 表格中与查看其他类似图书信息时的事件 代码如下: //…………………………………………………例程8-19…………………………………………………//  Private Sub Text1_KeyDown(KeyCode As Integer, Shift As Integer)  If KeyCode = vbKeyReturn Then ’按回车键 417 C H A P T E R 9 第 9 章 图书综合管理系统 text1.text = MS1.text Adodc3.RecordSource = "select * from kcb where 条形码=’" + MS1.TextMatrix(MS1.Row, 2) + "’" Adodc3.Refresh  If Adodc3.Recordset.RecordCount > 0 Then ’当记录大于零时 If MS1.Col = 2 Then With Adodc3.Recordset ’赋值给MS1表格 If .Fields("书号") <> "" Then MS1.TextMatrix(MS1.Row, 1) = .Fields("书号") If .Fields("条形码") <> "" Then MS1.TextMatrix(MS1.Row, 2) = .Fields("条形码") If .Fields("书名") <> "" Then MS1.TextMatrix(MS1.Row, 3) = .Fields("书名") If .Fields("作者") <> "" Then MS1.TextMatrix(MS1.Row, 4) = .Fields("作者") If .Fields("出版社") <> "" Then MS1.TextMatrix(MS1.Row, 5) = .Fields("出版社") If .Fields("图书类别") <> "" Then MS1.TextMatrix(MS1.Row, 7) = .Fields("图书类别") If .Fields("存放位置") <> "" Then MS1.TextMatrix(MS1.Row, 8) = .Fields("存放位置") If .Fields("单价") <> "" Then MS1.TextMatrix(MS1.Row, 9) = .Fields("单价") text1.text = MS1.text MS1.Col = 6 Grid1.Visible = False  text1.SetFocus End With End If End If If Adodc1.Recordset.RecordCount > 0 Then ’当记录大于零时 If MS1.Col = 1 Then With Adodc1.Recordset ’赋值给MS1表格 If .Fields("书号") <> "" Then MS1.TextMatrix(MS1.Row, 1) = .Fields("书号") If .Fields("条形码") <> "" Then MS1.TextMatrix(MS1.Row, 2) = .Fields("条形码") If .Fields("书名") <> "" Then MS1.TextMatrix(MS1.Row, 3) = .Fields("书名") If .Fields("作者") <> "" Then MS1.TextMatrix(MS1.Row, 4) = .Fields("作者") If .Fields("出版社") <> "" Then MS1.TextMatrix(MS1.Row, 5) = .Fields("出版社") If .Fields("图书类别") <> "" Then MS1.TextMatrix(MS1.Row, 7) = .Fields("图书类别") If .Fields("存放位置") <> "" Then MS1.TextMatrix(MS1.Row, 8) = .Fields("存放位置") If .Fields("单价") <> "" Then MS1.TextMatrix(MS1.Row, 9) = .Fields("单价") MS1.Col = 6 text1.text = MS1.text text1.SetFocus End With End If If MS1.Col = 6 Then MS1.Col = 9 If MS1.Col = 10 Then MS1.Row = MS1.Row + 1 MS1.Col = 1 Else If MS1.Col + 1 <= MS1.Cols - 1 Then MS1.Col = MS1.Col + 1 Else If MS1.Row + 1 <= MS1.Rows - 1 Then MS1.Row = MS1.Row + 1 MS1.Col = 1 End If End If End If Else If MS1.Col = 10 Then MS1.Row = MS1.Row + 1 418 SQL Server 2005 数据库系统开发案例精选 MS1.Col = 1 Else If MS1.Col + 1 <= MS1.Cols - 1 Then MS1.Col = MS1.Col + 1 Else If MS1.Row + 1 <= MS1.Rows - 1 Then MS1.Row = MS1.Row + 1 MS1.Col = 1 End If End If End If End If End If If KeyCode = vbKeyUp Then ’按KeyUp键 If MS1.Row > 1 Then MS1.Row = MS1.Row - 1 End If If KeyCode = vbKeyDown And (MS1.TextMatrix(MS1.Row, 1)) <> "" Then ’按KeyDown键 If MS1.Row < 99 Then MS1.Row = MS1.Row + 1 End If If KeyCode = vbKeyLeft Then ’按KeyLeft键 If text1.text <> "" Then text1.SelStart = 0 text1.SelLength = Len(text1.text) ’Len 函数返回 Long,其中包含字符串内字符的数目,或是存储一变量所需的字节数。 End If If MS1.Col - 10 <= MS1.Cols + 1 Then MS1.Col = MS1.Col - 1 If MS1.Col = 0 Then MS1.Col = 1 Else If MS1.Row + 1 <= MS1.Row - 1 Then MS1.Row = MS1.Row + 1 MS1.Col = 1 End If End If End If If KeyCode = vbKeyRight Then ’按KeyRight键 If text1.text <> "" Then text1.SelStart = 0 text1.SelLength = Len(text1.text) End If If MS1.Col + 1 <= MS1.Cols - 1 Then MS1.Col = MS1.Col + 1 Else If MS1.Row + 1 <= MS1.Rows - 1 Then MS1.Row = MS1.Row + 1 MS1.Col = 1 End If End If End If If KeyCode = vbKeyPageDown And MS1.Col = 1 Then ’按KeyPageDown 键 Adodc1.RecordSource = "select * from kcb" Adodc1.Refresh Grid1.Visible = True Grid1.SetFocus End If End Sub 419 C H A P T E R 9 第 9 章 图书综合管理系统  代码导读  KeyDown 事件:当 Text1 具有焦点时,按下键盘上的注意一个键时发生。  vbKeyReturn:键码常数,代表键盘上的键。  RecordCount:指示 Adodc3 的 Recordset 对象中当前记录数目。  SetFocus 方法:将焦点移至 text1 控件。 单击【登记】按钮时自动生成入库票号过程事件的代码如下: //…………………………………………………例程8-20…………………………………………………// Private Sub CmdReg_Click() ’登记 ’查询所有入库数据,并按票号排序 Adodc2.RecordSource = "select * from rkb order by 票号" Adodc2.Refresh ’创建入库票号 If Adodc2.Recordset.RecordCount > 0 Then ’当记录数大于零 If Not Adodc2.Recordset.EOF Then Adodc2.Recordset.MoveLast If Adodc2.Recordset.Fields("票号") <> "" Then lsph = Right(Trim(Adodc2.Recordset.Fields("票号")), 4) + 1 ’Right 函数返回 Variant (String),其中包含从字符串右边取出的指定数量的字符。 ’Trim 函数返回 Variant (String),其中包含指定字符串的拷贝,没有前导和尾随空白(Trim)。 PH.Caption = Date & "rk" & Format(lsph, "0000") End If Else PH.Caption = Date & "rk" & "0001" End If ’设置jsr有效 jsr.Enabled = True ’jsr获得焦点 jsr.SetFocus text1.Enabled = True MS1.Enabled = True ’确定文本框在MS1表格中的位置 text1.Width = MS1.CellWidth text1.Height = MS1.CellHeight text1.Left = MS1.CellLeft + MS1.Left text1.Top = MS1.CellTop + MS1.Top ’设置按钮有效或无效 CmdSave.Enabled = True CmdCancel.Enabled = True CmdReg.Enabled = False MS1.Enabled = True jsr.Enabled = True End Sub 9.7.8 入库查询 入库查询实现的是对图书入库信息的查询、删除及打印等操作。通过指定条件查询到 相应的入库信息,可将这些信息打印出来,也可以将选定的信息删除掉。 入库查询模块的运行结果如图 9.26 所示。 1.窗体设计 (1)在工程中新建一个窗体,将窗体的名称设置为“main_rcyw_rkcx”,BorderStyle 属 性设置为“1-Fixed Single”,MaxButton 属性设置为 False。 420 SQL Server 2005 数据库系统开发案例精选 图 9.26 入库查询模块运行结果 (2)在窗体中放置 Adodc 、DataGrid 、TextBox 、DTPicker 、CheckBox 、 ComboBox 、Label 和 CommandButton 等控件。主要控件对象的属性如表 9.10 所示。 表 9.10 主要控件对象的属性列表 对 象 属 性 值 ConnectionString DSN=NBooks RecordSource select * from rkb Adodc1 Adodc2 Visible False DataGrid1 DataSource Adodc1 DTPicker1 名称 DTP1 DTPicker2 名称 DTP2 Label3 名称 pz Label4 名称 sl Label5 名称 je 名称 CmdFind Command1 Caption &F 查询 名称 CmdDelete Command2 Caption &D 删除 名称 CmdPrint Command3 Caption &P 打印 名称 CmdEnd Command4 Caption &E 退出 入库查询窗体的设计结果如图 9.27 所示。 图 9.27 入库查询窗体的设计结果 421 C H A P T E R 9 第 9 章 图书综合管理系统 2.代码设计 当窗体启动时,设置 Ado 控件连接到数据库,并为 ComboBox 控件添加查询字段名称, 以及指定 DTPicker 控件中显示的日期。实现代码如下: //………………………………………………例程8-21……………………….…………………………// Private Sub Form_Load() Adodc1.ConnectionString = "DSN=NBooks" Adodc1.RecordSource = "select * from rkb" Adodc1.Refresh Adodc2.ConnectionString = "DSN=NBooks" Adodc2.RecordSource = "select * from rkb" Adodc2.Refresh ’添加字段列表 Combo1.AddItem ("书号") Combo1.AddItem ("条形码") Combo1.AddItem ("书名") Combo1.AddItem ("作者") Combo1.AddItem ("出版社") Combo1.AddItem ("版次") Combo1.AddItem ("图书类别") Combo1.AddItem ("存放位置") Combo1.AddItem ("票号") Combo1.AddItem ("操作员") Combo1.AddItem ("经手人") Combo1.ListIndex = 0 ’添加查询条件列表 Combo2.AddItem ("like") Combo2.AddItem ("=") Combo2.ListIndex = 0 ’设置查询日期 DTP1.Value = Date - 10 DTP2.Value = Date CmdFind_Click End Sub 单击【查询】按钮,查询符合条件的信息,实现的具体代码如下: //………………………………………………例程8-22…………………………………………………// Private Sub CmdFind_Click() ’查询 Select Case Combo2.text Case Is = "like" If Check1.Value = 0 And Check2.Value = 1 Then Adodc1.RecordSource = "select * from rkb where rkb." + Combo1.text + " like +’%’+’" + Text1.text + "’+’%’order by 票号" Adodc1.Refresh Adodc2.RecordSource = "select count(*)as 品种,sum(入库数量)as 合计数量,sum(金 额)as 合计金额 from rkb where rkb." + Combo1.text + " like ’%" + Text1.text + "%’" Adodc2.Refresh Call viewdata End If If Check1.Value = 1 And Check2.Value = 0 Then Adodc1.RecordSource = "Select * from rkb where 日期 between ’" + Str(DTP1.Value) + "’ and ’" + Str(DTP2.Value) + "’ order by 票号" ’Str 函数返回代表一数值的 Variant (String)。 Adodc1.Refresh Adodc2.RecordSource = "select count(*)as 品种,sum(入库数量)as 合计数量,sum(金 422 SQL Server 2005 数据库系统开发案例精选 额)as 合计金额 from rkb where 日期 between ’" + Str(DTP1.Value) + "’ and ’" + Str(DTP2.Value) + "’" Adodc2.Refresh Call viewdata End If If Check1.Value = 1 And Check2.Value = 1 Then Adodc1.RecordSource = "select * from rkb where rkb." & Combo1.text & " " & " like+ ’%’+’" + Text1.text + "’+’%’and 日期 between ’" + Str(DTP1.Value) + "’ and ’" + Str(DTP2.Value) + "’ order by 票号" Adodc1.Refresh Adodc2.RecordSource = "select count(*)as 品种,sum(入库数量)as 合计数量,sum(金 额)as 合计金额 from rkb where rkb." & Combo1.text & " " & "like +’%" + Text1.text + "%’and 日期 between ’" + Str(DTP1.Value) + "’ and ’" + Str(DTP2.Value) + "’" Adodc2.Refresh Call viewdata End If Case Is = "=" If Check1.Value = 0 And Check2.Value = 1 Then Adodc1.RecordSource = "select * from rkb where rkb." & Combo1.text & " " & "= ’" + Text1.text + "’order by 票号" Adodc1.Refresh Adodc2.RecordSource = "select count(*)as 品种,sum(入库数量)as 合计数量,sum(金 额)as 合计金额 from rkb where rkb." & Combo1.text & " " & "=’" + Text1.text + "’" Adodc2.Refresh Call viewdata End If If Check1.Value = 1 And Check2.Value = 1 Then Adodc1.RecordSource = "select * from rkb where rkb." & Combo1.text & " " & " =’" + Text1.text + "’and 日期 between ’" + Str(DTP1.Value) + "’and ’" + Str(DTP2.Value) + "’ order by 票号" Adodc1.Refresh Adodc2.RecordSource = "select count(*)as 品种,sum(入库数量)as 合计数量,sum(金 额)as 合计金额 from rkb where rkb." & Combo1.text & " " & "=’" + Text1.text + "’and 日期 between ’" + Str (DTP1.Value) + "’ and ’" + Str(DTP2.Value) + "’" Adodc2.Refresh Call viewdata End If End Select End Sub 技术细节 Select Case 判定语句 语法 Select Case testexpression [Case expressionlist1 [statementblock-1]] [Case expressionlist2 [statementblock-2]] [Case Else [statementblock-n]] End Select 每一个 expressionlist 是一个或几个值的列表。如果在一个列表中有多个值,就用逗号 把值隔开。每一个 statementblock 中含有零个或多个语句。如果不止一个 Case 测试表达式 相匹配,则只对第一个匹配的 Case 执行与之相关联的语句块。如果在表达式列表中没有一 个值与测试表达式相匹配,则 Visual Basic 执行 Case Else 子句(此项是可选的)中的语句。 423 C H A P T E R 9 第 9 章 图书综合管理系统 查询时调用的 viewdata()过程,事件代码如下: //…………………………………………………例程8-23…………………………………………………// Private Sub viewdata() ’声明显示入库品种、入库数量、入库金额的过程 With Adodc2.Recordset If .Fields(0) <> "" Then pz.Caption = .Fields(0) Else pz.Caption = "0" If .Fields(1) <> "" Then sl.Caption = .Fields(1) Else sl.Caption = "0" If .Fields(2) <> "" Then je.Caption = Format(.Fields(2), "0.00") Else je.Caption = "0.00" ’Format 函数返回 Variant (String),其中含有一个表达式,它是根据格式表达式中的指令 来格式化的。 End With End Sub 单击【打印】按钮将所查询的信息进行打印,实现的具体代码如下: //………………………………………………例程8-24…………………………………………………// Private Sub CmdPrint_Click() ’打印 Select Case Combo2.text Case Is = "like" If Check1.Value = 0 And Check2.Value = 1 Then DataE1.rsCommand2.Open "select * from rkb where rkb." + Combo1.text + " like +’%’+’" + Text1.text + "’+’%’order by 票号" End If If Check1.Value = 1 And Check2.Value = 0 Then DataE1.rsCommand2.Open "Select * from rkb where 日期 between ’" + Str(DTP1.Value) + "’ and ’" + Str(DTP2.Value) + "’ order by 票号" End If If Check1.Value = 1 And Check2.Value = 1 Then DataE1.rsCommand2.Open "select * from rkb where rkb." & Combo1.text & " " & " like +’%’+’" + Text1.text + "’+’%’and 日期 between ’" + Str(DTP1.Value) + "’ and ’" + Str(DTP2.Value) + "’ order by 票号" End If Case Is = "=" If Check1.Value = 0 And Check2.Value = 1 Then DataE1.rsCommand2.Open "select * from rkb where rkb." & Combo1.text & " " & "= ’" + Text1.text + "’order by 票号" End If If Check1.Value = 1 And Check2.Value = 1 Then DataE1.rsCommand2.Open "select * from rkb where rkb." & Combo1.text & " " & " =’" + Text1.text + "’and 日期 between ’" + Str(DTP1.Value) + "’ and ’" + Str(DTP2.Value) + "’ order by 票号" End If End Select DR1_tsrkcx.Show End Sub 9.7.9 库存上下限设置 图书入库后,需要对其库存设定存储上限和下限,这样做可以防止某种图书因为入库 过多造成图书堆积,或者由于库存不足造成图书断货。通过上下限设置模块为图书设置上 下限,从而满足其库存需求。 库存上下限设置模块的运行结果如图 9.28 所示。 1.窗体设计 (1)在工程中新建一个窗体,将窗体的名称设置为“main_rcyw_kcsxx”,BorderStyle 属性设置为“1-Fixed Single”,MaxButton 属性设置为 False。 424 SQL Server 2005 数据库系统开发案例精选 图 9.28 库存上下限设置模块运行结果 (2)在窗体中放置 Adodc 、DataGrid 、TextBox 和 ComboBox 等控件。主要控 件对象的属性如表 9.11 所示。 表 9.11 主要控件对象的属性列表 对 象 属 性 值 ConnectionString DSN=NBooks RecordSource select * from kcb Adodc1 Visible False DataGrid1 DataSource Adodc1 名称 CmdFind Command1 Caption &F 查询 名称 CmdEnd Command2 Caption &E 退出 库存上下限设置窗体的设计结果如图 9.29 所示。 图 9.29 库存上下限设置窗体的设计界面 2.代码设计 当窗体启动时,设置 Ado 控件连接到数据库,并为 ComboBox 控件添加查询字段名称, 以及锁定 DataGrid 控件中前 5 列数据,使其不能在控件中修改。实现代码如下: //…………………………………………………例程8-25………………………………………………// Private Sub Form_Load() ’自动识别路径 Adodc1.ConnectionString = "DSN=NBooks" Adodc1.RecordSource = "select * from kcb" Adodc1.Refresh 425 C H A P T E R 9 第 9 章 图书综合管理系统 ’添加字段列表 Combo1.AddItem ("书号") Combo1.AddItem ("条形码") Combo1.AddItem ("书名") Combo1.AddItem ("作者") Combo1.AddItem ("出版社") Combo1.AddItem ("图书类别") Combo1.AddItem ("存放位置") Combo1.ListIndex = 1 ’锁定DataGrid1表格的0至5列 Dim a As Integer For a = 0 To 4 DataGrid1.Columns(a).Locked = True Next a ’按选择的字段和输入的内容模糊查询 Adodc1.RecordSource = "select * from kcb " Adodc1.Refresh End Sub 单击【查询】按钮,按条件查询相应的图书库存信息,实现的代码如下: //…………………………………………………例程8-26…………………………………………………// Private Sub CmdFind_Click() ’查询 ’按选择的字段和输入的内容模糊查询 Adodc1.RecordSource = "select * from kcb where kcb." & Combo1.text & " " & " like ’%" + Text1.text + "%’order by 书号" Adodc1.Refresh End Sub 9.7.10 销量分析 通过销量分析,可以完成当月图书销量的排行与分析工作。 销量分析模块的运行结果如图 9.30 所示。 图 9.30 销量分析模块运行结果 1.窗体设计 (1)在工程中新建一个窗体,将窗体的名称设置为“main_jcfx_xlfx”,BorderStyle 属 426 SQL Server 2005 数据库系统开发案例精选 性设置为“1-Fixed Single”,MaxButton 属性设置为 False。 (2)在 main_jcfx_xlfx 窗体中放置 Adodc 、DataCombo 、MSFlexGrid 、MSChart 、 Label 、TextBox 和 CommandButton 等控件。主要控件对象的属性如表 9.12 所示。 表 9.12 主要控件对象的属性列表 对 象 属 性 值 ConnectionString DSN=NBooks RecordSource select * from xsb Adodc1 Visible False ConnectionString DSN=NBooks RecordSource select * from tslbb Adodc2 Visible False DataGrid1 DataSource Adodc1 销量分析窗体的设计结果如图 9.31 所示。 图 9.31 销量分析窗体的设计 2.代码设计 窗体加载时,使用 SQL 语句检索汇总销量数据库中的信息,并以图表形式显示出来。 实现的代码如下: //………………………………………………例程8-27………………………………………… ………// Private Sub Form_Load() Adodc1.ConnectionString = "DSN=NBooks" Adodc1.RecordSource = "select * from xsb" Adodc1.Refresh Adodc2.ConnectionString = "DSN=NBooks" Adodc2.RecordSource = "select * from tslbb" Adodc2.Refresh Set rs1 = New ADODB.Recordset rs1.Open "select top 20 书名,sum(销售数量)as 合计销售数量 from xsb where year(日期)=’" + Format (Date, "yyyy") + "’and month(日期)=’" + Format(Date, "mm") + "’ group by 书名,出版社 order by 2 desc", Cnn, adOpenKeyset, adLockOptimistic With msChart1 427 C H A P T E R 9 第 9 章 图书综合管理系统 .ShowLegend = True .Title.text = " " & Year(Date) & "年" & Month(Date) & "月份 " & DataCombo1.text & "图书 销量排行(前20名) " ’设置图表名称 .Title.VtFont.Size = 12 ’设置字体大小 .Title.VtFont.VtColor.Set 255, 0, 0 ’设置字体颜色 End With Set msChart1.DataSource = rs1 If rs1.RecordCount > 0 Then rs1.MoveFirst Set msChart1.DataSource = rs1 msChart1.ColumnLabel = "本月图书销售数量" End If rs1.Close Adodc1.RecordSource = "select top 20 书名,sum(销售数量)as 合计销售数量 from xsb where year (日期)=’" + Format(Date, "yyyy") + "’and month(日期)=’" + Format(Date, "mm") + "’ group by 书名,出版社 order by 合计销售数量 desc " ’Left 函数返回 Variant (String),其中包含字符串中从左边算起指定数量的字符。 Adodc1.Refresh DataGrid1.Columns(0).Width = 3100 DataGrid1.Columns(1).Width = 1500 End Sub 技术细节 使用 MSChart 控件分析商品月销售状况,相关属性和方法如下。 Chart3d 属性:此数值指定图表是否为三维图表。 ChartData 属性:返回或设置一个数组,该数组包含将要被该图表显示的值。 ChartType 属性:返回或设置用于显示图表的图表类型。 ShowLegend 属性:返回或设置一个决定图表的图例是否可见的值。 9.7.11 添加操作员 在进行图书管理时,不同操作员都有各自不 同的职责和权限。为了使“图书综合管理系统” 的操作不会乱,可以通过添加操作员模块添加、 删除操作员,以便高级操作员管理。 添加操作员模块的运行结果如图 9.32 所示。 1.窗体设计 (1)在工程中新建一个窗体,将窗体的名称 设置为“main_xtgl_czysz”,BorderStyle 属性设置 为“1-Fixed Single”,MaxButton 属性设置为 False。 (2)窗体中添加 Adodc 、ImageList 、ImageCombo 、ComboBox 、TextBox 、 Label 和 CommandButton 等控件。主要控件对象的属性如表 9.13 所示。 表 9.13 主要控件对象的属性列表 对 象 属 性 值 ConnectionString DSN=NBooks RecordSource select * from qxb Adodc1 Visible False 图 9.32 添加操作员模块运行结果 428 SQL Server 2005 数据库系统开发案例精选 续表 对 象 属 性 值 Text1 名称 TxtBH Text2 名称 TxtCZY Text3 名称 TxtMM Text4 名称 TxtOK 名称 CmdAdd Command1 Caption 添加 名称 CmdOk Command2 Caption 确定 名称 CmdEsc Command3 Caption 取消 名称 CmdEnd Command4 Caption 退出 添加操作员窗体的设计结果如图 9.33 所示。 图 9.33 添加操作员窗体的设计结果 2.代码设计 在窗体启动时,设置 Adodc 控件连接数据库,并向 ComboBox 控件与 ImageCombo 控 件添加信息,实现的代码如下: //…………………………………………..……例程8-28……………………………….…………………// Private Sub Form_Load() ’自动识别路径 Adodc1.ConnectionString = "DSN=NBooks" Adodc1.RecordSource = "select * from qxb" Adodc1.Refresh Dim NewItem As ComboItem ’声明一个ComboItem对象 Dim i As Integer ’声明一个整型变量 Combo1.AddItem ("系统管理员") ’向Combo控件中添加数据项 Combo1.AddItem ("高级操作员") ’向Combo控件中添加数据项 Combo1.AddItem ("普通操作员") ’向Combo控件中添加数据项 For i = 1 To 10 Set NewItem = ImageCombo1.ComboItems.Add(i, "头像" & i, "头像" & i, "头像" & i) Next i End Sub 429 C H A P T E R 9 第 9 章 图书综合管理系统 单击【添加】按钮,自动生成操作员编号,代码如下: //………………………………………………例程8-29……………………………………………………// Private Sub CmdAdd_Click() ’添加 Adodc1.RecordSource = "select * from qxb" Adodc1.Refresh If Adodc1.Recordset.RecordCount > 0 Then ’如果数据记录大于零 Adodc1.Recordset.MoveLast ’移至最后一条记录 TxtBH.text = Format(Val(Adodc1.Recordset.Fields("编号")) + 1, "00") ’Format 函数返回 Variant (String),其中含有一个表达式,它是根据格式表达式中的指令来 格式化的。 Else TxtBH.text = "01" End If TxtCZY.SetFocus ’设置焦点 End Sub 单击【保存】按钮,将所添加的操作员信息保存到数据库中。代码如下: //………………………………………………例程8-30……………………………………… …………// Private Sub cmdOK_Click() ’确定 ’保存操作员及密码 If TxtCZY.text = "" Then MsgBox "系统不允许操作员为空!", "图书综合管理系统" Exit Sub End If If TxtMM.text = "" Then MsgBox "密码不允许为空!", "图书综合管理系统" Exit Sub End If If TxtOk.text = "" Then MsgBox "确认密码不允许为空!", "图书综合管理系统" Exit Sub End If If TxtOk.text <> TxtMM.text Then MsgBox "密码与确认密码不同,请重新输入!", "图书综合管理系统" Exit Sub End If If Combo1.text = "" Then MsgBox "操作员级别不允许为空!", "图书综合管理系统" Exit Sub End If If ImageCombo1.text = "" Then MsgBox "操作员头像不允许为空!", "图书综合管理系统" Exit Sub End If Adodc1.RecordSource = "select * from qxb where 操作员=’" + TxtCZY.text + "’" Adodc1.Refresh With Adodc1.Recordset If .RecordCount > 0 Then ’如果数据记录大于零 MsgBox "此操作员已存在,请重新输入!", "图书综合管理系统" Else Adodc1.Recordset.Close Adodc1.Recordset.Open "select * from qxb", Cnn, 0, 3 .AddNew .Fields("编号") = TxtBH.text .Fields("操作员") = TxtCZY.text .Fields("密码") = TxtMM.text 430 SQL Server 2005 数据库系统开发案例精选 .Fields("操作员级别") = Combo1.text .Fields("头像") = ImageCombo1.text .Update ’更新记录 ’清空控件信息 TxtBH.text = "" TxtCZY.text = "" TxtMM.text = "" TxtOk.text = "" Combo1.text = "" ImageCombo1.text = "" End If End With End Sub 9.7.12 库存打印报表 库存打印是将所查询的信息以报表的形式进行打印。 库存打印报表模块的运行结果如图 9.34 所示。 图 9.34 库存打印报表模块的运行结果 1.窗体设计 若想设计数据报表,首先需要设计数据环境,设计数据环境的步骤如下。 (1)在 VB 开发环境中选择“工程”菜单下的“添加 Data Environment”,此时弹出图 9.35 所示的窗口。 图 9.35 数据环境窗口 (2)在属性窗口中将数据环境的名称修改为 DataE1,在数据连接 Connection1 上单击 鼠标右键,在弹出的菜单选择“属性”项,弹出数据连接属性对话框,如图 9.36 所示。 (3)在图 9.36 所示的窗口当中选择“Microsoft OLE DB Provider for ODBC Drivers”, 单击【Next】按钮,弹出图 9.37 所示的选择数据连接界面。 431 C H A P T E R 9 第 9 章 图书综合管理系统 图 9.36 选择数据提供者 图 9.37 设置数据连接 (4)按照图 9.37 所示的界面设置完数据连接后,单击【测试连接】按钮,测试数据连 接,最后单击【确定】按钮。 (5)在数据连接 Connection1 上单击鼠标右键,在弹出的菜单中选择“添加命令”项, 为数据连接添加命令,如图 9.38 所示。 图 9.38 为数据连接添加命令 (6)在所添加的 Command1 命令上单击鼠标右键,选择“属性”命令,在弹出的对话 框中设置该命令所连接的数据表信息,如图 9.39 所示。 图 9.39 Command1 设置“属性”的命令 432 SQL Server 2005 数据库系统开发案例精选 (7)设置 Command1 的连接对象。如图 9.40 所示。 (8)在图 9.40 所示的窗口中单击【确定】按钮,修改 Command1 名称为 Command3。 完成对数据环境的设置,设置完的数据环境窗口如图 9.41 所示。 图 9.40 设置 Command1 命令所连接的对象 图 9.41 设计完成之后的数据环境窗口 数据环境设计完成之后,就可以设计数据报表了,设计数据报表的步骤如下。 (1)在 VB 工程的“工程”菜单下选择“添加 Data Report”子菜单,将数据报表添加 到工程环境中,并将数据报表的名称设置为“DR1_kccx”。 (2)通过将数据报表中的 DataSource 属性设置为“DataE1”和将数据报表中的 DataMember 属性设置为“Command3”,使得数据报表与数据环境取得连接,如图 9.42 所示。 设置数据报表的 DataSource 属 性和 DataMember 属性 图 9.42 设置数据报表的 DataSource 属性和 DataMember 属性 (3)按照图 9.43 所示设置数据报表。 2.代码设计 在主窗体界面当中“报表管理”菜单中的“库存打印报表”子菜单中添加下面的代码, 即可调出库存打印报表。 433 C H A P T E R 9 第 9 章 图书综合管理系统 用鼠标选中要向数据报表中添加的字段信息,再按住 鼠标左键一直拖动到数据报表的“细节”当中,然后 在数据报表的“细节”中编辑所添加的字段信息 将字段拖动到“细节”中后,可以通 过设置字段的其他一些属性来改变 该字段在数据报表中的显示效果 图 9.43 设置数据报表中的内容 //…………………………………………………例程8-31…………………………………………………// Private Sub DataReport_QueryClose(Cancel As Integer, CloseMode As Integer) DataE1.rsCommand3.Close End Sub 9.8 疑难问题分析与解决 9.8.1 如何将图书类别和存放位置列表中的内容赋给 MSFlexGrid 表格 为了方便用户录入图书入库信息,图书入库模块中的图书类别和存放位置项将以列表方 式显示,用户可以在列表中选择图书类别和存放位置。要将列表中的内容赋给 MSFlexGrid 控件,首先应考虑在什么情况下将列表中的值赋给 MSFlexGrid 控件。本例是当用户选择列 表中信息后按键时,将列表中的内容赋给 MSFlexGrid 控件。为了界面协调,还需使 列表控件的位置与用户光标所在行位置一致。代码如下(MS1 为 MSFlexGrid 控件): //…………………………………………………例程8-32…………………………………………………// If KeyCode = vbKeyReturn Then MS1.Text = Combo1.Text MS1.Col = 8 Combo2.Width = MS1.CellWidth Combo2.Left = MS1.CellLeft + MS1.Left Combo2.Top = MS1.CellTop + MS1.Top Combo2.SetFocus End If 434 SQL Server 2005 数据库系统开发案例精选 9.8.2 如何锁定 DataGrid 表格的指定列 DataGrid 控件是进行数据访问和操作最有效的工具,通过 DataGrid 控件可直接以表格 的形式对数据进行浏览和编辑。如果要修改表格中的数据,可以修改 DataGrid 控件的属性。 如果只允许修改指定列,其他列不允许修改,可以设置 DataGrid 的 Locked 属性值为 True。 下面代码将锁定 DataGrid 表格的 0~5 列。实现的具体代码如下: //………………………………………………例程8-33……………………………………………………// Dim a As Integer For a = 0 To 5 DataGrid1.Columns(a).Locked = True Next a 9.8.3 数据批量录入 在图书入库时,可能会发生图书入库类别过多,如果采用文本框进行录入每次只能录 入 1 条,对录入工作造成不便。 可以使用 MSFlexGrid 控件进行批量录入,实现方法是通过 TextBox 控件向 MSFlexGrid 添加数据,然后通过 For 循环将 MSFlexGrid 内的数据添加到数据库当中。实现的具体代码 如下: //………………………………………………例程8-34……………………………………………………// For i = 1 To 101 If MS1.TextMatrix(i, 1) <> "" Then ’添加入库商品信息到"rkb"表中 If MS1.TextMatrix(i, 1) <> "" And MS1.TextMatrix(i, 2) <> "" And MS1.TextMatrix(i, 3) <> "" And MS1.TextMatrix(i, 4) <> "" _ And MS1.TextMatrix(i, 5) <> "" And MS1.TextMatrix(i, 6) <> "" And MS1.TextMatrix(i, 7) <> "" And MS1.TextMatrix(i, 8) <> "" _ And MS1.TextMatrix(i, 9) <> "" And MS1.TextMatrix(i, 10) <> "" And MS1.TextMatrix(i, 11) <> "" And jsr.text <> "" And _ PH.Caption <> "" And jsr.text <> "" And rq.Caption <> "" Then Cnn.Execute ("insert into rkb(书号,条形码,书名,作者,出版社,版次,图书类别,存放位置,单价, 入库数量,金额" & _ ",经手人,票号,操作员,日期) values(’" & MS1.TextMatrix(i, 1) & "’,’" & MS1.TextMatrix(i, 2) & "’,’" & _ MS1.TextMatrix(i, 3) & "’,’" & MS1.TextMatrix(i, 4) & "’,’" & MS1.TextMatrix(i, 5) & "’,’" & MS1.TextMatrix(i, 6) & _ "’,’" & MS1.TextMatrix(i, 7) & "’,’" & MS1.TextMatrix(i, 8) & _ "’,’" & MS1.TextMatrix(i, 9) & "’,’" & MS1.TextMatrix(i, 10) & "’,’" & MS1.TextMatrix(i, 11) & _ "’,’" & jsr.text & "’,’" & PH.Caption & "’,’" & frm_main.St1.Panels(3).text & "’,’" & rq.Caption & "’) ") Else MsgBox "请输入完整信息", , "" End If ’查找库存图书信息 Set rs2 = New ADODB.Recordset rs2.Open "select * from kcb where 书号=’" + MS1.TextMatrix(i, 1) + "’", Cnn, adOpenKeyset, adLockOptimistic If rs2.RecordCount = 0 Then ’添加入库图书信息到"kcb"表中 If MS1.TextMatrix(i, 1) <> "" And MS1.TextMatrix(i, 2) <> "" And MS1.TextMatrix(i, 3) <> "" And MS1.TextMatrix(i, 4) <> "" _ And MS1.TextMatrix(i, 5) <> "" And MS1.TextMatrix(i, 7) <> "" And MS1.TextMatrix(i, 8) <> "" _ And MS1.TextMatrix(i, 9) <> "" And MS1.TextMatrix(i, 10) <> "" And MS1.TextMatrix(i, 11) 435 C H A P T E R 9 第 9 章 图书综合管理系统 <> "" Then Cnn.Execute ("insert into kcb(书号,条形码,书名,作者,出版社,图书类别,存放位置,单价,现 存数量,图书总数,金额,借出次数) " & _ "values(’" & MS1.TextMatrix(i, 1) & "’,’" & MS1.TextMatrix(i, 2) & "’,’" & _ MS1.TextMatrix(i, 3) & "’,’" & MS1.TextMatrix(i, 4) & "’,’" & MS1.TextMatrix(i, 5) & _ "’,’" & MS1.TextMatrix(i, 7) & "’,’" & MS1.TextMatrix(i, 8) & "’,’" & MS1.TextMatrix(i, 9) & _ "’,’" & MS1.TextMatrix(i, 10) & "’,’" & MS1.TextMatrix(i, 10) & "’,’" & MS1.TextMatrix(i, 11) & "’,0) ") Else MsgBox "请输入完整信息", , "" End If Else ’更新"kcb"表中的"库存"及"库存金额" Adodc1.Recordset.Fields("现存数量") = Val(MS1.TextMatrix(i, 10)) + Val(Adodc1.Recordset.Fields ("现存数量")) ’Val 函数返回包含于字符串内的数字,字符串中是一个适当类型的数值。 Adodc1.Recordset.Fields("图书总数") = Val(MS1.TextMatrix(i, 10)) + Val(Adodc1.Recordset.Fields("图书总数")) Adodc1.Recordset.Fields("金额") = Val(Adodc1.Recordset.Fields("图书总数")) * Val(Adodc1.Recordset.Fields("单价")) Adodc1.Recordset.Update End If End If Next i 9.9 程序调试与错误处理 程序调试在编写程序代码时是非常重要的。对某些函数、命令理解不深;在编写过程 中疏忽大意等都会造成在程序调试中出现问题。在编写 Visual Basic 应用程序时可能会出现 几百种错误,至少错误提示信息说明了这一点。 编程中常出现的错误有语法错误、逻辑错误和例外错误 3 类。 语法错误是其中最容易出现和纠正的。编译程序代码是查找大多数语法错误的最快方 法。但是有一些与语法相关的错误并不能在编译中表达出来。常见的语法错误包括如下几点。 (1)忘记书写表达式中的等号与其他运算符。 (2)不正确地拼写命令或函数名。 (3)字符串两边的引号不配对,常见错误是在字符串中使用了与区分字符串界限的引 号相同的引号。在 Visual Basic 应用程序当中,单引号、双引号、“&”或“+”符号是字符串 的定界符。如果需要在字符串的内部使用以上任何一种字符,则定界符应使用不同的字符。 (4)复杂表达式中的括号不配对。 (5)Select Case….End Select、If…Else….End 等不配对。 逻辑错误比较难检测和解决。编译程序并不能发现它们。有时,严重的逻辑错误会停止 程序的执行。有一些逻辑错误会产生明显错误的结果。常见的逻辑错误包括如下几点。 (1)对象未引用。 (2)变量未定义或定义错误。 (3)溢出错误。 例外错误是由程序直接控制的外部环境引起的。例如,程序因为找不到它所需要的文 436 SQL Server 2005 数据库系统开发案例精选 件而失败,也许这个文件己被删除或移动。 下面结合图书综合管理系统当中的具体实例说明在程序调试中出现的常见问题。 9.9.1 字段长度问题导致数据添加失败 图 9.44 所示的错误是在添加数据时,输入 字符的长度超过字段的长度时的提示信息。 当出现上述错误时可以通过改变数据库 中相应字段的长度避免此类错误,或通过代码 判断添加数据的长度是否大于数据库字段的 长度。例如数据库字段长度为 10,现将 Text1 控件中的文本添加到数据库中,可以通过如下 代码判断 Text1 控件中的文本长度是否超过数 据库字段的长度。代码如下: //………………………………………………例程8-35……………………………………………………// If Len(Text1.Text) > 10 Then MsgBox "输入的字符长度过长,最多可以输入10个字符。" Else ’添加字段代码 ... End If 9.9.2 由于 ADO 控件记录源属性的命令类型设置错误而出现的问题 图 9.45 ADO 属性页设置 在设置 ADO 属性时如果在记录源选项卡的命令类型中选择 2 – adCmdTable,如图 9.45 所示。而在程序代码编写过程中出现如下代码: //……………………………………………例程8-36……………………………………………………// Adodc1.RecordSource = " select * from jsb order by 书证号" Adodc1.Refresh 在程序运行时,会出现图 9.46、图 9.47 所示的错误。 图 9.46 错误提示 图 9.44 错误提示信息 437 C H A P T E R 9 第 9 章 图书综合管理系统 解决办法:可以将 ADO 属性中的记录源的命令类型设置为 1–adCmdText,并在下面的 命令文本中添加相应的 SQL 语句,如图 9.48 所示。 图 9.47 错误信息 图 9.48 ADO 属性页 9.9.3 语句中忘记书写连接运算符 在编写登录模块代码时,代码中的 SQL 语句是以字符串的 形式出现的,所以当 SQL 语句与代码嵌套使用时需要与连接运 算符共同使用。否则将弹出图 9.49 所示的错误信息,产生错误 的代码如图 9.50 所示。 当 VB 语句与 SQL 语句共同使用时,该 VB 语句两边要加 上相应的连接运算符号,如" + Trim(czy.Caption) + ",这样在程 序运行时才不会出现图 9.49 所示的错误。 由于在此处忘记书写了运 算符,所以导致在运行程序 出现错误 图 9.50 调试之后的 VB 开放环境窗口 修改完成后的代码如下: //………………………………………………例程2-46……………………………………………………// Adodc1.RecordSource = "select * from qxb where 操作员 = ’" + Trim(czy.Caption) + "’" ’Trim 函数返回 Variant (String),其中包含指定字符串的拷贝,没有前导和尾随空白。 Adodc1.Refresh 9.9.4 End if 语句没有配对出现 在添加图书入库信息时再输入相关图书信息时,弹出图 9.51 所示的错误提示信息,调 图 9.49 查询信息时弹出的 错误提示信息 438 SQL Server 2005 数据库系统开发案例精选 试之后的 VB 开发环境如图 9.52 所示。 从提示的错误信息可以看到,出错的原因是由于在程序代码 中缺少“End If”语句引起的,在 VB 的语法结构中,End if 与 最近的 If 配对,也就是说 If 和 End If 必须成对的出现,否则就 会提示图 8.51 所示的“End If”的错误信息。 在程序代码中添加“End If”,使 If 和 End If 成对出现就会 避免这个错误的发生。 此处缺少 End If 语句 图 9.52 调试之后的 VB 开放环境窗口 修改后的程序代码如下: //………………………………………………例程8-37……………………………………………………// Private Sub Text1_KeyDown(KeyCode As Integer, Shift As Integer) If KeyCode = vbKeyReturn Then ’按回车键 Text1.text = MS1.text Adodc3.RecordSource = "select * from kcb where 条形码=’" + MS1.TextMatrix(MS1.Row, 2) + "’" Adodc3.Refresh If Adodc3.Recordset.RecordCount > 0 Then ’当记录大于零时 If MS1.Col = 2 Then With Adodc3.Recordset ’赋值给MS1表格 If .Fields("书号") <> "" Then MS1.TextMatrix(MS1.Row, 1) = .Fields("书号") If .Fields("条形码") <> "" Then MS1.TextMatrix(MS1.Row, 2) = .Fields("条形码") If .Fields("书名") <> "" Then MS1.TextMatrix(MS1.Row, 3) = .Fields("书名") If .Fields("作者") <> "" Then MS1.TextMatrix(MS1.Row, 4) = .Fields("作者") If .Fields("出版社") <> "" Then MS1.TextMatrix(MS1.Row, 5) = .Fields("出版社") If .Fields("图书类别") <> "" Then MS1.TextMatrix(MS1.Row, 7) = .Fields("图书类别") If .Fields("存放位置") <> "" Then MS1.TextMatrix(MS1.Row, 8) = .Fields("存放位置") If .Fields("单价") <> "" Then MS1.TextMatrix(MS1.Row, 9) = .Fields("单价") Text1.text = MS1.text MS1.Col = 6 Grid1.Visible = False Text1.SetFocus 图 9.51 添加图书入库信息 时弹出的错误提示信息 439 C H A P T E R 9 第 9 章 图书综合管理系统 End With End If End If If Adodc1.Recordset.RecordCount > 0 Then ’当记录大于零时 If MS1.Col = 1 Then With Adodc1.Recordset ’赋值给MS1表格 If .Fields("书号") <> "" Then MS1.TextMatrix(MS1.Row, 1) = .Fields("书号") If .Fields("条形码") <> "" Then MS1.TextMatrix(MS1.Row, 2) = .Fields("条形码") If .Fields("书名") <> "" Then MS1.TextMatrix(MS1.Row, 3) = .Fields("书名") If .Fields("作者") <> "" Then MS1.TextMatrix(MS1.Row, 4) = .Fields("作者") If .Fields("出版社") <> "" Then MS1.TextMatrix(MS1.Row, 5) = .Fields("出版社") If .Fields("图书类别") <> "" Then MS1.TextMatrix(MS1.Row, 7) = .Fields("图书类别") If .Fields("存放位置") <> "" Then MS1.TextMatrix(MS1.Row, 8) = .Fields("存放位置") If .Fields("单价") <> "" Then MS1.TextMatrix(MS1.Row, 9) = .Fields("单价") MS1.Col = 6 Text1.text = MS1.text Text1.SetFocus End With End If If MS1.Col = 6 Then MS1.Col = 9 If MS1.Col = 10 Then MS1.Row = MS1.Row + 1 MS1.Col = 1 Else If MS1.Col + 1 <= MS1.Cols - 1 Then MS1.Col = MS1.Col + 1 Else If MS1.Row + 1 <= MS1.Rows - 1 Then MS1.Row = MS1.Row + 1 MS1.Col = 1 End If End If End If Else If MS1.Col = 10 Then MS1.Row = MS1.Row + 1 MS1.Col = 1 Else If MS1.Col + 1 <= MS1.Cols - 1 Then MS1.Col = MS1.Col + 1 Else If MS1.Row + 1 <= MS1.Rows - 1 Then MS1.Row = MS1.Row + 1 MS1.Col = 1 End If End If End If End If End If If KeyCode = vbKeyUp Then ’按KeyUp键 If MS1.Row > 1 Then MS1.Row = MS1.Row - 1 End If If KeyCode = vbKeyDown And (MS1.TextMatrix(MS1.Row, 1)) <> "" Then ’按KeyDown键 If MS1.Row < 99 Then MS1.Row = MS1.Row + 1 End If 440 SQL Server 2005 数据库系统开发案例精选 If KeyCode = vbKeyLeft Then ’按KeyLeft键 If Text1.text <> "" Then Text1.SelStart = 0 Text1.SelLength = Len(Text1.text) ’Len 函数返回 Long,其中包含字符串内字符的数目,或是存储一变量所需的字节数。 End If If MS1.Col - 10 <= MS1.Cols + 1 Then MS1.Col = MS1.Col - 1 If MS1.Col = 0 Then MS1.Col = 1 Else If MS1.Row + 1 <= MS1.Row - 1 Then MS1.Row = MS1.Row + 1 MS1.Col = 1 End If End If End If If KeyCode = vbKeyRight Then ’按KeyRight键 If Text1.text <> "" Then Text1.SelStart = 0 Text1.SelLength = Len(Text1.text) End If If MS1.Col + 1 <= MS1.Cols - 1 Then MS1.Col = MS1.Col + 1 Else If MS1.Row + 1 <= MS1.Rows - 1 Then MS1.Row = MS1.Row + 1 MS1.Col = 1 End If End If End If If KeyCode = vbKeyPageDown And MS1.Col = 1 Then ’按KeyPageDown 键 Adodc1.RecordSource = "select * from kcb" Adodc1.Refresh Grid1.Visible = True Grid1.SetFocus End If End Sub Private Sub Text1_Change() MS1.text = Text1.text ’赋值给MS1.text If MS1.Col = 1 Then ’按书号查询库存图书信息 Adodc1.RecordSource = "select * from kcb where 书号 like +’" + Text1.text + "’+’%’" Adodc1.Refresh If Text1.text = "" Then ’当text1.text为空时 Grid1.Visible = False ’Grid1不可见 Else If Adodc1.Recordset.RecordCount > 0 Then ’当记录大于零时 Grid1.Visible = True ’Grid1可见 Text1.Visible = True Text1.SetFocus Else Grid1.Visible = False End If End If End If If MS1.Col = 9 Then MS1.TextMatrix(MS1.Row, 11) = Val(MS1.TextMatrix(MS1.Row, 9)) * Val(MS1. 441 C H A P T E R 9 第 9 章 图书综合管理系统 TextMatrix(MS1.Row, 10)) ’Val 函数返回包含于字符串内的数字,字符串中是一个适当类型的数值。 If MS1.Col = 10 Then MS1.TextMatrix(MS1.Row, 11) = Val(MS1.TextMatrix(MS1.Row, 9)) * Val(MS1. TextMatrix(MS1.Row, 10)) If MS1.Col = 7 Then Text1.Visible = False Combo1.Visible = True Combo1.Width = MS1.CellWidth Combo1.Left = MS1.CellLeft + MS1.Left Combo1.Top = MS1.CellTop + MS1.Top Combo1.SetFocus End If Dim a, B As Single For i = 1 To 101 a = Val(MS1.TextMatrix(i, 11)) + a B = Val(MS1.TextMatrix(i, 10)) + B If MS1.TextMatrix(i, 1) <> "" And MS1.TextMatrix(i, 10) <> "" Then pz.Caption = i Next i ’计算合计金额,合计数量 hjje.Caption = a ’计算合计金额 hjsl.Caption = B ’计算合计数量 End Sub 9.9.5 提示文件未找到的错误信息 运行程序之后在进行数据备份时,弹出图 9.53 所示的错误提示信息,调试之后的 VB 开发环境如图 9.54 所示。 图 9.53 在进行数据备份时弹出的错误提示信息 如果删除了应用程序运行时所需要的文件,就会弹出图 9.53 所示的“文件未找到”的 错误提示信息,将所需要的文件重新复制到原路径下,将解决此问题。 此处调用的可执行文件“备 份及恢复数据库.exe”已经 被删除,所以弹出“文件未 找到”的错误提示信息 图 9.54 调试之后的 VB 开放环境窗口 也可以添加 CommonDialog 控件 ,并更改代码为: //………………………………………………例程8-38……………………………………………………// On Error Resume Next ’进行错误处理 Shell App.Path & "\备份及恢复数据库.exe", 1 442 SQL Server 2005 数据库系统开发案例精选 If Err.Number = 53 Then ’当产生文件未找到错误时,执行以下操作 CommonDialog1.Filter = "备份及恢复数据库|备份及恢复数据库.exe" ’设定打开文件类型 CommonDialog1.FileName = App.Path CommonDialog1.ShowOpen If CommonDialog1.FileName <> "" Then ’判断打开文件路径是否为空 Shell CommonDialog1.FileName, 1 If Err Then MsgBox "请指定文件所在路径。" Exit Sub End If Else MsgBox "请指定文件所在路径。" Exit Sub End If End If End 9.9.6 解决在打印报表时弹出的无效数据源的问题 程序运行时,打印“库存”报表时,弹出图 9.55 所示的错误提示信息。 图 9.55 打印报表时弹出的错误提示信息 上述出错的原因是由于在设计报表时,没有连接报表数据源引起的。在设计完报表时, 需要在报表窗体的属性对话框中将报表的 DataSource 属性设置为“DataE1”,使报表与数 据环境相连接;DataMember 属性设置为“Command3”,使报表与数据连接取得连接,如 图 9.56 所示。这样,在运行程序时,就可以正常打印报表了。 图 9.56 设置使报表与数据环境与数据连接相连接的属性 9.9.7 解决报表的宽度大于纸的宽度的问题 程序运行时,打印“库存”报表时,弹出图 9.57 所示的错误提示信息。 443 C H A P T E R 9 第 9 章 图书综合管理系统 图 9.57 打印报表时弹出的错误提示信息 根据提示的错误信息可知,出错的原因是由于在设计报表时报表的宽度过宽引起的, 如图 9.58 所示。 报表的宽度过宽,将报表的宽度调窄一些可以解决“报表 的宽度大于纸的宽度”的问题,将鼠标放置在报表的右边 界,当鼠标变为此样式的时候向左或向右拖动鼠标可以调 整报表的宽度 图 9.58 调整报表的宽度 将报表的宽度调窄一些,就可以解决这个问题。

下载文档,方便阅读与编辑

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享文档获得金币 ] 5 人已下载

下载文档

相关文档