我们有以下情况:
我们的主数据库是 OpenEdge 数据库,我们有一个 SQL 数据库,必须与 OE 数据库同步。我们提出了一个计划,为 OE 表设置暂存表,在其中复制新创建的记录,并添加几个额外字段来记录创建记录的用户、日期等。我们已成功连接这两个数据库使用 OE DataServer,但是我们在设置触发器来查找新创建的记录并将它们复制到临时表并为这些附加日志记录字段分配值时遇到了麻烦。
我们尝试使用 RECID 作为新创建记录的标识符,并提出了一个可以处理该问题的触发过程。问题是,当作为程序运行时,它工作得很好。它找到记录并将所有内容复制到暂存表,没有任何问题。但是当我们在数据库上设置 CREATE 触发器来运行该过程时,我们会收到错误。
程序如下:
将变量 cRECID 定义为 RECID NO-UNDO。 将变量 cUser 定义为不可撤消字符。
cUser = USERID("maticna").
对于每个 Artikli NO-LOCK BY RECID(Artikli): 分配 cRECID = RECID(Artikli)。 结束。
如果 cRECID <> ?然后 做: 对于每个 Artikli,其中 RECID(Artikli) = cRECID :
FIND FIRST stagingArtikli WHERE RECID(stagingArtikli) = cRECID NO-LOCK NO-ERROR.
IF NOT AVAILABLE stagingArtikli THEN
DO:
CREATE stagingArtikli.
BUFFER-COPY Artikli TO stagingArtikli.
ASSIGN
stagingArtikli.CreatedBy = cUser
stagingArtikli.CreateDate = NOW
stagingArtikli.Replicated = NO
stagingArtikli.Edited = NO
stagingArtikli.EditDate = ?
stagingArtikli.EditUser = " "
.
END.
END.
结束。
当尝试使用以下简单过程创建新的 Artikli 记录时:
创建文章。 分配 Artikli.SifArtik =“12345678” Artikli.Name =“测试” 等等...
它会抛出一个错误,指出 Artikli.SifArtik 是强制性的,但具有未知(?)值。 (110)
您可能创建了 Artikli 表并将 SifArtik 字段的“强制”字段设置为 TRUE。您可能不应该这样做,最简单的解决方法是将必填字段设置为 FALSE。
在我看来,您显示的代码行似乎没有明显的问题会引发错误(110)。所以我建议你在启动参数中添加“-clientlog somefile.debug”。这将识别哪一行代码引发错误 (110)。另外 - 确保单行上没有多个语句(如示例代码所示)。
除此之外,您还需要注意 RECID 不是唯一值。 RECID 可以重用,并且不同的表甚至同一个表(如果分布在多个分区或租户中)可能存在相同的 RECID。如果您的数据通过转储和加载或表移动或类似方法重新组织,RECID 也会发生变化。因此,您可能希望找到一种不同的方法来唯一标识您的暂存记录。例如序列号或 GUID。
接下来,您的 FIND FIRST 要么会导致错误(因为您可能有重复的 RECID),要么毫无意义(如果您有真正独特的关系)。 FIRST 并不是每个 FIND 都需要的语法糖。仅当您确实真正打算处理一组记录中的第一条记录时才应使用它,如果是这种情况,则您缺少处理第二条、第三条等记录的任何代码。另外,你没有任何东西可以确定“第一”关系是如何确定的。在这种情况下,你希望运气好。 RECID 是一个整数,您将“首先”获得编号最小的记录。但其他 WHERE 子句的情况并非总是如此。例如,GUID 就不会有如此幸运的订购关系。
最后,为此目的使用触发器将仅捕获通过 4GL 代码发生的更改。如果允许某人与数据库建立 SQL 连接并授予创建或更新数据的权限,那么这些更改不会触发 4gl 触发器,并且您尝试跟踪此类更改将会失败。
好吧,还有一件事......这整件事就是“更改数据捕获”功能的设计目的。为此目的实施 CDC 会更加可靠和直接。为此,您至少需要运行 OpenEdge 11.7。还有一款名为“Pro2”的产品可以为您完成这项工作。在旧版本中,Pro2 使用触发器,就像您一样。在较新的版本中,它可以使用 CDC 来跟踪更改。