ms-access - Access 2007 触发器和程序等效项?

标签 ms-access stored-procedures triggers ms-office

好的,有没有人有一些关于触发器或存储过程的 Access 2007 功能的好资源?它甚至可以做它们或类似于它们的东西吗?我在 Microsoft 帮助中找到的每个资源都引用了 Access 2003,以及许多在线帮助手册。一切都在 2007 年发生了变化,因此翻译较旧的帮助手册有点困难。我真的很想使用 ms sql,但被迫在 Access 中执行这个小项目,因此任何资源都会有所帮助。

很酷,到目前为止所有的答案都是有帮助的。只是想确认一下我拥有的很多零散的 Access 知识。我想我可以让它适用于这个项目。哦,由于很多...繁文缛节,我无法使用 sql。

最佳答案

存储过程

Access 数据库引擎在 ANSI-92 查询模式下支持 CREATE PROCEDURE (SQL DDL) 语法例如

CREATE PROCEDURE GetCompanies
(
 :company_type VARCHAR(30) = NULL
)
AS
SELECT company_registered_number, organisation_name, company_type
  FROM Companies 
 WHERE company_type = IIF(:company_type IS NULL, company_type, :company_type);

因此,结果对象是 PROCEDURE并与表一起存储在数据库文件中。这里的重点是“存储”这个词(而不是“过程”),即它“接近数据”。使用这些对象可以促进前端 (FE) 与后端 (BE) 的良好分离,我的意思是逻辑而非物理;例如,存储在 VBA 代码或 Access Forms 控件属性中的 SQL 代码并不“接近数据”,并且将后端“层”与前端“层”混合在一起,使 SQL 代码的维护更加困难例如如果您需要重命名表中的列,那么工作很容易,只需查看 PROCEDURE s 和 VIEW s。

使用 PROCEDURE 的另一个优势是(或者更确切地说,是)当与用户级安全性 (ULS) 结合使用时,它可以帮助提高“可用性”。举个例子,经常有人问如何将 created_date 列添加到表中并保持其值。添加 DEFAULT的当前时间戳只能让您完成其中的一部分,例如
CREATE TABLE Entities (
   entity_ID CHAR(8) WITH COMPRESSION NOT NULL UNIQUE, 
   CONSTRAINT entity_ID__pattern 
      CHECK (entity_ID NOT ALIKE '%[!0-9]%'), 
   entity_name VARCHAR(20) NOT NULL, 
   CONSTRAINT entity_name__whitespace
      CHECK (
             entity_name NOT ALIKE ' %'
             AND entity_name NOT ALIKE '% '
             AND entity_name NOT ALIKE '%  %'
             AND LEN(entity_name) > 0
            ), 
   created_date DATETIME DEFAULT NOW() NOT NULL
);

但这并不能阻止不是当前时间戳的显式值。我们当然可以添加 CHECK强制执行此操作的约束或验证规则:
ALTER TABLE Entities ADD
   CONSTRAINT entity_created_date__must_be_current_timestamp
      CHECK (created_date = NOW());

这里的问题是 CHECK在行级别检查约束和验证规则,即如果您曾尝试更改另一列,则约束会受到影响。不好,所以:
ALTER TABLE Entities DROP
   CONSTRAINT entity_created_date__must_be_current_timestamp;

该怎么办?好吧,一种方法是从表中删除权限,以便最终用户(以及此上下文中的应用程序也是用户)不能 INSERTUPDATE直接表的数据,然后创建PROCEDURE s 允许更改数据,而是授予对 PROCEDURE 的适当权限。例如
CREATE PROCEDURE AddEntity (
   :entity_ID CHAR(8), 
   :entity_name VARCHAR(20)
)
AS 
INSERT INTO Entities (entity_ID, entity_name, created_date) 
VALUES (:entity_ID, :entity_name, NOW());

EXECUTE EXECUTE AddEntity '00000001', 'Black';

我使用过去时是因为您可能知道,Access 团队(还是 SharePoint 团队?:))从新的 Access2007 ACE 引擎中删除了 ULS。我不确定我是否可以推荐使用已弃用的功能。

现在是坏消息。许多(大多数?)人会争辩说这样的 PROCEDURE不是一个过程,他们有一个很好的观点,因为 Access 数据库引擎的 SQL 语法不支持流控制、变量声明,甚至不支持执行多个 SQL 语句的能力。换句话说,一个 PROCEDURE不能包含程序代码。考虑一个引用实体的表:
CREATE TABLE FlyingEntities (
   entity_ID CHAR(8) WITH COMPRESSION NOT NULL UNIQUE 
      REFERENCES Entities (entity_ID) 
      ON DELETE CASCADE 
      ON UPDATE CASCADE
);

要是有 PROCEDURE 就好了可以在 Entities 中创建一行,也可以根据参数值在 FlyingEntities 中创建一行,但这在单个 SQL 语句中是不可能的。因此,Access 数据库引擎 PROCEDURE值(value)有限,尤其是现在 ULS 已经消失。

触发器

