NBSI2内部功能实现大揭谜数据库教程

2024-05-05

NBSI2内部功能实现大揭谜数据库教程(精选9篇)

篇1:NBSI2内部功能实现大揭谜数据库教程

在Excel教学中,经常要向学生讲解数据的筛选操作,Excel中提供了两种数据的筛选操作,即“自动筛选”和“高级筛选”,但学生往往弄不明白,什么情况下要使用“自动筛选”和“高级筛选”?究竟可以实现数据的哪些筛选操作?怎样才能熟练地掌握数据的筛选呢?本人通过一些实例很好地化解了此部分教学中的难点,一起来看看吧。

自动筛选

“自动筛选”一般用于简单的条件筛选,筛选时将不满足条件的数据暂时隐藏起来,只显示符合条件的数据。我们通过下面的实例来进行讲解(如图1)。图1为某单位的职工工资表,打开“数据”菜单中“筛选”子菜单中的“自动筛选”命令,以“基本工资”字段为例,单击其右侧向下的列表按钮,可根据要求筛选出基本工资为某一指定数额或筛选出基本工资最高(低)的前10个(该数值可调整)记录。我们还可以根据条件筛选出基本工资在某一范围内符合条件的记录,条件“与”表示两个条件同时要成立,条件“或”表示两个条件只要满足其中之一就可以了。如图2所示,可根据给定的条件筛选出基本工资大于等于300且小于350的记录。另外,使用“自动筛选”还可同时对多个字段进行筛选操作,此时各字段间限制的条件只能是“与”的关系。如筛选出“基本工资”和“职务工资”都超过380的记录。

高级筛选

“高级筛选”一般用于条件较复杂的筛选操作,其筛选的结果可显示在原数据表格中,不符合条件的记录被隐藏起来,

也可以在新的位置显示筛选结果,不符合条件的记录同时保留在数据表中而不会被隐藏起来,这样就更加便于进行数据的对比了。

例如我们要筛选出“基本工资”或“职务工资”超过380且“实发”工资超过700的符合条件的记录,用“自动筛选”就无能为力了,而“高级筛选”可方便地实现这一操作。如图3所示,将“基本工资”、“职务工资”和“实发”三字段的字段名称复制到数据表格的右侧(表格中其他空白位置也可以),在图中所示位置输入条件,条件放在同一行表示“与”的关系,条件不在同一行表示“或”的关系。图4即为上述操作在新的位置(B20起始位置)筛选的结果。

总 结

通过上面的实例,学生基本能理解两种筛选操作的异同了。但还要适时地加以总结,巩固这些概念在学生头脑中的印象。

总结如下:“自动筛选”一般用于条件简单的筛选操作,符合条件的记录显示在原来的数据表格中,操作起来比较简单,初学者对“自动筛选”也比较熟悉。若要筛选的多个条件间是“或”的关系,或需要将筛选的结果在新的位置显示出来,就只有用“高级筛选”来实现了。 一般情况下,“自动筛选”能完成的操作用“高级筛选”完全可以实现,但有的操作则不宜用“高级筛选”,这样反而会使问题更加复杂化了,如筛选最大或最小的前几项记录。

最后,还要启发学生:在实际操作中解决数据筛选问题时,只要我们把握了问题的关键,选用简便、正确的操作方法,问题都能迎刃而解。

篇2:NBSI2内部功能实现大揭谜数据库教程

...所以昨天我试着找到了一个完全不同的更简单的实现。我决定以 Well-Known Binary 的形式(译者注: OpenGIS 的说明书中定义了两个表述空间对象的标准方式:一个是 WKT ( the Well-Known Text )形式,另一个是 WKB ( the Well-Known Binary )形式)存储几何体在一个图像列中。使用图像列的目的是它能够保存大到 2G 的数据,这对大多数的几何对象都足够了。而字节列和用户自定义类型一样,也有 8000 个字节的限制,所以也不够好。除了几何列之外,我还创建了四个实数类型的列,用来存储几何外接矩形框的最大最小坐标值,

这能提高基于外接矩形框的查询的效率。其它的列用来存储几何体的属性。

我在 SharpMap 中实现了这个方法。首先,我建立了一个小的数据库导入程序用来导入 shapefile 文件。它在数据库中建立一个表,然后把几何体及其对象导入其中。 SharpMap 为其提供了必要的数据读取器和 WKB 格式化程序。第二个部分是建立了一个数据提供接口, SharpMap 能够基于这个接口绘制数据。我做这些时多少参照了 PostGreSQL/PostGIS 的数据提供接口,只是用四个外框坐标列来做外接矩形框查询。所有这些工作所发费的时间不超过一个小时,因此,可以说做起来是比较简单的。

我必须说,对于这种方法的效率我是很惊讶的。它比 shapefile 的数据接口还快一点点,而 shapefile 数据接口曾经是 SharpMap 中最快的数据接口。而 PostGreSQL/PostGIS 相比而言要慢 4 - 6 倍。

我在这里创建了一个可下载的 web 演示程序。它分为两页:一个是导入到数据库,另一个是从数据库读取数据和绘制图层。所有你要做的是在 App_Data 文件夹中增加一个 SQL Server Express 数据库并把它命名为 “GeoDatabase.mdf” 。

篇3:NBSI2内部功能实现大揭谜数据库教程

一、四轮驱动模式内涵

“四轮驱动”又称全轮驱动, 指汽车前后轮都有动力。启动这种驱动模式, 可按行驶路面状态不同而将发动机输出扭矩按不同比例分布在前后所有的轮子上, 以提高汽车的行驶能力。[2]换而言之, “四轮驱动”模式就是按处境与遭遇不同状态而将内部力量和资源输出, 按不同比例科学合理分布, 以提高成功驶向目标的能力。

在这种合作模式中, 学校与企业发生直接关联, 企业与实体项目发生直接关联, 学校将理论结合实践的课程置换到项目专业教学中, 企业提供相应的实习环境和师资技能培养环境, 以突出学生创新性和应用能力的培养。在四轮驱动模式下, 高职“订单式”人才的培养要求我们面对市场, 深化与企业的合作, 走符合时代发展的人才培养模式之路。围绕企业发展和需求, 以技术技能的突破为目标, 加快高端领域的突破, 形成独具特色的优势。这种培养模式, 能有效培养他们的职业素养, 使他们顺利毕业并成为符合相应企业要求的高素质、高技能型人才。

二、四轮驱动模式下高职“订单式”人才培养的条件

(一) 选准企业, 是四轮驱动模式下高职“订单式”人才培养顺利实施的基础。

在企业的选择上要把握四个原则:第一要选择管理规范、发展前景广阔, 且具有一定规模, “订单量”大的企业;第二要选择在本行业中影响较大, 经济效益好, 有一定经营能力和抗风险能力, 且有先进的设备和技术的企业;第三要选择企业文化氛围好, 薪酬福利较好, 发展空间较大, 注重员工培训的企业;第四要选择重视教育、理念一致, 能积极配合和支持学校“订单式”人才培养, 有较好信誉的企业。企业的选择过程, 是校企双方相互了解沟通的过程, 也是精心培育校企感情的过程, 更是双方达成共识和共赢的过程。

(二) 组建订单班、加强订单学生的教育, 是推进四轮驱动模式下高职“订单式”人才培养实施的思想保证。

组建订单班要采取学生自愿报名, 双向选择, 择优录取的原则。学生进入订单班, 其主要目的是就业, 学生选择企业的理由包括很多方面, 如物质报酬、工作环境、职业声望、职业安全、发展机会等。学生是“订单式”人才培养的对象, 只有他们积极参与, 才能取得预定的效果。为此, 在实践中要注意抓好学生的思想教育和动员。

(三) 培养过程管理, 是四轮驱动模式下高职“订单式”人才培养取得实效的保障。

“订单式”人才培养是一项内容复杂, 头绪繁多的工作。“订单式”人才培养是否成功, 关键在于人才培养质量的高低。“订单式”人才培养是校企合作办学的具体方式, 因此, 订单学生的培养过程是“订单式”人才培养的关键, 影响整个“订单式”人才培养的成效。

(四) 实现学校、企业、学生之间的三赢, 是四轮驱动模式下高职“订单式”人才培养顺利实施的关键。

“订单式”人才培养工作的顺利开展, 找准学生、企业、学校之间利益契合点是关键问题。“订单式”人才培养, 一方面, 为企业解决了对技能型人才的需求。另一方面, 学校可以通过借助企业的优质资源来提升学生的岗位技能和职业素质, 并以“准员工”的资格获得就业岗位和广阔的发展空间。

实践证明, 只有实现学校、企业、学生三者的共赢, 才能充分调动各方参与工学结合的积极性, 四轮驱动模式下高职“订单式”人才培养的推进才具有坚实的基础和持久的动力。

三、四轮驱动模式下高职“订单式”人才培养的方法探析

“订单式”人才培养, 是指学校与用人单位针对社会和市场需求共同制定人才培养方案, 签订用人订单, 并在师资、技术、办学条件等方面合作, 通过工学结合的方式分别在学校和用人单位进行教学, 学生毕业后直接到用人单位就业的一种人才培养方式。[3]这种“订单”, 是企业从自身文化特征和岗位要求出发, 介入高职人才培养的全过程, 贯穿人才培养的始终。四轮驱动模式下高职“订单式”人才培养必须建立在校企双方互相信任、紧密合作的基础上, 使“专业设置与企业需求相适应、技能训练与岗位要求相协调、培养目标与用人标准相吻合”, 能有效以“出口”带动“入口”, 真正实现学校、企业、学生的“三赢”, 是校企合作最行之有效的方式。对于这种人才培养模式的实现, 我有以下几点思考。

(一) 联手策划、共同制定人才培养方案, 并实行双向管理。

按照企业对员工培养的要求, 结合企业产品技术及服务的特点, 学校与企业优势资源互补, 校企共同制定四轮驱动模式下高职“订单式”人才培养方案。课程设置要打破常规, 按企业要求引入课程, 并对原有课程进行删减, 重新组建新的课程体系, 按照“分配小组任务—小组研讨—团队工作—成果展示”的过程实施现场教学, 在教学的全过程完全融入企业运行模式。学校从企业引进实际生产项目, 在课堂的教学中实行案例教学, 通过知识点的讲解, 项目开发流程的分解, 让学生跟随产品的生产流程完成各教学任务, 最终按项目产品的合格标准对学生进行教学上的课程考核。[4]校企共同制定与实施人才培养方法, 能保证学生职业技能的培养与学有所用。

学生管理实行双班主任制度, 学校选派教师担任订单班班主任, 对日常事务进行管理, 企业派人事管理人员担任班主任, 对学生进行企业管理理念的渗透, 将企业文化纳入人才培养方案, 融入日常的教学、管理中, 并且定期开展具有企业文化特色的员工活动, 让学员感受企业的人文关怀, 增强学生的企业归属感。

(二) 共同打造双师型教学团队, 携手推行现场教学。

双师型教学团队是指承担教学任务的教师不但要具备过硬的理论和业务知识, 还必须具备较强的实践能力。[5]学校和企业要依据双方的师资特点, 由企业出资, 通过校内骨干教师培训、派遣企业培训教师授课、聘请校外优秀技术专家等方式为“订单班”打造一流校企联合的双师型教学团队。并且可以由企业赞助选送校内骨干教师赴该行业发达国家、地区进行学习考察, 同时学校可邀请企业管理专家、优秀技术人员到学校宣讲企业文化与内涵, 聘请企业优秀技术人员到学校任教。

教学过程需要学校和企业共同参与。学校按照企业对员工的素质技能要求, 采用理论与实践一体化教学方式, 指导学生按照企业项目工作路径在校内实施现场教学, 并由企业专技人员进行项目指导和评估。同时定期组织“订单班”学生到企业生产服务现场进行学习和实际操作。

(三) 校企合作共建共享实训基地。

