Access 历史版本特性变化列表(长期维护及时更新)

Access从92年到现在已经发布了12个版本。我们可以沿着各个版本特性的变化,感受一下Access的发展脉络。内容来源于网络,如有纰漏,欢迎在评论中指出。

时间

版本

版本号

变化

1992.11

Access 1.0

1.0

  • 第一个运行在Windows 3.0上的关系型数据库
  • 开始挑战当时DOS操作系统上的数据库管理系统霸主Borland公司的dBaseParadox

1993.05

Access 1.1

1.1

  • Access添加了Access Basic编程语言

1994.04

Access 2.0

2.0

  • 开始支持Windows 3.1,
  • 最小内存需求4M

1995.08

Access 95

7.0

  • Access被添加到微软办公软件Office 95套件中
  • 支持ActiveX控件
  • VBA取代了Access Basic
  • 需要运行在Windows 95

1997.01

Access 97

8.0

  • 加入了超链接特性

1999.06

Access 2000

9.0

  • 使用新的Jet数据库引擎
  • 开始拥有记录锁定功能
  • 引入ADOUnicode字符集编码,ADP
  • VBAVB6共享相同编程界面IDE

2001.05

Access 2002

10.0

  • 开始支持XML

2003.11

Access 2003

11.0

  • 使用Windows XP主题
  • 引入数字签名
  • 显式信任运行VBA代码

2007.01

Access 2007

12.0

  • 引入ACCDB数据库格式
  • 更安全的加密数据
  • 功能区用户界面
  • 选项卡式对象
  • 报表视图
  • 数据表中汇总行
  • 简化了的筛选功能
  • 分割式窗体
  • 导出为PDF
  • 日期选择器
  • 按钮图表支持
  • 支持搜索功能的导航窗格
  • 附件和多数值字段数据类型
  • 窗体对象锚定
  • Web浏览器控件
  • 图像控件
  • 目录级信任

2010.07

Access 2010

14.0

  • 引入Access 64位版本
  • 使用SharePoint ListAccess Web 应用程序(AWA)
  • 数据宏

2013.01

Access 2013

15.0

  • 可以创建使用SQL ServerAccess Web 应用程序(AWA)
  • 桌面Access数据库不再支持
    • ADP
    • 数据透视表
    • 数据透视图
    • 智能标记
    • 链接到dBase
    • Visual Source Code 集成
    • 升迁向导
    • 安装包向导
  • 文本和备注数据类型改名为短文本和长文本
  • 需要运行在Windows 7及更高版本操作系统上

2015.09

Access 2016

16.0

  • 引入Office助手告诉我”
  • 新的主题
  • 导出链接数据源信息到Excel
  • 更现代化的模板
  • 更大的“显示表”对话框
  • AWA可以用于SharePoint户内客户
  • 需要运行在Windows 7 SP1 及更高版本上

Access 与 Excel 之对比(翻译)

译者的话:

企业数据库全局战略中的Access(翻译)》发布之后,获得了大量的阅读点击。今天再翻译一篇Luke Chung的文章,相信你读完以后,不再对该类问题感到困惑。

翻译用了 1 周的业余时间,有误之处,欢迎批评指正。原文可参见这个链接


在Excel与Access之间抉择

Microsoft Office的高级用户经常问我们,为什么要使用Access?什么时候应该使用Access,而不是Excel?特别是当他们Excel用起来非常顺手的时候。以下是我们的观点。

给信息工作者赋能

我们认为,这不是二选一的问题。它们各自都有各自的优势,并且天然的相辅相成。了解它们的差异,并在不同的情况下,选择适合的一个的人,可以为他们自己以及所属的企业带来竞争优势。

Microsoft Office产品为个人(微软称之为信息工作者)赋能,使其可以独立完成任务。这样,你就可以充分利用你对工作内容的理解,为要做的事情弄一个解决方案。这要比你将问题提交到”IT专业人士”那里,去寻求帮助而高效得多。因为你需要让他了解你的技术需求,而他很可能对你的业务背景一无所知。当他还没有搞清楚状况,就去创建技术解决方案,结果可想而知。

Microsoft Excel的优点

Excel的学习曲线非常短,所以使用Excel很容易,而且生产效率很高。需要IT人员创建Excel的情况很少,信息工作者们可以自己做。

Excel可以轻松的存储数据,执行数值计算,格式化单元格,调整布局,生成结果或报告分享给他人。还有一些高级功能,例如,分类汇总,数据透视表,数据透视图,分析工具包,以及许多模板。这些高级功能使得Excel能够轻松完成各种任务。它甚至可以与SQL Server的分析服务(商业智能)集成,获取数据后,调整一下布局,字体,颜色等,得到你想要的报表。