Access 数据库引擎没有,也从未有过触发器,这是无法回避的事实。但问题是,你需要它们吗?

虽然我仍然喜欢 Access 数据库引擎的简单性,但事实是,很多年前我将所有“严肃”的工作转移到更“工业实力”和更多符合 SQL 标准的产品中,主要是 SQL Server。但是,在 SQL Server 中,我只将触发器用于两件事,在 Access 数据库引擎中,这两件事都可以在没有触发器的情况下(在一定程度上)完成。

这些用法首先是为了应对 SQL Server CHECK 的事实。约束不支持子查询;换句话说,它们可以是列级和行级,但不是表级。 Access数据库引擎CHECK Jet 4.0 中引入并仍然存在于 ACE (2007) 中的约束始终是表级的……好吧,它们是理论上的。存在一个问题(疑似错误),它们应该在 SQL 语句级别进行逻辑检查时在行级别进行检查。他们不支持 SQL-92 DEFERRABLE语法,因此没有解决此问题的方法(顺便说一句,SQL Server 在使用 FUNCTION 来解决无子查询限制时遇到了同样的问题)。不是所有 CHECK约束会遇到这个问题,但它的存在让我有点警惕。

对我来说,SQL Server 中触发器的第二次也是最后一次使用是由于另一个限制:尝试创建两个 REFERENCE 时,可怕的“FOREIGN KEY ...可能导致循环或多个级联路径”。 s 到相同的键,例如这在 Access 数据库引擎中是允许的:
CREATE TABLE Marriages (
   entity_ID_1 CHAR(8) WITH COMPRESSION NOT NULL UNIQUE
      REFERENCES Entities (entity_ID) 
      ON DELETE CASCADE 
      ON UPDATE CASCADE, 
   entity_ID_2 CHAR(8) WITH COMPRESSION NOT NULL UNIQUE
      REFERENCES Entities (entity_ID) 
      ON DELETE CASCADE 
      ON UPDATE CASCADE,
   CONSTRAINT cannot_marry_yourself 
      CHECK (entity_ID_1 <> entity_ID_2)
);

但是将其移植到 SQL Server(删除 WITH COMPRESSION 等),这是不允许的。在这种情况下,cannot_marry_yourself 将阻止循环,但 SQL Server 进行简单计数并确定 1 + 1 = 太多。我想,粗鲁但有效。使用触发器是唯一令人满意的解决方法; CASCADE引用 Action 是一个特别痛苦的触发器。

另一方面,Access 数据库引擎在这方面甚至比 SQL Server 更笨,因为它根本不尝试检测周期。如果您确实创建了一个循环,则不会收到任何警告,结果将是最后一次覆盖数据的竞争以及难以调试的情况。

除了这些用法之外,我避免使用触发器,因为它们是维护方面的难题(如果您一开始就可以正确使用它们)。我不知道有多少次同事向我寻求帮助,而我们都对问题可能出在哪里感到困惑,但后来他们羞怯地告诉我,他们忘记了他们创造的触发器。

所以,是的,Access 数据库引擎缺少触发器,但您可能会发现没有它们可能会更好。

哦,不要让我开始阅读 Access 数据库引擎的文档。它是支离 splinter 的,随着时间的推移,其中许多碎片已经消失了,而且许多一开始并不存在,例如我提到了 CHECK上面的约束,但从来没有发布任何细节,只有几个有缺陷的例子(我所知道的所有 CHECK 约束我必须通过反复试验来学习——还有什么是我还没有偶然发现的?!)确实存在的片段包含重大错误和遗漏错误……甚至错误地详细说明了从未存在过的功能!例如CREATE TABLE Statement从 Access2007 帮助中提到了临时表,名为 NOT NULL约束和多列 NOT NULL约束,所有这些都不存在,但没有提到 DEFAULT或事实,有些CONSTRAINT s 不使用索引实现。但 IMO 最严重的遗漏是 Access 数据库引擎表达式的引用,例如IIF()行为不同于 IIf()在 VBA 中,但这似乎目前没有记录。 Jet 3 的 SQL 帮助有这样一个列表,此后没有任何版本,并且 Jet 3 帮助在一两年前从 MSDN 上消失了。缺乏良好的文档确实削弱了 Access 数据库引擎的可信度。

关于ms-access - Access 2007 触发器和程序等效项?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1105872/

相关文章:

vba - 从 Excel 调用的 Access vba 函数会导致返回不同的值

MySQL StoredProcedure 从 select 中设置变量,以参数作为条件

sql - 消息 102,级别 15,状态 1,第 9 行 '-' 附近语法错误

MySQL 更改触发器以使用动态数据库名称

mysql - 在 MYSQL 的 INSERT 期间创建触发器显示错误

ms-access - 部署 MS Access 数据库应用程序以进行数据收集的选项

ms-access - vba 中的 OpenFileDialog 以字符串形式返回目录

SQL - 使用 IN (@Variable_CommaDelimitedListOfIDS) 的带有 Select 语句的存储过程

MySql错误: Can't update table in stored function/trigger because it is already used by statement which invoked this stored function/trigger