按照企业工作环境要求, 校企合作共同建设具有企业真实工作环境的校内仿真模拟实训基地, 在共同建设中由企业提供技术和设备, 建成企业技术与文化推广基地, 成为订单班学生与专业教师的技能训练与认证基地。实现订单培养过程中理论与实践、车间与教室、学生与学徒的一体化;为订单班学生提供真实的实训环境, 也为订单班学生感受职业环境、养成良好的职业行为习惯提供广阔的平台。

(四) 合理构建评价体系。

按照企业岗位任职要求, 校企双方共同参与订单班学生的选拔录用、教学过程监控、技能考核、职业综合素质评价等订单培养的全过程。结合企业员工相关标准, 建立起一整套与企业质量体系、职业技能标准、员工综合素质要求、企业生产现场评价指标等相结合的订单培养质量评价体系。

这种四轮驱动模式下高职“订单式”人才培养方式, 是依托学校和企业的优势资源, 面向产业, 培养适应岗位需求的一线人才, 使生产一线最新的技术与企业文化走进校园, 促进校园成为企业产品与技术的展示窗口;同时学校吸引产业内优势企业持续投入, 打造优秀教学团队、优化人才培养方案、引进企业先进技术、促进校企深度融合, 人才培养水平与就业质量不断提高, 真正实现了教育与产业的共赢发展, 从根本上解决了技能型人才培养的脱节问题, 学校的培养目标与企业的实际需求保持一致, 实现了学校、企业、学生“三赢”。

四、对四轮驱动模式下高职“订单式”人才培养的思考

(一) 校企双方需求互补是动力, 制度支持不可缺。

“订单式”人才培养是高职院校针对性很强的就业教育尝试, 需要学校从管理、用人等方面全力支持;而对企业原有的用人制度有着较大的冲击, 这就需要企业进行新的用人理念和体制的改革, 并从用人制度方面给予学校实质性支持。在现代职业教育运行模式下, 学校订单教学的实施困难要小于调动企业与学校合作的困难, 目前这种人才培养方式基本处于一头热的状态, 这需要学校在办学模式等方面确实对企业有足够的吸引力。同时还需要学校与企业多沟通, 用事实去刺激企业用人需求。相信随着国家教育相关政策的出台, 学校与企业四轮驱动模式下高职“订单式”人才培养之路会越走越宽阔。

(二) 对校企双方意义重大。

四轮驱动模式下高职“订单式”人才培养的实施.要求企业需要什么样的人才, 高职院校就要培养什么样的人才。[6]对学校而言, 这种培养方式有利于高职教育体制和人才培养模式的改革;使学校的教学内容与产业的需求同步, 并能弥补课本知识与产业发展之间的差距;人才培养过程有企业的完全参与, 对深化教学改革有着很大的帮助。对于企业来说, “订单式”人才培养的方案是根据企业岗位需求与学校共同制定的, 培养过程与企业生产零距离, 使企业的用人成本大大降低;校企联合培养过程中, 企业理念融入教学全过程, 使学生对企业的认同感得到强化, 同时也增强了学生的责任感、敬业精神和协作意识。因此, 四轮驱动模式下高职“订单式”人才培养实现了企业和学校优势资源在人才培养过程中的有机整合。

综上所述, 四轮驱动模式下高职“订单式”人才培养既是现代职业教育走向市场的必然选择, 又是现代企业走向科学发展的客观要求。这不仅是企业与教育的联姻, 而且是用人与育人的统一。现代教育制度与现代企业制度, 在服务经济和社会方面找到了共同点, 这是供需双方利益相关联, 使命相吻合的共赢之举。

参考文献

[1]万久玲.“四轮驱动”提高毕业生就业竞争力[J].河南教育, 2008, (10) .

[2]李晓燕.导说仿评“四轮驱动”教学模式的构建及其实践[J].湖南广播电视大学学报, 2011, (2) .

[3]张科海.高职院校实施“订单式”人才培养的几点思考[J].陕西工业职业技术学院学报, 2011, (12) .

[4]陈天荣.加强校企联合办学, 探索人才订单培养新模式[J].职教论坛, 2010, (35) .

[5]汤毅平、黄英.高职院校工学结合的途径与方法——订单培养与2+1培养[J].当代教育论坛:管理版, 2010, (11) .

篇4:NBSI2内部功能实现大揭谜数据库教程

对照表格我发现,很多表格项目如“性别”、“所属年级”、“是否团员”等项目,其填写的内容都是相同的几个值,能不能像上网时填写网页表单那样,将这些内容做成下拉式菜单,这样这些项目录入时就可以不需输入而可以直接选择,不就能大大提高录入速度了吗?下面就以录入“所属年级”这一表格项目为例,介绍一下具体实现的过程。

1.设置序列的有效值

这里所指的“序列”即某字段(如“所属年级”)内可能会填写的内容,这些内容是固定的,一般个数不会太多。首先选定“所属年级”字段所在的列 (除了字段名称),单击“数据”菜单中的“有效性”命令,弹出“数据有效性”对话框,选中“设置”选项卡,在“允许”下拉菜单中选择“序列”,在数据“来源”中输入“初一,初二,初三,高一,高二,高三”(一定要在英文状态下输入逗号作为分隔符!),其他设置按系统默认不变(如图1),

图1设置序列的有效值

2.设置输入提示信息

输入提示信息可以使录入过程更加清晰明了。具体制作步骤是:在图1中单击“输入信息”选项卡,选中“选定单元格时显示输入信息”复选框,在“输入信息”框内输入“请选择该生所属年级!”(如图2)。设置完成后,单击[确定]按钮。

图2设置输入提示信息

3.数据的录入

在以上设置完成之后就可以对所有学生的年级进行选择录入了,若要录入某学生的“所属年级”,只需单击单元格右侧的下拉菜单(如图3),选择该生所属的年级就可以了。

图3数据的录入

篇5:NBSI2内部功能实现大揭谜数据库教程

对于数据的处理工作,排序是其最基本的运算之一,在当今的计算机系统中,花费在排序上的时间占系统CPU运行时间的很大比重。有资料表明,在一些商用计算机上,在排序上的CPU时间达到20%至60%。为了提高计算机的工作效率,人们提出了各种各样的排序方法和算法。这些算法有力地发展、并充分地展示了算法设计的某些重要原则和高超技巧。因此,对于计算专业人员来说掌握排序算法是十分重要的。

二、排序算法简介

本次课程中我们将介绍六种排序方法:插入排序,选择排序,冒泡排序,希尔排序,快速排序及二路归并。

<1>直接选择排序(Selection Sort):简单的选择排序,它的比较次数一定:n(n-1)/2。也因此无论在序列何种情况下,它都不会有优秀的表现(从上100K的正序和反序数据可以发现它耗时相差不多,相差的只是数据移动时间),可见对数据的有序性不敏感。它虽然比较次数多,但它的数据交换量却很少。所以我们将发现它在一般情况下将快于冒泡排序。

<2>直接插入排序(Insertion Sort):简单的插入排序,每次比较后最多移掉一个逆序,因此与冒泡排序的效率相同。但它在速度上还是要高点,这是因为在冒泡排序下是进行值交换,而在插入排序下是值移动,所以直接插入排序将要优于冒泡排序。直接插入法也是一种对数据的有序性非常敏感的一种算法。在有序情况下只需要经过n-1次比较,在最坏情况下,将需要n(n-1)/2次比较。

<3>冒泡排序(Bubble Sort):将相邻的两个数据元素按关键字进行比较,如果反序,则交换。对于一个待排序的数据元素序列,经一趟排序后最大值数据元素移到最大位置,其它值较大的数据元素向也最终位置移动,此过程为一次起泡。然后对下面的记录重复上述过程直到过程中没有交换为止,则已完成对记录的排序。

<4>快速排序(Quick Sort):是冒泡排序的改进,它通过一次交换能消除多个逆序,这样可以减少逆序时所消耗的扫描和数据交换次数。在最优情况下,它的排序时间复杂度为O(nlog2n)。即每次划分序列时,能均匀分成两个子串。但最差情况下它的时间复杂度将是O(n^2)。即每次划分子串时,一串为空,另一串为m-1(程序中的100K正序和逆序就正是这样,如果程序中采用每次取序列中部数据作为划分点,那将在正序和逆时达到最优)。从100K中正序的结果上看“快速排序”会比“冒泡排序”更慢,这主要是“冒泡排序”中采用了提前结束排序的方法。有的书上这解释“快速排序”,在理论上讲,如果每次能均匀划分序列,它将是最快的排序算法,因此称它作快速排序。虽然很难均匀划分序列,但就平均性能而言,它仍是基于关键字比较的内部排序算法中速度最快者。

<5>希尔排序(Shell Sort):增量的选择将影响希尔排序的效率。但是无论怎样选择增量,最后一定要使增量为1,进行一次直接插入排序。但它相对于直接插入排序,由于在子表中每进行一次比较,就可能移去整个经性表中的多个逆序,从而改善了整个排序性能。希尔排序算是一种基于插入排序的算法,所以对数据有序敏感。

<6>归并排序(Merge Sort):归并排序是一种非就地排序,将需要与待排序序列一样多的辅助空间。在使用它对两个己有序的序列归并,将有无比的优势。其时间复杂度无论是在最好情况下还是在最坏情况下均是O(nlog2n)。对数据的有序性不敏感。若数据节点数据量大,那将不适合。但可改造成索引操作,效果将非常出色。

三、排序方法的选择

因为不同的排序方法适应不同的应用环境和要求,所以选择合适的排序方法很重要

(1)若n较小,可采用直接插入或直接选择排序。

当记录规模较小时,直接插入排序较好,它会比选择更少的比较次数;

但当记录规模较大时,因为直接选择移动的记录数少于直接插人,所以宜用选直接选择排序。

这两种都是稳定排序算法。

(2)若文件初始状态基本有序(指正序),则应选用直接插人、冒泡或随机的快速排序为宜(这里的随机是指基准取值的随机,原因见上的快速排序分析);这里快速排序算法将不稳定。

(3)若n较大,则应采用时间复杂度为O(nlog2n)的排序方法:快速排序、堆排序或归并排序序。

快速排序是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短;

堆排序虽不会出现快速排序可能出现的最坏情况。但它需要建堆的过程。这两种排序都是不稳定的。

归并排序是稳定的排序算法,但它有一定数量的数据移动,所以我们可能过与插入排序组合,先获得一定长度的序列,然后再合并,在效率上将有所提高。

(4)特殊的箱排序、基数排序

它们都是一种稳定的排序算法,但有一定的局限性:

1>关键字可分解。

2>记录的关键字位数较少,如果密集更好

3>如果是数字时,最好是无符号的,否则将增加相应的映射复杂度,可先将其正负分开排序。

四、AS中排列数组

1.申请一个长度为n的数组A:

var n:Number = 400;

var A:Array = new Array(n);

for (i=0; i < n; i++) {

A[i] = i;

}

trace(A);

2.将长度为n的数组打乱次序:

for (i=0; i < n; i++) {

var ran = int(Math.random()*n);

var temp = A[i];

A[i] = A[ran];

A[ran] = temp;

}

trace(A)

3.将数组中的所有元素倒排序:

A.reverse();

trace(A)

五、AS实现排序算法:

在执行各各排序算法之前,已经默认存在一个乱序的数组 A[400],默认代码:

var n:Number = 400;

var A:Array = new Array(n);

for (i=0; i < n; i++) {

A[i] = i;

}

for (i=0; i < n; i++) {

var ran = int(Math.random()*n);

var temp = A[i];

A[i] = A[ran];

A[ran] = temp;

}

1.直接插入排序

for (i = 0; i < n; i++) {

var temp = A[i];

for (j = i; j > 0 && temp < A[j - 1]; j--) {

A[j] = A[j - 1];

A[j - 1] = temp;

}

}

2.直接选择排序

for (i = 0; i < n - 1; i++) {

var s:Number = i;

for (j = s + 1; j < n; j++) {

if (A[j] < A[s]) {

s = j;

}

}

var temp = A[i];

A[i] = A[s];

A[s] = temp;

}

3.冒泡排序