Microsoft Excel的缺点

不幸的是,Excel的灵活性是有代价的。虽然创建公式,引用单元格,复制粘贴数据,以及将多个工作表和工作簿链接在一起都很容易,但随着工作变得越来越复杂,Excel数据变得越来越难管理。诚然,Excel是创建一次性分析的理想选择,但是随着时间的推移,数据会不断增长,业务会不断演化,Excel会变得问题多多。当新的行和列被添加进来后,汇总区域和公式可能需要修改或新增,数据和公式如果更新不一致,会导致错误的结果和决定。

Excel面临的挑战在于,随着时间推移,数据量不断增加,要准确的维护它们,是非常有难度的。

Microsoft Access的优点

Excel专家一般很难理解Access提供的那些Excel并不具备的功能。Access有以下几个特性:

  • 通过多个表让数据结构化和规范化
  • 可扩展性:可以自由的增加更多的数据记录
  • 数据和参照完整性
  • 查询和报表
  • 通过宏和VBA代码模块自动化

表结构和验证

使用Access,你可以很容易做到,将信息存储在一个地方,而在多个地方引用它。例如,你可以将客户信息(可能有客户姓名,地址,电话号码,电子邮件等)保存在客户表中。而这些信息可能会在其他的地方(可能是查询,窗体,报表等)被引用。如果客户的信息发生变化了,新的信息会在所有被引用的地方自动更新。设计表的时候,你会加入一些约束限制,例如设定字段为数值型,日期型,或者文本型等,从而获得比电子表格更高质量的数据。而设定字段类型仅仅只是一个开始。

Access中的记录可以自由的增减

Access与Excel最大的区别就是,在Access中,记录的增减是自由的。只要设计得当,新的数据记录可以随时不断的添加进来,而不需要填加任何新的字段(列)。所有的查询,窗体和报表会照常工作,而无需任何调整。当然,你可能会使用不同的筛选条件,但出来的结果一定是一致的。新的数据添加进来后,不需要重新测试或调整单元格公式。这样每年,每季度,每月,每周或每日,你都能生成准确的报告。

数据和参照完整性

有句话说“垃圾进,垃圾出”(garbage in – garbage out)。Access为规避这一点提供了许多工具,来保证数据质量。在Access表中,你可以很容易将查阅列表和验证规则应用于单个字段(列)和记录上。在窗体上做数据输入的时候,你还可以添加额外的规则来响应用户的选择和事件。Access还提供表间的参照完整性,以确保数据在多个表中有一致的定义。

查询和报表

你可以使用Access的查询和报表来切分数据,并以详细或者汇总的形式来呈现它,而不用去考虑数据是如何存储的和排序的。它提供了大量的功能和灵活性来分析和呈现结果。使用分组功能时,聚合信息可以随着数据的变动而自动增减。

通过宏与VBA模块进行自动化

在Access宏或者VBA模块中,你可以使用Docmd.TransferSpreadsheet命令将数据从Access表或查询中导出到Excel(使用acExport选项)。

使用acImport选项,TransferSpreadsheet命令还可以将Excel中的数据导入到Access表。

实际上,如果使用Office VBA自动化,你可以在Access中打开一个Excel文件,并将数据写入到指定的单元格,自动的更新Excel中的数据。

Microsoft Access的缺点

Access最大的缺点就是,做为一个数据库,它需要你掌握更多的知识和技能才能使用。搞清楚如何定义规范化的表,将他们连接在一起,并结构化好数据,使其易于编辑,查询和生成报表,这些内容对于初学者来说是很有挑战性的。但是这是设计所有关系型数据库,都需要面对的问题,一旦掌握了,你就可以将其应用于其他数据库。

构建数据库,创建查询和设计报表布局的学习曲线可能看起来相当艰巨。这肯定要比在Excel单元格中敲入数据要复杂得多。另外,很可能让你感到十分沮丧的是,在Access中,你无法轻松的复制和粘贴单元格区域,你也无法在Access的报表结构中做任何特别的调整。(例如,想通过特殊字体或备注来突出显示某个值或者某一行)虽然你可以利用Access的VBA代码模块来做定制化,但是相对于Excel所见即所得(WYSIWYG)的设计来说,你要花费更多的精力。此外,一些数据分析功能,比如power pivot,在Access中是没有的。

