尝试在 Microsoft Access 中制作高效的日历
Posted
技术标签:
【中文标题】尝试在 Microsoft Access 中制作高效的日历【英文标题】:Trying to Make an Efficient Calendar in Microsoft Access 【发布时间】:2012-11-16 00:07:11 【问题描述】:我正在开发一个设备管理系统,前端使用 MS Access .mdb 文件,后端使用 SQL Server 2008。如果需要,我可以将前端转换为 MS Access 2010 文件。
我创建了一个日历表单,用户可以在其中查看预订、退出或过期的设备。它看起来像这样:
我使用 42 个子表单制作了这个,不幸的是速度很慢。使用上面显示的数据,加载只需要大约 5 秒,但是一旦我使用真实数据,它就开始真正陷入无法接受的困境。我试图通过将子表单的源对象保持空白直到它们显示出来来提高效率,并且直到此时才加载记录源。这足以使上面看到的示例运行得相当快,但对于真实数据来说仍然不够。
所以我想做的,要么找到一种方法来提高效率,同时仍然使用子窗体,找到另一个代替子窗体工作的控件,或者用列表框切换子窗体,但不知何故仍然能够格式化行的颜色。我知道这对于列表框来说是不可能的,但我是一名程序员,如果不会浪费我太多时间,我愿意尝试子类化列表框来做到这一点。不幸的是,我从来没有做过任何 vba 子类化,所以我需要指出一些好的资源才能这样做。
每天子窗体的记录源设置代码如下:
f("sub" & X & Y).Form.RecordSource = "SELECT * " & _
"FROM QRY_Calendar " & _
"WHERE CDate(StartDate) <= #" & curDate & "# " & _
"AND ((EndDate IS NULL OR CDate(EndDate) >= #" & curDate & "#)" & _
IIf(CDate(curDate) <= Date, " OR ((Date_In IS NULL OR CDate(Date_In) >= #" & curDate & "#) AND Date_Out IS NOT NULL)", "") & ") " & _
"ORDER BY IIF(Date_Out Is Not Null And (Date_In Is Null Or CDate2(Date_In)>=#" & curDate & "#) And CDate2(EndDate)<#" & curDate & "#,0,iif(CDate2(Date_Out)<=#" & curDate & "# And (Date_In Is Null Or CDate2(Date_In)>=#" & curDate & "#),1,2)), ID"
QRY_Calendar 如下所示:
SELECT B.ID, Person, Initials, ProjectNum & '-' & ProjectYear & '-' & Format(TaskNum,'000') AS Project, Sign_Out_Code, Value AS Type, StartDate, EndDate, Date_Out, Date_In
FROM (((TBL_Booking AS B INNER JOIN TBL_Person AS P ON B.PersonID = P.ID) INNER JOIN LKUP_List AS T ON B.EquipTypeID = T.ID) LEFT JOIN TBL_Usage AS U ON B.ID = U.BookingID) LEFT JOIN TBL_Equipment AS E ON U.Equipment_ID = E.ID;
表 TBL_Booking 中的 StartDate 和 EndDate 是预订的开始和结束,表 TBL_Usage 中的 Date_Out 和 Date_In 是注销的开始和结束。 每个注销都通过外键 BookingID 链接到预订。如果 Date_In 为 NULL,则表示设备当前已注销。
LKUP_List 是我几年前开始工作之前的一个名称不佳的表,我从来没有费心去改变它。它包含设备类型的列表(除其他外)。预订是针对设备类型而非特定项目的,当用户注销其设备时,会在 TBL_Usage 中创建一条与特定设备相关联的记录。
如果有人对我应该采取哪个方向以及我可以在哪里寻求指导有任何想法,我将不胜感激。
【问题讨论】:
这只是一个报告 - 这里有任何用户交互吗?您可以通过此表格预订/取消预订设备吗? 不,预订和退出是在其他地方完成的。这只是为了让用户可以很好地了解正在使用的内容。除了更改月份之外,这里唯一的交互是单击某一天会显示该天的更详细视图。 所以这只是一份报告?那么为什么不只是建立一个报告呢?而不是一个表格?您是否会考虑其他技术,例如 SQL Server Reporting Services?这是通过网络交付的,因此没有人需要安装 MS Access。而且我相信您可以从 MS Access 调用 s-s-rS 报告(它只是一个 URL) 转贴:这只是数据库用户界面中的一项功能,无论如何,每个人都至少安装了 MS Access 的运行时。我想保留日历视图,并且报告将无法工作,因为这些项目不适合盒子,并且必须滚动浏览。真正困扰我的是数据的格式。我想保留颜色编码,但这是 MS Access 的限制之一。如果没有颜色编码,使用简单的列表框应该很容易做到这一点,我假设它比子表单更有效。 也许退后一步,想想用户想要做什么。什么界面对用户最有用?当他们运行此报告时,他们真正在寻找什么?他们是否查看特定 GPS 是否已注销?或者是否有免费的 GPS?他们甚至对历史信息感兴趣吗?他们是否只想单击一个按钮并在下一个可用日期找到下一个 GPS?每天都有滚动条的日历看起来不错,但可能无法解决他们真正想要的问题。这是一份报告这一事实是一个非常重要的区别。 【参考方案1】:首先,42 个子表单的加载速度非常快,事实上我已经这样做了很多年,42 个子表单的加载时间实际上是瞬时的。
因此,这表明这里的读者可以忽略这里的一些 cmets,这表明基于脚本或基于文本的解释系统(例如 html)与具有NEAR direct 直接写入视频显卡的能力。
请记住,如果您了解 Windows 桌面应用程序可以直接写入视频卡的简单和基本知识,那么很少有人会尝试比较并建议 HTML 中的渲染系统在速度方面有任何真正的希望,如果我们去的话在这里比较两种不同的架构。
所以这里真正的问题是 can 日历的运行速度有多快,42 个子表单是否会成为问题?
答案很简单,42 个子表单不成问题,而且速度很快!
我的以下 Access 日历几乎立即呈现。
即使在生产环境中,我的上述 Access 日历也已使用多年。即使日历每天都有更多无法显示在屏幕上的数据,加载时间也是即时的。其中很多正在运行,其中桌面(客户端)通过标准互联网连接到在网站上运行的 SQL Server 的托管版本访问 SQL Server 后端。即使在这种带宽更有限的情况下,日历的加载时间和响应也几乎是即时的。因此,无论我是否使用 accDB(基于文件)后端、使用 SQL 服务器作为后端,甚至更令人惊奇的是,该表单都可以很好地与我的许多通过常规 Internet 运行此 Access 日历的客户配合使用后端是在托管网站上运行的 SQL 服务器的连接。而且我什至有一个使用 SharePoint(列表)后端运行的版本,它再次运行没有问题和明显的延迟。
上面的设计有 42 个子表单,正如没有数据所指出的,子表单几乎是即时加载的。说明这一点很重要,因此我提供了一些真实世界和事实证据来贬低那些显然不掌握和理解基本计算机体系结构的人在这里制作的其他 cmet。因此,这些人会建议加载 42 个子表单在某种程度上会降低软件速度,而事实上我可以很容易地证明情况并非如此。因此,这里其他人的证人和证词可以被证明是没有价值的,因此这种观点是基于对计算机的基本操作如何在我们的行业中运作缺乏了解。 HTML 无法与这里的这种设置进行比较。
说到基于 Web 的 Access 允许 Web 发布,然后我发布以下视频,其中包含在 Web 浏览器中运行的 Access 内置日历。这个基于浏览器的日历仅使用 Access 构建,没有任何第三方工具。
http://www.youtube.com/watch?v=AU4mH0jPntI
上述视频的结果显示了此日历应用程序的流畅且即时响应的基于 Web 的版本。
现在我应该指出,在上述基于 Web 的示例中,我没有使用 42 个子表单,因为在 Web 浏览器中,每个表单都是一个单独的框架,并导致重新呈现从服务器发送的表单。这意味着对于基于 42 个子表单的设计的 Access web 是不可能的。您将在渲染方面遭受巨大的性能损失(即使没有数据,因为 XMAL 表单是按需加载以节省时间,但在这种情况下,这种设置会受到伤害)。
但是,正如视频所示,基于 Web(也适用于基于客户端)的解决方案是填写一个表格,在该表格中将文本框绑定到该表格。因此,具有一个记录显示正如上面的视频中所指出的那样,并且显示了这样的结果意味着接近即时的响应,并且即使在网络浏览器中也是如此。
我强调基于 WEB 的应用程序,因为该视频仅使用 Access 构建,没有其他工具。
现在回到性能问题和基于客户端的应用程序。当然,我们现在知道加载 42 个子表单不是问题。
问题当然是运行 42 个单独的 SQL 查询,使用各种表达式将数据提取到这些子表单中,这是瓶颈和性能下降的地方。因此,如果我们使用 42 个文本框,甚至 42 个列表框,这个性能问题不会改变。
所以问题在于尝试执行 42 个单独的 SQL 查询。请记住,每个 SQL 查询都需要时间来解析、检查语法,然后构建查询计划等。事实上,在数据甚至开始为那个给定查询流动之前,必须发生相当多的操作。事实上,我发现一个查询在带宽方面可能是大约 10,000 行数据流的成本。
基于以上信息,我设计的这 42 个子表单之所以可以立即加载和执行,是因为我只执行一个查询来返回整个月的数据。换句话说,我使用显示的开始日期和结束日期执行查询。然后,我运行 VBA 代码将生成的 reocrdset 中的数据处理为子表单 1 到 42。因此,VBA 代码将生成的记录集数据填充到 42 个子表单中。所以这是这里的关键概念和建议,以确保高性能计算并且不会降低速度。
总结和总结:
性能瓶颈不是使用 42 个子表单,而是拥有 42 个记录集和 42 个查询,并且可能需要计算 42 次额外的代码和表达式。消除 42 次查询和 42 次并不得不重新执行此类 SQL 语句,这个瓶颈将几乎消失。
我敢说,使用 42 个列表框,甚至只是 42 个文本框并继续执行 42 条这样的 SQL 语句,不会产生任何有价值的性能改进。
【讨论】:
感谢您抽出宝贵时间给我如此深思熟虑和详细的答复。我考虑了您所说的,并将执行时间缩短到约 3 秒。看来这一次都是由于最初的查询,如下一条评论中所示。查询返回 89 条记录。预订和使用表有超过 3000 条记录。我想知道是否有一种方法可以提高效率。如果不是这样也没关系,三秒的延迟也不算太糟糕,当我现在删除表中一些不必要的数据时,它可能会缩小。SELECT B.ID, P.Person, P.Initials, ProjectNum & '-' & ProjectYear & '-' & FORMAT(TaskNum,'000') AS Project, E.Sign_Out_Code, T.Value AS Type, B.StartDate, B.EndDate, U.Date_Out, U.Date_In
FROM (((TBL_Booking AS B INNER JOIN TBL_Person AS P ON B.PersonID = P.ID) INNER JOIN LKUP_List AS T ON B.EquipTypeID = T.ID) LEFT JOIN TBL_Usage AS U ON B.ID = U.BookingID) LEFT JOIN TBL_Equipment AS E ON U.Equipment_ID = E.ID
WHERE StartDate <= #11/30/2012# AND ((EndDate IS NULL OR EndDate >= #11/01/2012#) OR ((Date_In IS NULL OR Date_In >= #11/01/2012#) AND Date_Out IS NOT NULL));
【参考方案2】:
不久前问了一个关于日历的问题:Creating a 'calendar matrix' in Access
也就是说,您可能永远无法通过绑定到非平凡查询的 43 个子表单来获得良好的性能。
可能的小改进
您并不是说您的数据是否在后端服务器上,在这种情况下,每个子表单都必须通过网络获取数据。 如果是这种情况,您最好对服务器进行一次查询以提取所有数据并将其缓存在前端。然后,您只需对本地表进行简单的过滤,这应该会更快,尽管 42 个子表单可能会成为性能的一大瓶颈。
一个简单的INSERT INTO
查询可以帮助您入门,前提是您根据正常查询返回的数据创建了一个名为myCacheTable
的本地表。
轻量级控件
您可能应该尝试的第一件事是使用可敬的listbox
。
它相当轻量级,并且有很多方法可以配置它们。
如果你将它与我上面提到的从服务器缓存数据结合起来,你可以获得更好的性能。
支持网络的控件
正如HelloW 所提到的,最好使用设置为TextFormat = RichText
的文本框并为它们提供简单的HTML(它不支持太多)来格式化内部数据:
完整的网页
可能设置起来有点复杂,但在 UI 方面很难被击败,可能是使用现有的 javascript 库,如 FullCalendar,或者将您自己的 html 直接注入浏览器文档(您可以使用简单的 @987654332 @ 格式化日历)。
下面是一个sample online calendar 在 Access 表单中的 WebBrowser
控件中的示例:
【讨论】:
【参考方案3】:我同意这在 HTML 中效果最好的想法。 用格式化为富文本格式的文本框替换每个子表单。然后在表单加载(或其他一些事件)上获取该月的记录集并循环通过它将文本添加到每个文本框。可用的 HTML 子集通常足以获得您需要的大部分格式。
注意事项
-
就 vba 而言,这需要一些真正的思考。很可能您对此感到满意,因为您已经走到了这一步。
只有一个查询,所以速度可以接受更多
您的关键 HTML 标签将是
<br>
和颜色标签
您将无法仅更改文本颜色的背景颜色(我可能在这里错了)
【讨论】:
当 Office 包含包含功能齐全的日历的 Outlook 时,为什么所有的 HTML 工作? 这是一个很好的观点。但是,有时客户端没有 Outlook,在这种情况下,这可能会有所帮助。我的回答让我想起了一句话“当你只有一把锤子时,每个问题看起来都像钉子”:) 你的评论很好。【参考方案4】:另一种解决方案是制作许多文本框控件,每个控件代表日历日中的记录。
您运行 1 个查询 - 快!
在 VBA 中循环遍历每个文本框控件并为其分配水平和垂直位置、内容(值)、格式、可见性(您不需要显示没有数据的控件)。
缺点是您必须提前决定需要多少个文本框控件,这可能不足以满足查询传递的所有记录。
要克服这个问题,您可以任意决定您有 100 个控件,仅首先显示记录集中更重要的记录(例如过期),并记下“并非所有记录都显示”。如果用户想查看所有记录,他点击特定日期,更详细的子表单打开,显示该日期的所有记录。
我从未在日历中尝试过,但我有一个带有甘特图的表格,显示时间条。每个时间栏都是一个文本框控件。 我有 120 个控件,并且可以立即使用。
【讨论】:
【参考方案5】:另一种解决方案是使用 Tcal,我刚刚更新到版本 1.4.2 什么是 Tcal? Tcal 是具有完整图形界面的客户端-服务器跨平台日历。使用 TcalServer 和 TCP/IP,Tcal 将事件、截止日期和工作时间记录到您公司的个性化 FileMaker Pro、Microsoft Access 或 mysql 数据库文件中。您可以为您的活动分配资源和工作名称、查看其他资源日历、接受或拒绝邀请。 Tcal 适用于 Mac OSX 和 Window(7 或 XP),并且是免费的,最多可供 2 个连接用户使用。 你可以在这里找到 Tcal:http://www.tcal.it/eng/index.html
【讨论】:
以上是关于尝试在 Microsoft Access 中制作高效的日历的主要内容,如果未能解决你的问题,请参考以下文章
尝试使用Microsoft Access更新DataGridView时出错
在 microsoft access 中使用组合框过滤表单结果