for (i = 0; i < n; i++) {

for (j = i; j < n; j++) {

if (A[i] > A[j]) {

var temp = A[i];

A[i] = A[j];

A[j] = temp;

}

}

}

4.希尔排序

var increment = 6;

while (increment > 1) {

increment = int(increment / 3 + 1);

Shellpass(increment);

}

function Shellpass(c) {

for (i = c; i < n; i++) {

if (A[i] < A[i - c]) {

var temp = A[i];

j = i - c;

do {

A[j + c] = A[j];

j = j - c;

} while (j > 0 && temp < A[j]);

A[j + c] = temp;

}

}

}

5.快速排序

function QuickSort(A, low, hig) {

var i = low, j = hig;

var mid = A[int((low + hig) / 2)];

do {

while (A[i] < mid) {

i++;

}

while (A[j] > mid) {

j--;

}

if (i <= j) {

var temp = A[i];

A[i] = A[j];

A[j] = temp;

i++;

j--;

}

} while (i <= j);

if (low < j) {

arguments.callee(A,low,j);

}

if (i < hig) {

arguments.callee(A,i,hig);

}

}

QuickSort(A,0,n - 1);

6.二路归并

var B:Array = new Array(A.length);

for (k = 1; k < n; k *= 2) {

MergePass(k);

}

function MergePass(len) {

for (i = 0; i + 2 * len < n; i = i + 2 * len) {

MergeA(i,i + len - 1,i + 2 * len - 1);

}

if (i + len < n) {

MergeA(i,i + len - 1,n - 1);

}

}

function MergeA(low, m, hig) {

var i = low, j = m + 1, z = 0;

while (i <= m && j <= hig) {

B[z++] = (A[i] <= A[j]) ? A[i++] : A[j++];

}

while (i <= m) {

B[z++] = A[i++];

}

while (j <= hig) {

B[z++] = A[j++];

}

for (z = 0, i = low; i <= hig; z++, i++) {

A[i] = B[z];

}

篇6:NBSI2内部功能实现大揭谜数据库教程

我们经常在设计数据库的时候用一个系统自动分配的ID来作为我们的主键,但是在ORACLE 中没有这样的功能,我们

可以通过采取以下的功能实现自动增加ID的功能

1.首先创建 sequence

create sequence seqmax increment by 1

2.使用方法

select seqmax.nextval ID from dual

就得到了一个ID

篇7:NBSI2内部功能实现大揭谜数据库教程

那么,怎么生成BOM表呢?下面的CAD教程中,我们将以浩辰CAD燕秀模具为例,演示一下如何利用其BOM功能快速生成BOM表格数据。

首先,运行浩辰CAD燕秀模具2011的BOM功能,软件会弹出对话框(如图1)

图1

从对话框中我们可以看出,浩辰CAD燕秀模具2011的BOM功能提供了新建、插入、修改等三种编辑模式。在新建模式中,零件名称、零件规格、材料、数量、备注、序号等很多内容可以进行可视化编辑,而且已经编辑的内容可以使用修改状态修改,这些人性化的设定都使新建BOM表的过程变得更加直观、便捷,

而在自动测量定料尺寸中,我们还可以对图纸中的模板进行自动尺寸测量(如图2)。

图2

例如,当我们添加公模板和母模板的标注时,软件将会进行自动尺寸测量,并呈现出如下效果(如图3)

图3

而当我们在某个序号前忘记标注一个对象时,我们就可以使用插入模式,浩辰CAD燕秀模具2011软件的BOM表插入模式序号是自动更新的,不用二次输入,明细表也同步更新。

从以上演示我们可以发现,浩辰CAD燕秀模具2011中的BOM表功能除了具备关于BOM表的基本功能以外,还具有很多智能化、人性化的功能,这可以方面我们快速生成美观大方的BOM表格。

篇8:NBSI2内部功能实现大揭谜数据库教程

我们知道现在大多数导航系统,都是通过实时接收美国GPS卫星发送的定位信号,并通过不断的地图计算实时准确指明我们所设定的目的地路径和距离,从而实现其导航这个功能。但是,在我们全家的多次出行导航仪使用过程中,我发现它还存在一个最大的缺点:不能实时判断我们将经过的道路的拥堵情况,只能简单根据导航仪系统内所存放的固定(经验)数据进行路径计算和引导。这个缺点在一些城市交通高峰时间路段和高速公路发生交通事故、意外拥堵时,表现得尤为突出。也就是说,现在的导航系统并非最智能,还是存在着缺陷,主要就是不能判断将要通过的道路情况实时提供拥堵路径的解决方案。

我的想法是改变导航仪目前只单向接收定位卫星信号的这个模式,把导航仪、GPS卫星以及城市里或公路上存在的wifi、3g信号基站结合起来。做到双向或多向的数据信号交换,实现地面交通数据实时采集、拥堵路段避让、最优路径调整三位一体的导航方式。它的主要想法和功能实现步骤是:1、所有的导航仪在进行导航时都不断发送自己目前所在位置的信息给导航公司;2、导航公司根据每个导航仪所发信息能够计算出实时道路拥堵的情况;3,每个导航仪根据导航公司发布的道路拥堵情况进行目的地路径的重新调整。它其实就是一个智能的交通情况采集辨认系统,相当于把每个导航仪都变成一个信息采集器:比方根据同一路段的二台以上导航仪行进速度同时减慢或停顿,就可以判定该路段已出现拥堵,如果定位信息一直不停变化,就代表这个地区很流畅。

篇9:MySQL教程数据库教程

■ 如何利用mysql客户机程序与MySQL通信。

■ SQL 语言的基本语句。(如果您曾经使用过其他RDBMS,从而熟悉SQL,那么浏览一下这个教程,看看SQL 的MySQL版与您熟悉的版本有何差别也是很好的。)正如上一节所述, MySQL采用客户机/服务器体系结构,其中服务器运行在存放数据库的机器上,而客户机通过网络连接到服务器。这个教程主要基于mysql客户机的应用。mysql读取您的SQL 查询,将它们发送给服务器,并显示结果。mysql运行在MySQL所支持的所有平台上,并提供与服务器交互的最直接的手段,因此,它首先是一个逻辑上的客户机。

在本书中,我们将用samp_db 作为样例数据库的名称。但是有可能在您完成本例子的过程中需要使用另一个数据库名。因为可能在您的系统上已经有某个人使用了samp_db 这个名称,或者管理员给您指定了另一个数据库名称。在后面的例子中,无论是哪种情况,都用数

据库的实际名称代替samp_db。表名可以像例子所显示的那样精确地使用,即使系统中的多个人都具有他们自己的样例数据库也是如此。顺便说一下,在MySQL中,如果有人使用了相同的表名也没什么关系。一旦各个用户都具有自己的数据库, MySQL将一直保留这些数据库名,防止各用户互相干扰。

1.4.1基本要求

为了试验这个教程中的例子,必须安装MySQL。特别是必须具有对MySQL客户机和某个MySQL服务器的访问权。相应的客户机程序必须位于您的机器上。至少需要有mysql程序,最好还有mysqlimport程序。服务器也可以位于您的机器上,尽管这不是必须的。实际上,只要允许连接到服务器,那么服务器位于何位置都没有关系。若服务器正巧运行在您的机器上,适当的客户机程序又已经安装,那么就可以开始试验了。如果您尚需设法搞到MySQL,可参阅附录A“获得和安装软件”的说明。如果您正自己安装MySQL,可参阅这一章,或把它给管理员看。如果网络访问是通过一个因特网服务商(ISP)进行的,那么可查看该服务商是否拥有MySQL。如果该ISP 不提供MySQL服务,可查看附录J“因特网服务商”以得到某些选择更适合的服务商的建议。

除MySQL软件外,还需要得到创建样例数据库及其表的权限。如果您没有这种权限,可以向MySQL管理员咨询。管理员可通过运行mysql并发布如下的命令提供这种权限:

MySQL与mysql的区别

为了避免混淆,应该说明,“MySQL”指的是整个MySQLRDBMS,而“mysql”代表的是一个特定的客户机程序名。它们的发音都是相同的,但可通过不同的大小写字符和字体来区分。关于发音,MySQL的发音为“my-ess-queue-ell”。我们知道这是因为MySQL参考指南中是这样发音的。而SQL 的发音为“sequel”或“ess-queue-ell”。我不认为哪个发音更好一些。愿意读哪个音都可以,不过在您对别人读的时候,他可能会用他认为是“正确”的发音对您进行纠正。

前一个命令在paul 从localhost(服务器运行在正运行的同一主机)连接时,允许它完全访问samp_db 数据库及它的所有表。它还给出了一个口令secret。第二个命令与第一个类似,但允许paul 从任何主机上连接(“%”为通配符)。也可以用特定的主机名取代“%”,使paul只能从该主机上进行连接。(如果您的服务器允许从localhost 匿名访问,由于服务器搜索授权表查找输入连接匹配的方式的原因,这样一个GRANT 语句可能是必须的。)关于GRANT语句以及设置MySQL用户账号的更详细信息,可在第11章“常规的MySQL管理”找到。

1.4.2 取得样例数据库的分发包

这个教程在某些地方要涉及来自“样例数据库分发包”中的文件。有的文件含有帮助来设置样例数据库的查询或数据。为了得到这个分发包,可参阅附录A。在打开这个分发包时,将创建一个名为samp_db 的目录,此目录中含有所需的文件。无论您在哪个地方试验与样例数据库有关的例子,建议都移入该目录。

1.4.3 建立和中止与服务器的连接

为了连接到服务器,从外壳程序(即从UNIX 提示符,或从Windows 下的DOS 控制台)激活mysql程序。命令如下:

其中的“%”在本书中代表外壳程序提示符。这是UNIX 标准提示符之一;另一个为“$”。在Windows 下,提示符类似“c:>”。

mysql命令行的options 部分可能是空的,但更可能的是发布一条类似如下的命令:

在激活mysql时,有可能不必提供所有这些选项;确切使用的命令请咨询MySQL管理员。此外,可能还需要至少指定一个名称和一个口令。

在刚开始学习MySQL时,大概会为其安全系统而烦恼,因为它使您难于做自己想做的事。(您必须取得创建和访问数据库的权限,任何时候连接到数据库都必须给出自己的名字和口令。)但是,在您通过数据库录入和使用自己的记录后,看法就会马上改变了。这时您会很欣赏MySQL阻止了其他人窥视(或者更恶劣一些,破坏!)您的资料。

下面介绍选项的含义:

■ -hhost_name(可选择形式:--host=host_name)

希望连接的服务器主机。如果此服务器运行在与mysql相同的机器上,这个选项一般可

省略。

■ -uuser_name(可选择的形式:--uuser=user_name)您的MySQL用户名。如果使用UNIX 且您的MySQL用户名与注册名相同,则可以省去这个选项;mysql将使用您的注册名作为您的MySQL名。在Windows 下,缺省的用户名为ODBC。这可能不一定非常有用。可在命令行上指定一个名字,也可以通过设置USER 变量在环境变量中设置一个缺省名。如用下列set 命令指定paul 的一个用户名:

■ - p(可选择的形式:--password)

这个选项告诉mysql提示键入您的MySQL口令。注意:可用-pyour_password 的形式(可选择的形式: --password =your_password)在命令行上键入您的口令。但是,出于安全的考虑,最好不要这样做。选择-p 不跟口令告诉mysql在启动时提示您键入口令。例如:

在看到Enter password: 时,键入口令即可。(口令不会显到屏幕,以免给别人看到。)请注意,MySQL口令不一定必须与UNIX 或Windows 口令相同。如果完全省略了-p 选项,mysql就认为您不需要口令,不作提示。请注意: -h 和-u选项与跟在它们后面的词有关,无论选项和后跟的词之间是否有空格。而-p 却不是这样,如果在命令行上给出口令, -p 和口令之间一定不加空格。例如,假定我的MySQL用户名和口令分别为paul 和secret,希望连接到在我注册的同一机器上运行的服务器上。下面的mysql命令能完成这项工作:

在我键入命令后, mysql显示Enter password: 提示键入口令。然后我键入口令( * * * * * *表明我键入了secret)。如果一切顺利的话, mysql显示一串消息和一个“ mysql>”提示,表示它正等待我发布查询。完整的启动序列如下所示:

为了连接到在其他某个机器上运行的服务器,需要用-h 指定主机名。如果该主机为pit-viper.snake.net,则相应的命令如下所示:

在后面的说明mysql命令行的多数例子中,为简单起见,我们打算省去- h、-u和-p 选项。并且假定您将会提供任何所需的选项。

有很多设置账号的方法,从而不必在每次运行mysql时都在连接参数中进行键入。这个问题在1. 5节“与mysql交互的技巧”中介绍。您可能会希望现在就跳到该节,以便找到一些更易于连接到服务器的办法。

在建立了服务器的一个连接后,可在任何时候键入下列命令来结束会话:

还可以键入Control-D 来退出,至少在UNIX 上可以这样。

1.4.4 发布查询

在连接到服务器后,就可以发布查询了。本节介绍有关与mysql交互应该了解的一些知识。为了在mysql中输入一个查询,只需键入它即可。在查询的结尾处,键入一个分号(“;”)并按Enter 键。分号告诉mysql该查询是完整的。(如果您喜欢键入两个字符的话,也可以使用“ g”终止查询。)在键入一个查询之后, mysql将其发送到服务器上。该服务器处理此查询并将结果送回mysql,mysql将此结果显示出来。下面是一个简单的查询例子和结果:

它给出当前的日期和时间。(NOW() 函数本身并无多大用处,但可将其用于表达式中。如比较当前日期和其他日期的差异。)

mysql还在结果中显示行数计数。本书在例子中一般不给出这个计数。因为mysql需要见到分号才发送查询到服务器,所以在单一的行上不需要键入分号。如果有必要,可将一个查询分为几行,如下所示:

请注意,在键入查询的第一行后,提示符从‘mysql’ 变成了‘- >’;这表示mysql允许继续键入这个查询。这是一个重要的提示,因为如果在查询的末尾忘记了分号,此提示将有助于提醒您查询尚不完整。否则您会一直等下去,心里纳闷为什么mysql执行查询为什么这么长的时间还没完;而mysql也搞不清为什么结束查询的键入要花您那么多的时间!

大部分情况下,用大写字符、小写字符或大小写字符混合键入查询没什么关系。下列查询全是等价的:

本书中的例子用大写字符表示SQL 关键字和函数名,用小写字符表示数据库、表和列名。

如果在查询中调用一个函数,在函数名和后跟的圆括号中间不允许有空格,例:

这两个查询看上去差别不大,但第二个失败了,因为圆括号并没有紧跟在函数名的后面。如果已经开始键入一个多行的查询,而又不想立即执行它,可键入‘ c’ 来跳过(放弃)它,如:

请注意,提示符又变回了‘mysql>’,这表示mysql为键入的新查询作好了准备。可将查询存储在一个文件中并告诉mysql从文件中读取查询而不是等待键盘输入。可利用外壳程序键入重定向实用程序来完成这项工作。例如,如果在文件my_file.sql 中存放有查

询,可如下执行这些查询:

可用这种办法调用任何所需的文件。这里用后缀为“.sql”来表示该文件含有SQL 语句。执行mysql的这种方法将在输入数据到samp_db 数据库时的“增加新记录”中使用。为了装载一个表,让mysql从某个文件中读取INSERT 语句比每次用手工键入这些语句更为方便。

本教程的其余部分向您提供了许多可以自己试试的查询。这些查询以‘mysql>’ 提示为前导后跟结束分号,这些例子通常都给出了查询输出结果。可以按给出的形式键入这些查询,所得到的结果应该与自学材料中的相同。给出的查询中无提示符的或无分号语句结束符的只是用来说明某个要点,不用执行它们。(如果愿意您可以试一下,但如果试的话,请记住给语句末尾加一个分号。)本书后面的章节中,我们一般不给出‘mysql>’ 提示或SQL 语句的分号。这样做的原因是为了可以在非mysql客户机程序的语言环境(如在Perl 脚本中或PHP 脚本中)中发布查询,在这些语言环境中,既无提示符也不需要分号。在专门针对mysql输入一个查询的场合会作出相应的说明。

1.4.5 创建数据库

现在开始创建samp_db 样例数据库及其表,填充这些表并对包含在这些表中的数据进行一些简单的查询。

使用数据库涉及几个步骤:

1) 创建(初始化)数据库。