结论

Excel可以非常灵活的生成个性化的报表,并且可以在任何地方自由的设定格式或添加批注。Access回报给你的则是,一旦设计完毕投入使用,它就能提供长期的数据准确性和一致性,毕其功于一役。对于一次性的分析来讲,使用Access当然就是用牛刀杀鸡,但如果数据需要长期维护,报表需要定时生成的话,使用Excel往往会遇到困难。大多数企业都有许多“相似”的Excel表,相互之间只存在一点点细微的差异,但是随着时间的推移,很快它们就变得不一致。精心设计的Access数据库就不存在这种难以管理的挑战。也就是说,Access和Excel都有其优点和缺点。

最佳实践就是将Excel和Access两者的优点结合起来,形成一个混合解决方案,将Access中的数据导出或复制到Excel。Access数据库的数据参照完整性,严格定义的数据以及有质量保证的数据输出,再结合适宜临时分析的Excel,可以让你充分利用两者的优势。而使用自动化流程,可以让数据在Excel与Access之间的平滑的交互和共享。

根据我们的经验,这些解决方案会随着时间的推移,以一种非常不可预知的方式进化升迁。掌握这种混合解决方案,能让你快速灵活的响应业务变化,使你和企业有效的完成任务。

祝你好运!

Access 开发框架(翻译+改编)系列之八——从属对象

框架的最终目的,是提供一个明确定义的地方,将对象的属性和行为可以放置在这里,用于将来的项目开发。控件是一个主要的例子,因为它们没有内建类(built-in class),而我们想扩展它们的功能。于是,我们为每个控件类型创建了类,这样我们就能扩展这个控件的功能。

为了这个目的,在本系列中,我们将为已创建的组合框控件类添加一些新的功能。这个新功能就是从属对象重新查询(dependent object re-query)

从属对象重新查询的意思就是,我们某个类对象创建一个方法,当该类对象的值有变化时,任何从属于该类对象的对象的值,都会执行重新查询,获得更新。在本系列中,这个类对象就是组合框控件类。当用户在组合框控件中选择了一个新的值,任何从属于这个组合框控件的对象会自动的重新查询,基于组合框控件的值,更新自己的筛选数据。

这样的行为通常是非常有用的,同时也能向我们展示,如果我们想让框架做更多的事情的话,我们应该如何在其中添加新的事物,从而扩展我们的框架。

从属对象

从属对象在Access应用程序中是很普遍的。举个例子,有一个窗体,上面有2个组合框,名字分别为cboCompany和cboEmployees。当用户选择cboCompany的值后,cboEmployees需要重新查询自己的可选数据,只显示公司为组合框控件cboCompany中的值的员工数据。

从属对象的功能在通常情况下是怎样实现的呢?一般是为从属对象创建一个查询,这个查询为该从属对象提供数据,在该查询中,有一个字段,该字段引用了被从属的对象的值。换句话说,cboEmployees的“row source”属性(译者注:我用的英文版本Access,该属性对应的中文名称可能是“行来源”)中的查询会设置类似于“Like form!frmMyForm!cboCompany”这样的筛选条件。控件cboEmployees是从属于(依赖于)控件cboCompany的。仅仅这样做好设置以后,当你修改cboCompany的值以后,你会发现cboEmployee的值并未立即发生更新,你必须手动刷新(或通过代码)窗体,从属的组合框控件才会更新。

为了在我们的框架中实现这种功能。我们可以简单的直接在控件类中添加一个从属对象集,然后为每一个控件类添加方法,以便可被添加到这个集合中,当控件类对象销毁之前,将其从集合中移除。当然我们也会添加一个重新查询的方法,遍历集合中的所有对象,调用每个对象的重新查询方法。注意,这隐含着一个意思,每个可从属于其他控件的控件必须有一个公用的重新查询方法。

本章相关代码示例文件8.1 从属对象

从属对象代码

从属对象的代码大概是这个样子的:

在每个控件类的开始部分(为了方便阅读,剥离了所有的错误处理代码)

在每个控件类初始化事件中,将集合对象实例化。

在每个控件类的Term()方法中写入清除代码

最后,公用函数或方法来处理从属对象的相关事情:

用这种方法,当然,不会有任何问题。但是,如果我们从类的角度,来思考这个问题的话,我们完全有更好的方案。我们可以创建一个从属对象类,将相关的代码都放置其中,然后我们只需要在每个控件类中添加一个从属类对象。