2) 创建数据库中的表。

3) 对表进行数据插入、检索、修改或删除。

检索现有数据是对数据库执行的最简单且常见的操作。另外几个最简单且常见的操作是插入新数据、更新或删除现有数据。较少使用的操作是创建表的操作,而最不常用的操作是创建数据库。

我们将从头开始,先创建数据库,再插入数据,然后对数据进行检索。为了创建一个新的数据库,用mysql连接到数据库然后发布CREATE DATABASE 语句,此语句指定了数据库名:

在创建表以及对这些表进行各种操作之前,必须先创建samp_db 数据库。创建数据库后,这个新创建的数据库并不是当前数据库。这可从执行下面的查询看出:

为了使samp_db 成为当前数据库,发布USE 语句即可:

USE 为少数几个不需要终结符的语句之一,当然,加上终结符也不会出错。HELP 是另一个不需要终结符的语句。如果想了解不需要终结符的语句有哪些,可发布HELP 语句。在发布了USE 语句后,samp_db 成为缺省数据库:

使数据库成为当前数据库的另一个方法是在激活mysql时在命令行上指定它,如下所示:

事实上,这是一个命名要使用的数据库的方法。如果需要连接参数可在数据库名前指定。例如,下列两个命令使我们能连接到在本地主机和p i t - v i per.snake.net 上的samp_db 数据库上:

除非另有指定,否则后面的例子都假定在激活mysql时,在命令行上给出samp_db 使其成为当前数据库。如果激活数据库时忘了在命令行上指定数据库,只需发布USE samp_db 语句即可。

1.4.6 创建表

本节中,我们将创建样例数据库samp_db 所需的表。我们首先考虑美国历史同盟需要的表。然后再考虑学分保存方案所需的表。在某些数据库的书籍中,在这里要大讲分析与设计、实体―关系图、标准程序以及诸如此类的东西。这里确实也可以讲这些东西,但是我宁可只讲点实用的东西,比方说,我们的数据库应该是怎样的:数据库中将包含什么内容,每个表中有哪些数据以及由决定如何表示数据而带来的一些问题。这里所作出的关于数据表示的选择并不是绝对的。在其他场合下,可能会选择不同的方式来表示类似的数据,这取决于应用的需要以及打算将数据派何用途。

1. 美国历史同盟所需的表

美国历史同盟的表设计相当简单:

■ 总统( p r e s i d e n t )表。此表含有描述每位总统的记录。同盟站点上的联机测验要使用这个表。

■ 会员( member )表。此表用来维护同盟每个会员的当前信息。这些信息将用来建立会员地址名录的书面和联机版本、发送会员资格更新提示等等。

(1) president表

president 表很简单,因此我们先讨论它。这个表将包含每位美国总统的一些基本信息:

■ 姓名。姓名在一个表中可用几种方式表示。如,可以用一个单一的列来存放完整的姓名,或者用分开的列来分别容纳名和姓。当然用单一的列更为简单,但是在使用上会带来一些限制,如:

■ 如果先输入只有名的姓名,则不可能对姓进行排序。

■ 如果先输入只有姓的姓名,就不可能对具有名的姓名进行显示。

■ 难以对姓名进行搜索。例如,如果要搜索某个特定的姓,则必须使用一个特定的模式,并且查找与这个模式匹配的姓名。这样较之只查找姓效率更低和更慢。member 表将使用单独的名和姓的列以避免这些限制。名列还存放中名(注:西方国家的姓名一般将名放在前,姓放在后,而且除了有名和姓外,有时还有中名,这是在位置上介于名和姓之间的中间名字)或首字母。这样应该不会削弱我们可能进行的任何一种排序,因为一般不可能对中名进行排序(或者甚至不会对名进行排序)。姓名即可以“ Bush, George W. ”格式显示,也可以“G e o rge W. B us h”格式显示。还有一种稍显复杂一点的情形。一个总统( Jimmy Carter)在其姓名的末尾处有一

个“ J r. ”,这时怎样做?根据名字打印的格式,这个总统的姓名显示为“ J a m e s E . C a r ter, J r.”或“C a r ter, James E., Jr.”,“J r.”与名和姓都没有关系,因此我们将建另外一个字段来存放姓名的后缀。这表明在试图确定怎样表示数据时,即使一个特殊的值也可能会带来问题。它也表明,为什么在将数据放入数据库前,尽量对数据值的类型进行了解是一个很好的想法。如果对数据了解不够,那么有可能在已经开始使用一个表后,不得不更改该表的结构。这不一定是个灾难,但通常应该避免。

■ 出生地(城市和州)。就像姓名一样,出生地也可以用单个列或多个列来表示。使用单列更为简单些,但正如姓名中的情形一样,独立的多个列使我们可以完成用单个列不方便完成的事情。例如,如果城市和州分别给出,查找各位总统出生在哪个州的记录就会更容易一些。

■ 出生日期和死亡日期。这里,唯一特殊的问题是我们不能要求都填上死亡日期,因为有的总统现在还健在。MySQL提供了一个特殊的值NULL,表示“无值”,可将其用在死亡日期列中以表示“仍然健在”。

(2) member 表

存储历史同盟会员清单的member 表在每个记录都包含单个人员的基本描述信息这一点上,类似于president 表。但是每个member 的记录所含的列更多,member 表的各列如下:

■ 姓名。使用如president 表一样的三个列来表示:姓、名(如果可能的话还有中名)、后缀。

■ ID 号。这是开始记录会员时赋给每个会员的唯一值。以前同盟未用ID 号,但现在的记录做得更有系统性,所以最好开始使用ID 号。(我希望您找到有利于使用MySQL并考虑到其他的将它用于历史同盟记录的方法。使用数字,将member 表中的记录与其他与会员有关的表中的记录相关联要更容易一些。)

■ 截止日期。会员必须定期更新他们的会员资格以免作废。对于某些应用,可能会用到最近更新的日期,但是近更新日期不适合于历史同盟。会员资格可在可变的年数内(一般为一年、二年、三年或五年)更新,而最近更新的日期将不能表示下一次更新必须在何时进行。此外,历史同盟还允许有终生会员。我们可以用未来一个很长的日期来表示终生会员,但是用NULL 似乎更为合适,因为“无值”在逻辑上对应于“永不终止”。

■ 电子邮件地址。对于有电子邮件地址的会员,这将使他们能很容易地进行相互之间的通信。作为历史同盟秘书,这使您能电子化地发送更新通知给会员,而用不着发邮政信函。这比到邮局发送信函更容易,而且也不贵。还可以用电子邮件给会员发送他们的地址名录条目的当前内容,并要求他们在有必要时更新信息。

■ 邮政地址。这是与没有电子邮件(或没有返回信息)的会员联络所需要的。将分别使用街道地址、城市、州和Zip 号。街道地址列又可以用于有诸如P.O. Box 123 而不是123 Elm St. 的会员的信箱号。我们假定所有同盟会员全都住在美国。当然,对于具有国际会员的机构,此假设过于简化了。如果希望处理多个国家的地址,还需要对不同国家的地址格式作一些工作。例如,这里的Zip 号就不是一个国际标准,有的国家有省而不是州。

■ 电话号码。与地址字段一样,这个列对于联络会员也是很有用的。

■ 特殊爱好的关键词。假定每个会员一般都对美国历史都有兴趣,但可能有的会员对某些领域有特殊的兴趣。此列记录了这些特殊的兴趣。会员可以利用这个信息来找到其他具有类似兴趣的会员。

(3) 创建表

现在我们已经作好了创建历史同盟表的准备。我们用CREATE TABLE 语句来完成这项工作,其一般格式如下:

其中tbl_name 代表希望赋予表的名称。column_specs 给出表中列的说明,以及索引的说明(如果有的话)。索引能使查找更快;我们将在第4 章“查询优化”中对其作进一步的介绍。

president 表的CREATE TABLE 语句如下所示:

如果想自己键入这条语句,则调用mysql,使samp_db 为当前数据库:

然后,键入如上所示的CREATE TABLE 语句。(请记住,语句结尾要增加一个分号,否则mysql将不知道哪儿是语句的结尾。)

为了利用来自样例数据库分发包的预先写下的描述文件来创建president 表,可从外壳程序运行下列命令:

不管用哪种方法调用mysql,都应该在命令行中数据库名的前面指定连接参数(主机名、用户名或口令)。CREATE TABLE 语句中每个列的说明由列名、类型(该列将存储的值的种类)以及一些可能的列属性组成。president 表中所用的两种列类型为VARCHAR 和DATE。VARCHAR(n)代表该列包含可变长度的字符(串)值,其最大长度为n 个字符。可根据期望字符串能有多长来选择n 值。

state 定义为VARCHAR( 2 );即所有州名都只用其两个字符的缩写来表示。其他的字符串列则需要更长一些,以便存放更长的值。

我们使用过的其他列类型为DATE。这种列类型表示该列存储的是日期值,这一点也不令人吃惊。而令人吃惊的是,日期的表示以年份开头。其标准格式为“ Y Y Y Y- M M - D D”(例如,“1999 - 07 - 18”)。这是日期表示的ANSI SQL 标准。我们用于president 表的唯一列属性为NULL(值可以缺少)和NOT NULL(必须填充值)。多数列是NOT NULL 的,因为我们总要有一个它们的值。可有NULL 值的两个列是s uff i x(多数姓名没有后缀)和death(有的总统仍然健在,所以没有死亡日期)。member 表的CREATE TABLE 语句如下所示:

将此语句键入mysql或执行下列外壳程序命令:

从列的类型来看,member 表并不很有趣:所有列中,除了一列之外,其他列都是可变长字符串。这个例外的列就是e x p i r a t i o n,为DATE 型。终止日期值有一个缺省值为“0 0 0 0 - 0 0 -0 0”,这是一个非NULL 的值,它表示未输入合法的日期值。这样做的原因是expiration 可以是NULL,它表示一个会员是终身会员。但是,因为此列可以为NULL,除非另外指定一个不同的值,否则它将取缺省值“ 0 0 0 0 - 0 0 - 0 0”。如果创建了一个新会员记录,但忘了指定终止日期,该会员将成为一个终身会员!通过采用缺省值“ 0 0 0 0 - 0 0 - 0 0”的方法,避免了这个问题。它还向我们提供了一种手段,即可以定期地搜索这个值,以找出过去未正确输入终止日期的记录。

请注意,我们“忘了”放入会员ID 号的列。这是专门为了以后练习使用ALTER TABLE语句而遗留下的。现在让我们来验证一下MySQL是否确实如我们所期望的那样创建了表。在mysql中,发布下列查询:

与MySQL3.23 一样,此输出还包括了显示访问权限信息的另一个列,这里没有给出,

因为它使每行太长,不易显示。

这个输出结果看上去和我们所期望的非常一致,除了state 列的信息显示它的类型为CHAR( 2 )。这就有点古怪了,我们不是定义它为VARCHAR(2) 了吗?是的,是这样定义的,但是MySQL已经悄悄地将此类型从VARCHAR 换成了CHAR。原因是为了使短字符串列的

存储空间利用更为有效,这里不多讨论。如果希望详细了解,可参阅第3 章中关于ALTE RTABLE 语句的介绍。但对这里的使用来说,两种类型没有什么差别。

如果发布一个DESCRIBE member 查询,mysql也会显示member 表的类似信息。DESCRIBE 在您忘了表中的列名、需要知道列的类型、了解列有多宽等的时候很有用。它对于了解MySQL存储表行中列的次序也很有用。列的这个存储次序在使用INSERT 或LOAD DATA 语句时非常重要,因为这些语句期望列值以缺省列的次序列出。DESCRIBE 可以省写为DESC,或者,如果您喜欢键入较多字符,则DESCRIB Etbl_name 另一个等同的语句为SHOW COLUMNS FROM tbl_name。

如果忘了表名怎么办?这时可以使用SHOW TABLE S。对于samp_db 数据库,我们目前

为止创建了两个表,其输出结果如下:

如果您甚至连数据库名都记不住,可在命令行上调用mysql而不用给出数据库名,然后发布SHOW DATABASES 查询:

数据库的列表在不同的服务器上是不同的,但是至少可以看到samp_db 和mysql;后一个数据库存放控制MySQL访问权限的授权表。DESCRIBE 与SHOW 查询具有可从外壳程序中使用的命令行等同物,如下:

% mysqlshow 与SHOW DATABASES 一样列出所有数据库

% mysqlshow db _ name 与SHOW TABLES 一样列出给定数据库的表

% mysqlshow db_name tbl_name 与DESCRIBE tbl_name 一样,列出给定表中的列

2. 用于学分保存方案的表

为了知道学分保存方案需要什么表,我们来看看在原来学分簿上是怎样记学分的。图1- 2示出学分簿的一页。该页的主体是一个记录学分矩阵。还有一些对学分有意义的必要信息。学生名和ID 号列在矩阵的一端。(为了简单好看,只列出了四个学生。)在矩阵顶端,记录了进行测验和测试的日期。图中示出9月3号、6号、16号和2 3号进行测验, 9月9号和10月1号进

行测试。

为了利用数据库来记录这些信息,需要一个学分表。这个表中应该包含什么记录呢?很明显,每一行都需要有学生名、测验或测试的日期以及学分。图1-3 示出了用这样的表表示的一些来自学分簿的学分。(日期以MySQL的表示格式“Y Y Y Y- M M - D D”表示。)

但是,以这种方式设置表似乎有点问题。好像少了点什么。请看图1- 3中的记录,我们分辨不出是测验的学分还是测试的学分。如果测验和测试的学分权重不同,在确定最终的学分等级时知道学分的类型是很重要的。或许可以试着从学分的取值范围来确定学分的类型(测验的学分一般比测试的学分少),但是这样做很不方便,因为这需要进行判断,而且在数据中也不明显。可以通过记录学分的类型来进行区分,如对学分表增加一列,此列包含“ T”或“Q”以表示是“测试”或是“测验”,如图1-4 所示。这具有使学分数据类型清析易辨的优点。不利的地方是这个信息有点冗余。显然对具有同一给定日期的记录,学分的类型列总是取相同的值。9月2 3日的学分总是为“ Q”类型,而10月1日的学分其类型总是具有“ T”类型。这样令人很不满意。如果我们以这种方式记录一组测验或测试的学分,不仅要为每个新记录输入相同的日期,而且还要一再重复地输入相同的学分类型。谁会希望一再输入冗余的信息呢?

我们可以试试另外一种表示。不在score 表中记录学分类型,而是从日期上区分它们。我们可以做一个日期列表,用它来记录每个日期发生的“学分事件”(测验或测试)。然后可以将学分与这个事件列表中的信息结合,确定学分是测验学分还是测试学分。这只要将score 表记录中的日期与event 表中的日期相匹配得出事件类型即可。图1- 5示出这个表的设计并演示了score 表记录与9月2 3日这个日期相关联的工作。通过将score 表中的记录与event 表中记录相对应,我们知道这个学分来自测验。

这比根据某些猜测来推断学分类型要好得多;我们可以根据明确记录在数据库中的数据来直接得到学分类型。这也比在score 表中记录学分类型更好,因为我们只需对每个类型记录一次。

但是,在第一次听到这种事情时(即结合使用多个表中的信息),可能会想,“嗯,这是一个好主意,但是不是要做很多工作呢?会不会使工作更复杂了?”在某种程度上,这种想法是对的。处理两个记录表比处理一个要复杂。但是再来考察一下学分簿(见图1- 2)。不是也记录了两套东西吗?考虑下列事实:

■ 在学分矩阵中用两个单元记录学分,其中每个单元都是按学生名字和日期(在矩阵的旁边和顶上)进行索引的。这代表了一组记录;与score 表的作用相同。

■ 怎样知道每个日期代表的事件类型呢?在日期上方写了字符“ T”或“Q”!因此,也在矩阵顶上记录了日期和学分类型之间的关系。它代表第二组记录;与event 表的作用相同。

换句话说,这里建议在两个表中记录信息与用学分簿记录信息所做的工作没什么不同。唯一不同的是,这两组信息在学分簿中不是那么明显地被分开。在图1- 5中所示的event 表的设计中加了一个要求,那就是日期必须是唯一的,因为要用它连接score 与event 表的记录。换句话说,同一天不能进行两次测验,或者同一天不能进行一次测验和一次测试。否则,将会在score 表中有两个记录并且在event 表中也有两个记录,全都具有相同的日期,这时就不知道应如何将score 的记录与event 的记录进行匹配。如果每天不多于一个学分事件,这就是一个永远不会出现的问题,可是事实并非如此简单。有时,一天中可能会有不止一个学分事件。我常听有的人说他们的数据,“那种古怪情况从不会出现。”然而,如果这种情况确实出现时,就必须重新设计表以适应这种情况引起的问题。最好是预先考虑以后可能出现的问题,并预先准备好怎样处理他们。因此,我们假定有时可能会需要同一天记录两组学分。我们怎样处理呢?如果出现这种情况,问题并不难解决。只要对处理数据的方式作一点小的更改,就可使同一日期上有多个事件而不会引起问题:

1) 增加一个列到event 表,并用它来给表中每个记录分配一个唯一的编号。实际上这就给了每个事件一个唯一的ID 号,因此我们称该列为event_id 列。(如果觉得这好像是做傻事,可看一下图1-2 中的学分簿,其中已经有这个特征了。事件ID 正好与学分簿分数矩阵中列号相似。这个编号可能没有清晰地写在那儿并标上“事件ID,”但是它确实在那儿。)

2) 当向score 表中输入学分时,输入的是事件ID 而不是日期。这些改变的结果如图1-6 所示。现在连接score 和event 表时,用的是事件ID 而不是日期,而且不仅用event 表来决定每个学分的类型,而且还用它来决定其日期。并且在event 表中不再有日期必须唯一这个限制,而唯一的是事件ID。这表示同一天可以有一打测试和测验,而且能够在记录里边直接保存它们。(毫无疑问,学生们听到这个一定浑身发抖。)不幸的是,从人的观点来看,图1-6 中的表设计较前一个更不能令人满意。score 表也更为抽象一些,因为它包含的从直观上可以理解的列更少。而图1-4 中此表的设计直观且容易理解,因为那个score 表具有日期和学分类型的列。当前的score 表如图1-6 所示,日期和学分类型的列都没有了。这极大地去除了作为人能够很容易考虑的一切。谁希望看到其中有“事件ID”的score 表?如果有的话,也不代表我们大多数人。

此时,可看到能够电子化地完成学分记录,且在赋予学分等级时不必做各种乏味的手工计算。但是,在考虑了如何实际在一个数据库中表示学分信息后,又会被怎样抽象和拆分组成学分信息的表示难住了。自然会产生一个问题:“根本不使用数据库可能会更好一些?或许MySQL不适合我?”正如您所猜测的那样,笔者将从否定的方面对这个问题进行回答,否则这本书就没必要再往下写了。不过,在考虑如何做一件工作时,应考虑各种情况并提问是否最好不使用数据库系统(如MySQL)而使用一些别的东西(如电子表格等):

■ 学分簿有行和列,而电子表格也有。这使学分簿和电子表格在概念上和外观上都非常类似。

■ 电子表格能够完成计算,可以利用一个计算字段来累计每个学生的学分。但是,要对测验和测试进行加权可能有点麻烦,但这也是可以办得到的。另一方面,如果希望只查看某部分数据(如只查看学分或测试),进行诸如男孩与女孩的比较,或以一种灵活的方式显示合计信息等,情况又大有不同了。电子表格的功能显得要差一些,而关系数据库系统完成这些工作相当容易。另外要考虑的一点是为了在关系数据库中进行表示而对数据进行抽象和分解,这个问题并不真的那么难以应付。只要考虑安排数据库使其不会以一种对您希望做的事无意义的方式来表示数据即可。但是,在确定了表示方式之后,就要靠数据库引擎来协调和表示数据了。您肯定不会希望将它视为一堆支离破碎的东西。

例如,在从score 表中检索学分时,不希望看到事件ID;但希望看到日期。这没有什么问题。数据库将会根据事件ID 从event 表中查找出日期。您还可能想要看看是测验的学分或测试的学分。这也不成问题。数据库将用相同的方法查找出学分类型,也是利用事件ID。请记住,这就是如像MySQL这样的关系数据库的优势所在,即,使一样东西与另一样东西相关联,以便从多个来源得出信息并以您实际想看到的形式提供出来。在学分保存数据的情况中,MySQL确实利用事件ID 将信息组合到了一起,而无需人工来完成这件事。

现在我们先来看看,如何使MySQL完成这种将一个东西与另一个东西相联系的工作。

假定希望看到1999年9月2 3号的学分,针对某个特定日期中给出的事件的学分查询如下所示:

相当吓人,是吗?这个查询通过将score 表的记录与event 表的记录连接(关联)来检索学生名、日期、学分和学分的类型。其结果如下所示:

您肯定注意到了,它与图1-4 中给出的表设计相同,而且不需要知道事件ID 就可得出这个结果,只需指出感兴趣的日期并让MySQL查找出哪个学分记录具有该日期即可。如果您一直担心抽象和分解会使我们损失一些东西的话,看到这个世界,就不会有这种担心了。

当然,在考虑过查询后,您还可能对其他别的东西产生担心。即,这个查询看上去有点长并且也有点复杂;是不是做了很多工作写出这样的东西只是为了查找某个给定日期的学分?是的,确实是这样。但是,在每次想要发布一个查询时,有几种方法可以避免键入多行的SQL。一般情况下,一旦您决定如何执行这样一个查询并将它保存起来后,就可以按需要多次执行它。我们将在1. 5节“与mysql交互的技巧”中介绍怎样完成这项工作。

在上述查询的介绍中,我们有点超前了。不过,这个查询比起我们要实际用来得出学分的查询是有点简单了。原因是,我们还要对表的设计作更多的修改。我们将采用一个唯一的学生ID,而不在score 表中记录学生名。(即,我们将使用来自学分簿的“ ID”列的值而不是来自“ Name”列的值。)然后,创建另一个称为student 的表来存放name 和student_id 列(见图1- 7)。

为什么要作出这种修改呢?只有一个原因,可能有两个学生有相同的名字。采用唯一的学生ID 号可帮助区分他们的学分。(这与利用唯一的事件ID 而不是日期来分辨出相同日期的测试或测验完全类似。)在对表的设计作了这样的修改后,实际用来获得给定日期的学分查询变得更为复杂了一些,这个查询如下:

如果您不能立即清楚地读懂这个查询的意思的话,也不必担心。在进一步深入这个教程之后,就能看懂这个查询了。将会从图1- 7中注意到,在student 表中增加了点学分簿中没有的东西。它包含了一个性别列。这便可以做一些简单的事情,如对班级中男孩和女孩的人数计数;也可以做一些更为复杂的事情,如比较男孩和女孩的学分。我们已经设计完了学分保存的几乎所有的表。现在只需要另外

一个表来记录出勤情况即可。这个表的内容相对较为直观,即,一个学生ID 号和一个日期(见图1- 8)。表中的每行表示特定的学生在

给定的日期缺勤。在学分时段末,我们将调用MySQL的计数功能来汇总此表的内容,以便得出每个学生的缺勤数。

既然现在已经知道学分保存的各个表的结构,现在可以创建它们了。student 表的CREATE TABLE 语句如下:

将上述语句键入mysql或执行下列外壳程序命令:

CREATE TABLE 语句创建了一个名为student 的表,它含有三列,分别为: name、s e x和s t ud e n t _ i d,

name 是一个可变长的字符串列,最多可存放20 个字符。这个名字的表示比历史同盟表中所用的表示要简单,它只用了单一的列而不是分别的名和姓列。这是因为我们已经预先知道,不存在无需做另外的工作就使得在多个列上工作得更好的查询样例。sex 表示学生是男孩还是女孩。这是一个ENUM(枚举)列,表示只能取明确地列在说明中的值之一,这里列出的值为:“F”和“M”,分别表示女和男。在某列只具有一组有限值时,ENUM 类型非常有用。我们可以用CHAR(1) 来代替它,但是ENUM 更明确规定了列可以取什么值。如果对包括一个ENUM 列的表发布一条DESCRIBE tbl_name 语句,MySQL将确切地显示可取的值有哪些。顺便说一下, ENUM 列中的值不一定只是单个字符。此列还可以定义为ENUM(‘f e m a l e’,‘m a l e’)。

student_id 为一个整数型列,它将包含唯一的ID 号。通常,大概会从一个中心资料来源处(如学校办公室)取得学生的ID 号,但在这里是我们自己定的。虽然student_id 列只包含一个数,但其定义包括几个部分:

■ INT 说明此列的值必须取整数(即无小数部分)。

■ UNSIGNED 不允许负数。

■ NOT NULL 表示此列的值必须填入。(任何学生都必须有一个ID 号。)

■ AUTO_INCREMENT 是MySQL中的一个特殊的属性。其作用为:如果在创建一个新的student 表记录时遗漏了student_id 的值(或为NULL),MySQL自动地生成一个大于当前此列中最大值的唯一ID 号。在录入学生表时将用到这个这特性,录入学生表时可以只给出name 和sex 的值,让MySQL自动生成student_id 列值。

■ PRIMARY KEY 表示相应列的值为快速查找进行索引,并且列中的每个值都必须是惟一的。这样可防止同一名字的ID出现两次,这对于学生ID 号来说是一个必须的特性。(不仅如此,而且MySQL还要求每个AUTO_INCREMENT 列都具有一个惟一索引。)如果您不理解AUTO_INCREMENT 和PRIMARY KEY 的含义,只要将其想像为一种为每个学生产生ID 号的魔术方法即可。除了要求值唯一外,没有什么别的东西。请注意:如果确实打算从学校办公室取得学生ID 号而不是自动生成它们,则可以按相同的方法定义student_id 列,只不过不定义AUTO_INCREMENT 属性即可。event 表如下定义:

将此语句键入mysql或执行下列外壳程序的命令:

所有列都定义为NOT NULL,因为它们中任何一个值都不能省略。date 列存储标准的MySQLDATE 日期值,格式为“Y Y Y Y- M M - D D”(首先是年)。type 代表学分类型。像student 表中的sex 一样,type 也是一个枚举列。所允许的值为“T”和“Q”,分别表示“测试”和“测验”。event_id 是一个AUTO_INCREMENT 列,类似于student 表中的student_id 列。采用AUTO_INCREMENT 允许生成唯一的事件ID 值。正如student 表中的student_id 列一样,与值的惟一性相比,某个特定的值并不重要。score 表如下定义:

将此语句键入mysql或执行下列外壳程序的命令:

score 为一个INT (整型)列。即,假定学分值总是为一个整数。如果希望使学分值具有小数部分,如5 8 . 5,应该采用浮点列类型,如FLOAT或DECIMAL。student_id 列和event_id 列都是整型,分别表示每个学分所对应的学生和事件。通过利用它们来连接到student 和event 表,我们能够知道学生名和事件的日期。我们将两个列组成了PRIMARY KEY。这保证我们不会对同一测验或测试重复一个学生的学分。而且,这样还很容易在以后更改某个学分。例如,在发现学分录入错时,可以在利用MySQL的REPLACE语句放入一个新记录,替换掉旧的记录。不需要执行DELETE 语句与INSERT 语句;MySQL自动替我们做了。请注意,它是惟一的event_id 和student_id 的组合。在score 表中,两者自身都可能不惟一。一个event_id 值可有多个学分记录(每个学生对应一个记录),而每个student_id 值都对应多个记录(每个测验和测试有一个记录)。用于出勤情况的absence 表如下定义:

将此语句键入mysql或执行下列外壳程序的命令:

student_id 和date 列两者都定义为NOT NULL,不允许省略值。应定义这两列的组合为主键,以免不当心建立了重复的记录。重要的是不要对同一天某个学生的缺旷进行重复计数。

1.4.7 增加新记录

至此,我们的数据库及其表都已经创建了,在下一节“检索信息”中,我们将看到怎样从数据库中取出数据。现在我们先将一些数据放入表中。在数据库中加入数据有几种方法。可通过发布INSERT 语句手工将记录插入某个表中。还可以通过从某个文件读取它们来增加记录,在这个文件中,记录既可以是利用L O A DDATA 语句或mysqlimport 实用程序装入的原始数据值,也可以是预先写成可馈入mysql的INSERT 语句的形式。本节介绍将记录插入表的每种方法。您所应做的是演习各种方法以明了它们是如何起作用的。然后到本节结束处运行那儿给出的命令来清除表并重装它们。这样做,能够保证表中含有作者撰写下一节时所处理的相同记录,您也能得到相同的结果。让我们开始利用INSERT 语句来增加记录,这是一个SQL 语句,需要为它指定希望插入数据行的表或将值按行放入的表。INSERT 语句具有几种形式:

■ 可指定所有列的值

例如:

“I N TO”一词自MySQL3.22.5 以来是可选的。(这一点对其他形式的INSERT 语句也成立。)VALUES 表必须包含表中每列的值,并且按表中列的存放次序给出。(一般,这就是创建表时列的定义次序。如果不能肯定的话,可使用DESCRIBE tbl_name 来查看这个次序。)在MySQL中,可用单引号或双引号将串和日期值括起来。上面例子中的NULL值是用于student 和event 表中的AUTO_INCREMENT 列的。(插入“错误”的值将导致下一个student_id 或event_id 号的自动生成。)自3.22.5 以来的MySQL版本允许通过指定多个值的列表,利用单个的INSERT语句将几行插入一个表中,如下所示:

例如:

这比多个INSERT 语句的键入工作要少,而且服务器执行的效率也更高。

■ 可以给出要赋值的那个列,然后再列出值。这对于希望建立只有几个列需要初始设置的记录是很有用的。

例如:

自MySQL3.22.5 以来,这种形式的INSERT 也允许多个值表:

在列的列表中未给出名称的列都将赋予缺省值。

■ 自MySQL3.22 .10 以来,可以col_name = value 的形式给出列和值。

例如:

在SET 子句中未命名的行都赋予一个缺省值。使用这种形式的INSERT 语句不能插入多行。将记录装到表中的另一种方法是直接从文件读取数据值。可以用LOAD DATA 语句或用mysqlimport 实用程序来装入记录。LOAD DATA 语句起批量装载程序的作用,它从一个文件中读取数据。可在mysql内使用它,如下所示:

该语句读取位于客户机上当前目录中数据文件member.txt 的内容,并将其发送到服务器装入member 表。如果您的MySQL版本低于3 . 2 2 . 15,则LOAD DATA LOCAL 不起作用,因为那时从客户机读取数据的能力是在LOAD DATA 上的。(没有LOCAL 关键字,被读取的文件必须位于服务器主机上,并且需要大多数MySQL用户都不具备的服务器访问权限。)缺省时,LOAD DATA 语句假定列值由tab 键分隔,而行则以换行符结束。还假定各个值是按列在表中的存放次序给出的。也有可能需要读取其他格式的文件,或者指定不同的列次

序。更详细的内容请参阅附录D的LOAD DATA 的条款。mysqlimport 实用程序起LOAD DATA 的命令行接口的作用。从外壳程序调用mysqlimport ,它生成一个LOAD DATA 语句:

mysqlimport 生成一个LOAD DATA 语句,此语句使member.txt 文件被装入member 表。如果您的MySQL版本低于3 . 2 2 . 15,这个实用程序不起作用,因为--local 选项需要L O A DDATA LOCAL。正如使用mysql一样,如果您需要指定连接参数,可在命令行上数据库名前指定它们。mysqlimport 从数据文件名中导出表名(它将文件名第一个圆点前的所有字符作为表名)。例如,member.txt 将被装入member 表,而president.txt 将被装入president 表。如果您有多个需要装入单个表的文件,应仔细地选择文件名,否则mysqlimport 将不能使用正确的表名。对于如像member1.txt 与member2.txt 这样的文件名, mysqlimport 将会认为相应的表名为

member1和member 2。不过,可以使用如member.1.txt 和member.2.txt 或member.txt1和member.txt2 这样的文件名。在试用过这些记录追加的方法后,应该清除各个表并重新装载它们,以便它们的内容与下一节假定的内容相同。从外壳程序执行下列命令:

每个文件都含有一个删除可能曾经插入到表中的记录的DELETE 语句,后跟一组INSERT 语句以初始化表的内容。如果不希望分别键入这些命令,可试一下下列语句:

1.4.8 检索信息

现在各个表已经创建并装有数据了,因此让我们来看看可以对这些数据做点什么。SELECT 语句允许以一般的或特殊的方式检索和显示表中的信息。它可以显示表的整个内容:

或者只显示单个行中单个列的内容:

SELECT 语句有几个子句(部件),可以根据需要用来检索感兴趣的信息。每个子句都可简单、可复杂,从而SELECT 作为一个总的语句也繁简皆宜。但是,可以放心,本书中不会有花一个钟头来编写的长达数页的查询。(我在书中看到有很长的查询时,一般会立即跳过它们,因此我猜您也会这样。)SELECT 语句的一般形式为:SELECT 要选择的东西FROM 一个或多个表WHERE 数据必须满足的条件记住,SQL 为一个自由格式的语言,因此在您编写SELECT 查询时,语句的断行不必严格依照本书。

为了编写SELECT 语句,只需指定需要检索什么,然后再选择某些子句即可。刚才给出的子句“ FROM”、“WHERE”是最常用的,还有一些其他的子句,如GROUP BY、ORDER BY和LIMIT 等。FROM 子句一般都要给出,但是如果不从表中选择数据,也可不给出。例如,下列查询只显示某些可以直接计算而不必引用任何表的表达式的值,因此不需要用FROM 子句:

在确实使用一个FROM 子句指定了要从其中检索数据的表时, SELECT 语句的最“普通”的格式是检索所有内容。用“ *”来表示“所有列”。下面的查询将从student 表中检索所有行并显示:

各列按它们MySQL在表中存放的次序出现。该次序与发布DESCRIBE student 语句时显示的列次序相同。(例子末尾的“. . .”表示此查询返回的输出行比这里显示的还要多。)可明确地命名希望得到的一列或多列。如果只选择学生名,发布下列语句:

如果名字不止一列,可用逗号分隔它们。下列的语句与SELECT * FROM student 等价,只是明确地指出了每一列:

可按任意次序给出列:

如果有必要,同一列甚至也可以给出多次,虽然这样做一般是没有意义的。列名在MySQL中不区分大小写的。下面的查询是等同的:

数据库和表名有可能区分大小写的;这有取决服务器主机上使用的文件系统。在UNIX上运行的服务器对数据库名和表名是区分大小写的,因为UNIX 的文件名是区分大小写的。Windows 的文件名不区分大小写,因此运行在Windows 上的服务器对数据库名和表名不区分

大小写。MySQL允许您一次从多个表中选择列。我们将这个内容留到“从多个表中检索信息”小节去介绍。

1. 指定检索条件

为了限制SELECT 语句检索出来的记录集,可使用WHERE 子句,它给出选择行的条件。可通过查找满足各种条件的列值来选择行。

可查找数字值:

也可以查找串值。(注意,一般串的比较是不区分大小写的。)

可以查找日期值:

可搜索组合值:

WHERE 子句中的表达式可使用表1-1中的算术运算符、表1-2 的比较运算符和表1-3 的逻辑运算符。还可以使用圆括号将一个表达式分成几个部分。可使用常量、表列和函数来完成运算。在本教程的查询中,我们有时使用几个MySQL函数,但是MySQL的函数远不止这里

给出的这些。请参阅附录C,那里给出了所有MySQL函数的清单。

在用表达式表示一个需要逻辑运算的查询时,要注意别混淆逻辑与运算符与我们平常使用的“与”的含义。假如希望查找“出生在Vi rginia 的总统与出生在Maryland 的总统”。应该注意怎样表示“与”的关系,能写成如下的查询吗?

错了,因为这个查询的意思是“选择既出生在Vi rginia 又出生在M a r y l a n d的总统”,不可能有同时出生在两个地点的总统,因此这个查询无意义。在英语中,可以用“a n d”表示这种选择,但在SQL 中,应该用OR 来连接两个条件,如下所示:

这有时是可以觉察到的,不仅仅是在编写自己的查询时可以觉察到,而且在为他人编写查询时也可以知道。最好是在他人描述想要检索什么时仔细听,但不一定使用相同的逻辑运算符将他人的描述转录成SQL 语句。对刚才所举的例子,正确的英语等价描述为“选择出生在Vi rginia 或者出生在Maryland 的总统。”

2. NULL 值

NULL 值是特殊的;因为它代表“无值”。不可能以评估两个已知值的相同方式来将它与已知值进行评估。如果试图与通常的算术比较运算符一道使用NULL,其结果是未定义的:

为了进行NULL 值的搜索,必须采用特殊的语法。不能用= 或!= 来测试等于NULL 或不等于NULL,取而代之的是使用IS NULL 或IS NOT NULL 来测试。例如,因为我们将健在总统的死亡日期表示为NULL,那么可按如下语句查找健在的总统:

MySQL3.23 及以后的版本具有一个特殊的MySQL专有的比较运算符“ < = >”,即使是NULL 与NULL 的比较,它也是可行的。用这个比较运算符,可将前面的两个查询重写为:

3. 对查询结果进行排序

有时我们注意到,在一个表装入初始数据后,对其发布一条SELECT * FROM tbl_name查询,检索出的行与这些行 入的顺序是相同的。但不要认为这种情况是有规律的。如果在初始装入表后进行了行的删除和插入,就会发现服务器返回表的行次序被改变了。(删除记录在表中留下了未使用的“空位”,MySQL在以后插入新记录时将会试图对其填补。)缺省时,如果选择了行,服务器对返回行的次序不作任何保证。为了对行进行排序,可

使用ORDER BY 子句:

在ORDER BY 子句中,可在列名之后利用ASC 或DESC 关键字指定排序是按该列值的升序或降序进行的。例如,为了按倒序(降序)名排列总统名,可如下使用DESC:

如果在ORDER BY 子句中,对某个列名既不指定ASC 又不指定DESC,则缺省的次序为升序。在对可能包含NULL 值的列进行排序时,如果是升序排序, NULL 值出现在最前面,如果是按降序排序,NULL 值出现在最后。

查询结果可在多个列上进行排序,而每个列的升序或降序可以互相独立。下面的查询从president 表中检索行,并按出生的州降序、在每个州中再按姓氏的升序对检索结果进行排序:

4. 限制查询结果如果一个查询返回许多行,但您只想看其中的几行,则可以利用LIMIT 子句,特别是与ORDER BY 子句结合时更是如此。MySQL允许限制一个查询的输出为前n 行。下面的查询选择了5 位出生日期最早的总统:

如果利用ORDER BY birth DESC 按降序排序,将得到5 位最晚出生的总统。LIMIT 也可以从查询结果中取出中间部分。为了做到这一点,必须指定两个值。第一个值为结果中希望看到的第一个记录(第一个结果记录的编号为0 而不是1)。第二个值为希望看到的记录个数。下面的查询类似于前面那个查询,但只显示从第11行开始的5 个记录:

自MySQL3.23.2 以来,可按照一个公式来排序查询结果。例如,利用ORDER BYRAND( ) 与LIMIT 结合,从president 表中随机抽取一个记录:

5. 计算并命名输出的列值

前面的多数查询通过从表中检索值已经产生了输出结果。MySQL还允许作为一个公式的结果来计算输出列的值。表达式可以简单也可以复杂。下面的查询求一个简单表达式的值(常量)以及一个涉及几个算术运算符和两个函数调用的较复杂的表达式的值:

此查询把名和姓连接起来,中间间隔一个空格,将总统名形成一个单一字符串,而且将出生城市和州连接在一起,中间隔一个逗号,形成出生地。

在利用表达式来计算列值时,此表达式被用作列标题。如果表达式很长(如前面的一些查询样例中那样),那么可能会出现一个很宽的列。为了处理这种情况,此列可利用AS name结构来重新命名标题。这样的名称为列别名。用这种方法可使上面的输出更有意义,如下所示:

6. 使用日期

在MySQL中使用日期时要记住的是,在表示日期时首先给出年份。1999 年7 月27 日表示为“1999 - 07 - 27”,而不是像通常那样表示为“ 07 - 27 - 1999”或“27 - 07 - 1999”。MySQL提供了几种对日期进行处理的方法。可以对日期进行的一些运算如下:

■ 按日期排序。(这点我们已经看到几次了。)

■ 查找特定的日期或日期范围。

■ 提取日期值的组成部分,如年、月或日。

■ 计算日期的差。

■ 日期增加或减去一个间隔得出另一日期。

下面给出一些日期运算的例子。

为了查找特定的日期,可使用精确的日期值或与其他日期值进行比较,将一个DATE 列与有关的日期值进行比较:

为了测试或检索日期的成分,可使用诸如YEAR( )、MONTH( ) 或DAYOFMONTH( ) 这样的函数。例如,可通过查找月份值为3 的日期,找出与笔者出生在相同月份(三月)的总统。

为了更详细,详细到天,可组合测试MONTH( ) 和DAYOFMONTH( ) 以找出在笔者的生日出生的总统:

这是一种可用来生成类似报纸上娱乐部分所刊登的那种“这些人今天过生日”清单的查询。但是,不必按前面的查询那样插入一个特殊的日期。为了查找每年的今天出生的总统,只要将他们的生日与C U R R E N T _ DATE 进行比较即可:

可从一个日期减去另一个日期。这样可以知道日期间的间隔,这对于确定年龄是非常有用的。例如,为了确定哪位总统活得最长,可将其逝世日期减去出生日期。为此,可利用函数TO _ DAYS( ) 将出生日期和逝世日期转换为天数,求出差,然后除以365 得出大概的年龄:

此查询中所用的FLOOR( ) 函数截掉了年龄的小数部分,得到一个整数。得出日期之差,还可以确定相对于某个特定日期有多长时间。这样可以告诉历史同盟的会员,他们还有多久就应该更新自己的会员资格了。计算他们的截止日期和当前日期之差,如果小于某个阈值,则不久就需要更新了。下面的查询是查找需要在60 天内更新的会员:

自MySQL3.22 以来,可使用DATE_ADD( ) 或DATE_SUB( ) 从一个日期计算另一个日期。这些函数取一个日期及时间间隔并产生一个新日期。例如:

本节中前面给出的一个查询选择70 年代逝世的总统,它对选择范围的端点使用直接的日期值。该查询可以利用一个字符串日期和一个由开始日期和时间间隔计算出的结束日期来重写:

会员更新查询可根据DATE_ADD( ) 写出如下:

本章前面给出了一个查询如下,确定不久要来检查但还没来诊所的牙科病人:

现在回过头来看,读者会更清楚这个查询的含义了。

7. 模式匹配

MySQL允许查找与某个模式相配的值。这样,可以选择记录而不用提供精确的值。为了进行模式匹配运算,可使用特殊的运算符( LIKE 和NOT LIKE),并且指定一个包含通配符的串。字符“_”匹配任意单个字符,而“%”匹配任意字符序列(包括空序列)。使用L I K E或NOT LIKE 的模式匹配都是不区分大小写的。下列模式匹配以“W”或“w”开始的姓:

此查询给出了一个常见的错误,它对一个算术比较运算符使用了模式。这种比较成功的惟一可能是相应的 实包含串“ W %”或“w %”。下列模式匹配任意位置包含“W”或“w”的姓:

MySQL还提供基于扩展正规表达式的模式匹配。正规表达式在附录C 的REGEXP 运算符的介绍中描述。

8. 生成汇总

MySQL所能做的最有用的事情是浓缩大量的原始数据行并对其进行汇总。当学会了利用MySQL来生成汇总时,它就变成了用户强有力的好帮手了,因为手工进行汇总是一项冗长的、费时的、易出错的工作。汇总的一种简单的形式是确定在一组值中哪些值是唯一值。利用DISTINCT 关键字来删除结果中的重复行。例如,总统出生的各个州可按如下找出:

其他的汇总形式涉及计数,可利用COUNT( ) 函数。如果使用COUNT (*),它将给出查询所选择的行数。如果一个查询无WHERE 子句,COUNT(*) 将给出表中的行数。下列查询给出共有多少人当过美国总统:

如果查询有WHERE 子句,COUNT(*) 将给出此子句选择多少行。下面的查询给出目前为止对班级进行了多少次测试:

COUNT(*) 对选中的行进行计数。而COUNT(col_name) 只对非NULL 值进行计数。下面的查询说明了这些差异:

这表示,总共有41位总统,他们中只有一个具有名字后缀,并且大多数总统都已去世。自MySQL3.23.2 以来,可以将COUNT( ) 与DISTINCT 组合对选择结果集中不同的值进行计数。例如,为了对总统出生的不同州进行计数,可执行下列查询:

可以根据汇总列中单独的值对计数值进行分解。例如,您可能根据下列的查询结果知道班级中所有学生的人数:

但是,有多少是男孩?有多少是女孩?分别得出男孩、女孩的一种方法是分别对每种性别进行计数:

虽然这个方法可行,但是它很繁锁而且并不真正适合于可能有许多不同的值的列。考虑一下怎样以这种方式确定每个州出生的总统人数。您不得不找出有哪些州,从而不能省略(SELECT DISTINCT state FROM president),然后对每个州执行一个SELECT COUNT(*) 查询。很显然,有些事是可以简化的。所幸MySQL可以利用单个查询对一个列中不同的值进行计数。因此,针对学生表可以按如下得出男孩和女孩的人数:

如果以这种方法对值计数, GROUP BY 子句是必须的;它告诉MySQL在对值计数之前怎样进行聚集。如果将其省去,则要出错。COUNT(*) 与GROUP BY 一起用来对值进行计数比分别对每个不同的列值进行计数有更多的优点,这些优点是:

■ 不必事先知道要汇总的列中有些什么值。

■ 不用编写多个查询,只需编写单个查询即可。

■ 用单一查询就可以得出所有结果,因此可以对结果进行排序。

前两个优点对于更方便地表示查询很重要。第三个优点也较为重要,因为它提供了显示

结果的灵活性。在使用GROUP BY 子句时,其结果是在要分组的列上进行排序的,但是可以

使用ORDER BY 来按不同的次序进行排序。例如,如果想得到各州产生的总统人数,并按产

生人数最多的州优先排出,可以如下使用ORDER BY 子句:

如果希望进行排序的列是从计算得出的,则可以给该列一个别名,并在ORDER BY 子句中引用这个别名。前面的查询说明了这一点; COUNT(*) 列的别名为count。引用这样的列的另一种方法是引用它在输出结果中的位置。前面的查询可编写如下:

我不认为按位置引用列易读。如果增加、删除或重新排序输出列,必须注意检查ORDER BY子句,并且如果列号改变后还得记住它。别名就不存在这种问题。如果想与计算出来的列一道使用GROUP BY,正如ORDER BY 一样,应该利用别名或列位置来引用它。下面的查询确定在一年的每个月中出生的总统人数:

如果不想用LIMIT 子句来限制查询输出,而是利用查找特定的COUNT( ) 值来达到这个目的,可使用HAVING 子句。下面的查询给出了产生两个以上总统的州:

从更为普遍的意义上说,这是一种在要查找的列中重复值时执行的查询类型。HAVING 类似于WHERE,但它是在查询结果已经选出后才应用的,用来缩减服务器实际送到客户机的结果。除了COUNT( ) 外还有许多汇总函数。MIN( )、MAX( )、SUM( ) 和AVG( ) 函数在确定列的最大、最小、总数和平均值时都非常有用,甚至可以同时使用它们。下面的查询得出给定的测试和测验的各种数字特性。它还给出有多少学分参与了每个值的计算(有的学生可能缺旷或未计入)。

当然,如果您知道这些信息是来自测验的还是测试的,则它们就会更有意义。但是,为了产生那样的信息,还需要参考event 表;我们将在下一节“从多个表中检索信息”讨论这个查询。汇总信息是很有意思的,因为它们是那么有用,但不太好控制,容易走样。请看下列查询:

此查询选择已经去世的总统,按出生地对他们进行分组,并计算出他们逝世时的年龄,计算出平均年龄(每个州的),然后按平均年龄进行排序。换句话说,此查询按所出生地确定已故总统的平均寿命。但这说明了什么呢?它仅仅说明您可写该查询,当然并不说明此查询是否值得写。并不是用一个数据库可以做的所有事情都同样有意义;但是,人们有时在发现可以利用自己的数据库进行查询时感到很开心。这可能说明关于转播运动会的不断增加的深奥的(空洞的)统计数据在过去几年里正在不断增多的原因。运动统计者可以使用他们的数据库来计算出某个队的历史纪录,而这些数字你可能感兴趣,也可能毫无兴致。

9. 从多个表中检索信息

到目前为止,我们所编写的查询都是从单个表中得到数据的。现在,我们将进行一件更为有趣的工作。以前笔者曾经提到过,关系DBMS 的强大功能在于它能够将一样东西与另一样东西相关联,因为这样使得能够结合多个表中的信息来解答单个表不能解答的问题。本节介绍怎样编写这种查询。在从多个表中选择信息时,需要执行一种称为连接( j o i n)的操作。这是因为需要将一个表中的信息与其他表中的信息相连接来得出查询结果。即通过协调各表中的值来完成这项工作。

我们来研究一个例子。在前面的“学分保存方案”小节中,给出了一个检索特定日期的测验或测试学分的查询,但没有解释。现在可以进行解释了。这个查询实际涉及到三种连接方法,因此我们分两步进行研究。第一步,我们构造一个对特定日期的学分进行选择的查询,如下所示:

此查询找出具有给定日期的记录,然后利用该记录中的事件ID 查找具有相同事件ID 的学分。对于每个匹配的事件记录和学分记录组合,显示学生ID、学分、日期和事件类型。此查询在两个重要方面不同于我们曾经编写过的其他查询。它们是:

■ FROM 子句给出了不止一个表名,因为我们要检索的数据来自不止一个表:

FROM event,score

■ WHERE 子句说明event 和score 表是由每个表中的event_id 值的匹配连接起来的:

where event.event_id=score.event_id

请注意,我们是怎样利用tbl_name.col_name 语法引用列,以便MySQL知道引用的是哪些表的列。(event_id 出现在两个表中,如果不用表名来限定它的话将会出现混淆。)此查询中的其他列( date、score、type)可单独使用而不用表名限定符,因为它们在表中只出现一次,从而不会出现含混。但是,一般在连接中我们对每个列都进行限定以便清晰地表示出每个列是属于哪个表。在完全限定的形式下,查询如下:

从现在起,我们将使用完全限定的形式。第二步,我们利用student 表完成查询以便显示学生名。(第一步中查询的输出给出了student_id 字段,但是名字更有意义。)名字显示是利用score 表和student 表两者都具有student_id 列,使它们中的记录可被连接这个事实来完成的。最终的查询如下:

此查询与前一个查询的差别在于:

■ student 表被增加到了FROM 子句中,因为除了event 表和score 表外还用到了它。

■ student_id 列现在不明确了(因为现在有两个引用到的表都含有此列),因此必须限定为score.student_id 或student.student_id 以表明使用的是哪个表。

■ WHERE 子句有一个附加项,它说明根据学生ID 将score 表记录与student 表记录进行匹配。

■ 此查询是显示学生名而不是学生ID。(当然,如果愿意的话,可以两者都显示。)利用此查询,可以加入任意日期,得到该日期的学分,用学生名和学分类型完善查询结果。不一定要了解关于学生ID 或事件ID 的情况。MySQL小心地得出相关的ID 值并利用它们自动地使各表的行相配。

学分保存方案涉及的另一项工作是汇总学生的缺勤情况。缺勤情况是按学生ID 和日期在absence 表中记录的。为得到学生名(而不仅仅是ID),我们需要根据student_id 的值将absence 表连接到student 表。下面的查询给出了学生的ID 号和名字以及缺勤计数:

注意:虽然我们在GROUP BY 子句中应用了一个限定符,但对于这个查询来说不是必须的。因为GROUP BY 子句只引用选择表中(此查询的前两行)的列。在该处只有一个名为student_id 的列,因此MySQL知道应该用哪个列。这个规则对ORDER BY 子句也成立。如果我们希望只了解哪些学生缺过勤,则此查询所产生的输出也是有用的。但是,如果我们将此清单交给学校办公室,他们可能会说,“其他的学生呢?我们需要每个学生的情况。”这是一个稍微有点不同的问题。它表示需要知道学生的缺勤数,即使没有缺勤的学生也需要知道。因为问题的不同,查询也应该不同。

为了解决上述问题,使用LEFT JOIN 而不涉及WHERE 子句中的学生ID。LEFT JOIN要求MySQL对从连接首先给出的表中选择每行生成一个输出行(即LEFT JOIN 关键字左边给出的表)。由于首先给出student 表,我们得到了每个学生的输出结果,即使是那些在absence 表中未给出的学生也都包括在输出中。此查询如下:

前面,在“生成汇总”一节中,我们执行了一个查询,它生成score 表中数据的数值特征。该查询的输出列出了事件ID,但不包括学分日期或类型,因为我们不知道怎样将score 表连接到event 表以得到学分的日期和类型。现在可以做到了。下面的查询类似于早先的那个,但是它给出了学分的日期和类型而不只是简单的数字事件ID:

可利用诸如COUNT( ) 和AVG( ) 这样的函数生成多个列上的汇总,即使这些列来自不同的表也是如此。下面的查询确定学分数,以及事件日期与学生性别的每种组合的平均学分。

我们可以使用一个类似的查询来完成学分保存方案的一个任务,即在学期末计算每个学生的总学分。相应的查询如下:

不一定要求连接必须用两个不同的表来完成。这似乎有点奇怪,但是确实可以将一个表连接到其自身。例如,可通过针对每个总统的出生地查看其他各个总统的出生地,确定几个总统是否出生在相同城市。此查询如下:

此查询有两个技巧性的东西:

■ 我们需要使用同一表的两个实例,因此建立了表的别名( p 1、p 2),并利用它们无歧义地引用表列。

■ 每个总统的记录与自身相匹配,但是我们不希望在输出中看到同一总统出再现两次。WHERE 子句的第二行保证比较的记录为不同总统的记录,使记录不与自身匹配。可以编写一个查找出生在同一天的总统的类似查询。出生日期不能直接比较,因为那样会错过出生在不同年份的总统。我们用MONTH( ) 和DAYOFMONTH( ) 来比较出生日期的月和日,相应的查询如下:

利用DAYOFYEAR( ) 而不是MONTH( ) 和DAYOFMONTH( ) 将得出一个更为简单的查询,但是在比较闰年日期与非闰年日期时将会得出不正确的结果。迄今所执行的连接结合了来自那些在某种意义上具有逻辑关系的表中的信息,但是只有您知道该关系无意义。MySQL并不知道(或不关心)所连接的表相互之间是否相关。例如,可将event 表连接到president 表以找出在某个总统生日那天是否进行了测验或测试,此查询如下:

上一篇:双节祝福短信下一篇:党课授课内容