使用一个专用的类来处理这个问题的最大的好处,就是我们可以把所有类似的代码都放在一个地方——类中,然后在我们需要的地方,定义一个clsDepObj对象,然后调用类的方法。我们不再需要在每个控件中都重复去维护那一堆相似的代码。

每个控件类代码

创建了从属对象类clsDepObj,在控件类中,我们不再需要上述代码了,我们只需要这些:

在每个控件类的开始部分(为了方便阅读,剥离了所有的错误处理代码)

在每个控件类初始化事件中,将从属类对象实例化。

在每个控件类的Term()方法中写入清除代码

然后创建一个属性来获取从属类对象的指针(句柄/引用)

你不得不承认,相比将整个从属类的代码都添加在到每一个控件类中来说,在每个控件类中只用添加这些行,要来的更加清晰和容易。更不必说,如果我们想添加一些其他的从属对象功能到框架中来的话,我们只需要在一个地方添加即可,而不必在每个控件类中都做一遍。

有一件事情我们必须要记住,在每个包含从属对象的控件类中,要添加一个重新查询的方法。显而易见,如果这个控件类有一个数据源,那么我们需要重新查询这个控件,也需要调用从属对象类的重新查询方法。

最后,当组合框的AfterUpdate(更新后)事件被触发后,我们想重新查询新类的从属对象集合中所有的对象。我们通过调用mclsDepObj的重新查询方法就可以了。WithEvents!你将会爱上它。

现在,我们有了这个新的类和它的功能,我们怎样告诉框架来使用它呢?答案就在窗体类的初始化的地方——窗体的Open事件。

窗体的内建类

我修改了frmPeople11窗体,添加了2个组合框控件在窗体的头部,cboCompany和cboEmployee,分别包含公司和和这些公司的员工。窗体的代码大概是这样子的:

我们的自定义窗体类dclsFrm

以及窗体的打开事件

我知道这看起来非常复杂,但是我们可以一步一步来看,我会告诉你每一步是在干什么。Set语句和Init语句跟以前是一样的。我们将指向窗体内建类的指针(Me)和指向窗体本身的指针(Me)传递给fdclsFrm对象。非常凑巧的是,对窗体来讲,Me既代表了窗体内建类,也代表了物理窗体,所以出现2个Me,看起来有点奇怪。

接下来,我们用一个With语句来加快我们获取dclsFrm对象内部内容的速度

dclsFrm有一个Children属性,可以返回类的集合指针。有了这个,我们现在可以引用集合的属性和方法。我们使用.Item()方法从集合中返回一些东西。

还记得吗?在dclsFrm类中,我们有一个控件扫描方法,可以发现窗体上的所有控件,然后为每个控件创建一个对象,然后将该对象的指针保存在集合colChildren中。还记得我们使用什么作为主键吗?是的,我们使用了控件的名字。这样一来,.Item(“cboCompany”)告诉类对象在集合colChildren中返回名叫“cboCompany”的对象,换句话说,就是控件cboCompany的控件类对象。

这样的话,.Item(“CboCompany”)就是指向组合框类对象的指针,与下述语句是一样的:

既然我们有了指向组合框控件类对象的指针,我们就可以调用这个类对象的任何方法或属性了,这就有了下面的语句:

代码的意思就是,对组合框控件cboCompany的控件类对象来讲,调用它的从属类方法clsDepObj,返回指向它的从属类对象的指针,然后调用从属类对象的Add方法,准备添加一个从属类对象。

记住,句点符号指示那个类的属性或方法,这样一层一层的引用,有点像魔术师的盒子,大盒子放着中盒子,中盒子中放着小盒子,一直到我们最终要引用的对象。

fdclsFrm.Children.Item(“class name”).clsDepObj.Add

顺便说一下,我们可以在这行上面设置一个断点,然后单步调试这段代码,观察各种类的方法的调用情况,返回的指针指向下一个对象,然后调用下一个对象的方法,返回下下一个对象等,一直到最后,我们钻入到最后的Add方法。

这非常有趣!

好了,让我们回到主题。

我们已经告诉dclsFrm要添加一些东西到clsDepObj。“一些东西”就是组合框控件cboEmployee的类对象。

类似的,我让窗体本身也从属与组合框控件cboCompany,所以我们也需要告诉cboCompany,dclsFrm也是一个从属对象。

最后,我们还需要重新查询cboCompany,以便它能重新查询它的从属对象。

引用窗体的Children集合对象,找到为cboCompany创建的对象,适用其clsDepObj的方法获取从属对象的引用,使用从属对象的Add方法,添加一个从属对象到从属对象集中。被添加的对象是cboEmployee的类对象和窗体本身,fdclsFrm。一旦我们将这两个项目添加到从属对象集中,重新查询整个结构。

我非常清楚,当你第一看到这些东西的时候,你肯定是眼花缭乱的。但是,请相信我,一旦你使用了类,方法,属性和集合一段时间后,这会变成你的第二天性。

总结

通过添加一个新的,只有一个集合变量,和几个公用方法的小的类,我们创建了一个操控从属对象的方法。一旦类创建好,每个需要从属对象功能的控件类,只需要添加几行代码就可以了。很有可能,最大的难点,是在窗体打开事件中,需要找到正确的控件,引用到它的从属对象,然后添加该控件的从属对象。这两个从属对象分别是cboEmployee和窗体本身。

最后的结果就是,当窗体被打开以后,没有任何记录显示出来,因为公司还没有选择,而窗体的绑定数据源中,公司作为了筛选条件。一旦我们选择了一个公司,公司组合框控件就有了值,这个值就可以用来筛选窗体和组合框控件cboEmployee。因为cboCompany会调用它的从属对象clsDepObj的重新查询方法Requery,窗体的类会重新查询窗体本身,cboEmployee的控件类会重新查询cboEmployee。顺便说一下,如果cboEmployee也被编码了,拥有自己的从属对象,cboEmployee的类对象也会重新查询它所有的从属对象,整个过程,就想波纹一样,自动的一环套一环的执行下去。

类是非常强大的工具,允许我们将功能封装在一个地方,将所有的实现必要的行为相关的变量和代码封装在一个位置,如果有必要的话,我们只需要到这个地方修改或添加新的功能。你可以将这个独立的类放到你自己的框架中,只需要相对少的功夫,就能为你自己的组合框和其他控件添加从属对象功能。从属对象处理是非常小而琐碎的功能,但是想象一下,如果类拥有十几个属性和方法会有会怎样?封装性和可移植行成为了学习使用类的首要原因。

译者注:本章介绍的从属对象非常不好理解,要搞清楚三点,一是,谁是从属对象(cboEmployee,fdclsFrm),谁是被从属对象(cboComanpy),被从属对象的变化会导致从属对象的变化。第二点是要知道如何设置窗体的绑定数据,以及组合框控件的绑定数据源,当然Access比较基础的知识。最后一点是,要了解,如果没有本章介绍的从属对象,那些在绑定的数据源中引用了被从属控件值的窗体,在被从属控件值更新后,会自动获得更新吗?答案当然是否定的。

最后,我做了这个示例文件8.1 从属对象,在该示例文件中,有3个窗体:frmPeople10,frmPeople11,frmPeople12,分别演示了未应用任何从属对象类的情况,为cboCompany添加了从属对象,为cboCompany和cboEmployee都添加了从属对象的情况。读者可以分别测试一下,看看效果差别在哪里。

后记:翻译到此章的时候,一直萦绕在我脑中的一个疑问有了一个答案。还是那个比较恼人的对象卸载问题。按照Colby的类模板的要求,对象在卸载自己的时候,首先卸载自己colChildren中的子对象,卸载子对象前,先执行子对象的Term()方法。问题来了:很显然,本章介绍的clsDepObj中的集合mcolDepObj中的对象,肯定都不是由其父对象dclsCtlComboBox所实例化,当卸载clsDepObj的时候,也需要执行它的集合中的子对象的Term()方法吗?答案当然是否定的。那么什么时候执行子对象的Term()方法?什么时候不用执行呢?

大家可以注意到,我在类模板的最后,添加了下面一个私有方法。什么时候执行Term(),由子对象的父对象是否是当前对象来决定。因为每个对象的父对象只有一个,就是实例化自己的对象。

相应的,重写后的每个类中,都有类似的代码。这样就解决了,什么时候该释放类,什么时候只是清除其指针的问题。

Colby自始至终都未曾论述过这个问题,相反,他创建了一个叫做实例堆的类clsInstanceStack(后续系列中会谈到),这个类用通俗的话来讲,就是对象的生死簿。主要用来做故障查询和除错用的。个人觉得,如果不把问题的根源找到,而只是在出现问题的时候,再来调试查错,还是于事无补的。

对象由谁实例化的,谁就是这个对象的父对象,这个对象的销毁也必须由其父对象来完成,其他的类对象,如果在其子集中引用了该类对象,那么只能在其子集中清除引用指针就好了。总结成一句话,谁创造的,谁才能毁灭