字符串在 MSAccess 的 VBA 代码的 For Each 循环中异常行为

String acting abnormally in a For Each loop in VBA code in MSAccess

提问人: 提问时间:12/29/2008 最后编辑:10 revs, 3 users 70%Andrew G. Johnson 更新时间:5/27/2015 访问量:1971

问:

好的,所以我从一个问题开始,并根据这个网站和其他网站的建议对代码进行了大量更改,所以我想我应该创建一个新问题。

尽管我的代码更短、更高效,但同样的问题仍然存在;我正在使用一个名为 strSQL 的字符串,其中包含我想要执行的 INSERT 语句。我有一个 FOR EACH 循环,它遍历我的 MSAcess 窗体上的每个控件(确保它们是文本框、下拉列表或复选框)并确定字段是否已更改。如果有,它会生成一个查询字符串来记录更改,并将其存储在 strSQL 中。

问题在于,同一个查询被一次又一次地执行。我添加了一个 DEBUG。执行查询字符串的行之前和之后的 PRINT 语句,调试器显示字符串已更改!是的,你没看错,这似乎是不可能的,但我已经截屏了。

首先是我的代码:

Private Sub Form_BeforeUpdate(Cancel As Integer)
    Dim C As Control
    For Each C In Controls
        Select Case C.ControlType
            Case acTextBox, acComboBox, acCheckBox
                Dim strOriginalValue, strCurrentValue, strSQL As String

                strOriginalValue = IIf(IsNull(C.OldValue), "", IIf(C.OldValue = vbTrue Or C.OldValue = vbFalse, IIf(C.OldValue = vbTrue, "Yes", "No"), C.OldValue))
                strCurrentValue = IIf(IsNull(C.Value), "", IIf(C.Value = vbTrue Or C.Value = vbFalse, IIf(C.Value = vbTrue, "Yes", "No"), C.Value))

                If strOriginalValue <> strCurrentValue Then
                    strSQL = "INSERT INTO fringefestival_changes (change_time,change_admin,action_taken,user_affected,year_affected,field_affected,type_affected,old_value,new_value) VALUES (NOW(),'" & ThisUserName() & "','Edit'," & [id] & ",0,'" & C.ControlSource & "','Administrator','" & Replace(strOriginalValue, "'", "") & "','" & Replace(strCurrentValue, "'", "") & "')"
                    Debug.Print "Before: " & strSQL
                    CurrentDb.Execute strSQL, dbFailOnError
                    Debug.Print "After: " & strSQL
                End If
        End Select
    Next
End Sub

下面是调试器的结果:

Before: INSERT INTO fringefestival_changes (change_time,change_admin,action_taken,user_affected,year_affected,field_affected,type_affected,old_value,new_value) VALUES (NOW(),'ajohnson','Edit',3,0,'indoor_performers_tab','Administrator','No','Yes')
After: INSERT INTO fringefestival_changes (change_time,change_admin,action_taken,user_affected,year_affected,field_affected,type_affected,old_value,new_value) VALUES (NOW(),'ajohnson','Edit',3,0,'indoor_performers_tab','Administrator','No','Yes')
Before: INSERT INTO fringefestival_changes (change_time,change_admin,action_taken,user_affected,year_affected,field_affected,type_affected,old_value,new_value) VALUES (NOW(),'ajohnson','Edit',3,0,'volunteers_tab','Administrator','No','Yes')
After: INSERT INTO fringefestival_changes (change_time,change_admin,action_taken,user_affected,year_affected,field_affected,type_affected,old_value,new_value) VALUES (NOW(),'ajohnson','Edit',3,0,'volunteers_tab','Administrator','No','Yes')

其次,我的截图...首先是调试器:12,其次是结果:这里 -- 请注意,调试器太宽了,所以我截取了两张屏幕截图,结果有一行被涂掉了,因为它与这个问题无关。

请注意,在我给出的示例中,唯一应该不同的列应该是“field_affected”列。

我完全不知所措,我不知道为什么它会将正确的字符串输出到调试器并执行其他操作。

编辑:在使用CurrentDb.Execute之前,我使用的是DoCmd.RunSQL,但这需要我禁用然后重新启用警告。由于两者的结果相同(相同的错误),因此我使用了单行解决方案而不是三行解决方案。

更新:感谢 shahkalpesh 帮助我意识到数据确实被正确插入,我可以在 SQL Server 的 management studio 中看到它,但 MS Access 仍然错误地显示它......问题是为什么?

最终编辑:通过向表中添加标识/自动递增整数列来修复,我怀疑缺少不同的字段值使 MSAccess 感到困惑(尽管它确实没有理由)——这里的士气是 M$ 是愚蠢的

MS-Access VBA

评论

0赞 Fionnuala 12/29/2008
请准确指出 SQL 字符串之前和之后的差异。你有两个前后集合,它们彼此不同,但据我所知,前后是一样的。
0赞 Fionnuala 12/29/2008
PS 您可以简化:strOriginalValue = IIf(C.OldValue = vbTrue 或 C.OldValue = vbFalse, _ Format(C.OldValue, “Yes/No”), Nz(C.OldValue, “”))
0赞 Fionnuala 12/29/2008
请不要使用屏幕截图,请在您的文本中显示您关注之前和之后的差异 - 我只能看到代码中请求的 SQL 输出。
0赞 Andrew G. Johnson 12/29/2008
Remou - 结果已添加为文本
0赞 Fionnuala 12/29/2008
您关心的区别在哪里?我看不出有什么问题,SQL正在按预期执行。你想发生什么?

答:

1赞 Mitch Wheat 12/29/2008 #1

有问题的表单是否绑定到数据源?这是使用 Access 的最常见方式,如果是这样,您可能不需要通过 SQL 进行更新。

Form_BeforeUpdate() 通常在表单绑定到数据源时使用。通常不会使用此事件来确定控件的值是否已更改,是否需要写回数据库...

评论

0赞 Andrew G. Johnson 12/29/2008
是的,我只使用 MSAccess 作为前端 - 所有数据都存储在 SQL Server 数据库中。在这种情况下,你会建议我做什么?
0赞 Andrew G. Johnson 12/29/2008
此外,我正在使用 ODBC 连接到数据库,如果这还不明显......
0赞 Mitch Wheat 12/29/2008
如果窗体及其控件绑定到数据源(术语中是基于链接表的查询),则可能不需要编写任何代码(除非要在编写之前截获和更改值)来保存更改的信息...
0赞 Andrew G. Johnson 12/29/2008
你是说我应该使用我假设的触发器。我最初走的是这条路,但决定不这样做,因为我需要记录进行更改的人的活动目录用户名(ThisUserName()的返回值),并且无法通过触发器做到这一点。
0赞 Andrew G. Johnson 12/29/2008
这是当地节日的管理模块。如果对表演者、节目等进行了更改,首席管理员希望查看究竟是谁进行了更改以及更改是什么——也称为旧/新值
0赞 Stefan 12/29/2008 #2

您对 currentdb(我假设是 access-db)运行这些查询,但实际上使用的是您希望发生更改的 SQL Server 数据库?

sql Server 中的这些表是否链接到 access-db 中的表,或者您使用的是什么方法?

评论

0赞 Andrew G. Johnson 12/29/2008
是的,它们是链接到 SQL Server 数据库的表。
0赞 Stefan 12/29/2008
你确定这些链接指向你认为的数据库吗?我犯过很多次错误(在不同的开发/部署服务器之间切换时),在错误的数据库中查找,以为我在我的本地数据库上工作,但实际上与另一个数据库运行。
0赞 Andrew G. Johnson 12/29/2008
不,我敢肯定,不仅只有一个数据库运行此架构,而且即使我连接到错误的数据库,我仍然不会因此而出现此错误。
0赞 Stefan 12/29/2008
如果“其他”数据库已经只有这两条记录并且从未更新过,它“可以”以这种方式表现出来,只显示它们。但是好吧,如果你排除了这一点,那么我们必须检查其他可能性
0赞 Lasse V. Karlsen #3

您是否检查过表中是否有损坏的触发器?这是一个很长的镜头,但一些非常非常奇怪的问题是由之前坏/损坏的触发器引起的,在你注意到触发器之前,它们很难理解......

评论

0赞 Andrew G. Johnson 12/29/2008
整个数据库上没有触发器,但有一个有效的建议。
1赞 shahkalpesh 12/29/2008 #4

如果可以转到特定的SQL Server表(使用查询分析器或Enterprise Mgr),并查看它是否按预期工作。我怀疑VBA中的链接表可能会向您显示不正确的图片。

编辑:如果您有 SQL 事件探查器,请查看那里正在执行的内容,以确认您对执行同一查询的怀疑。

评论

0赞 Andrew G. Johnson 12/29/2008
哇,你是绝对正确的。如果我直接进入 SQL Server,数据是正确的。当我看到这个时,我实际上笑出声来,现在的问题是:为什么它在MS Access中无法正确显示?
0赞 shahkalpesh 12/29/2008
不确定那部分。但是,即使在 Access 中工作时,我也观察到了这一点。而且,我想在你回复查询后写它,在调试窗口中正确打印:)
-1赞 John Mo 12/29/2008 #5

啊,你也在使用 SQL Server。我很幸运地使用触发器来审核 Access 背后的数据更改。有几个怪癖,但是使用受信任的身份验证通过 ODBC 链接表非常容易。

好的,所以你不能或不想使用触发器。使用 Access 前端 SQL 时,我通常在 VBA 代码中使用 ADO 对象来执行此类操作。带有 ODBC 的链接表非常适合绑定表单,但没有什么比 ADO 更适合直接转到 SQL Server。

您是否希望了解有关使用受信任的身份验证链接表的详细信息,或者有关使用 ADO 执行 SQL Server 工作的帮助?

0赞 Andrew G. Johnson #6

通过向更改表添加自动递增的整数主键列来修复。

傻傻的存取...

评论

0赞 David-W-Fenton 1/2/2009
不,愚蠢的 Andrew G. Johnson 不知道如何设计 Access 应用程序。如果您考虑过 ODBC 必须如何工作,您就会意识到主键对于所有表都是必不可少的,并且需要时间戳字段来刷新绑定表单中的数据。
0赞 Andrew G. Johnson 1/2/2009
愚蠢的 ODBC* -- 为什么你认为拥有所有这些额外的不必要的担忧是明智的?
-1赞 2 revs, 2 users 70%David-W-Fenton #7

我不得不说,围绕这个问题的讨论让我发疯。使用 ODBC 链接表时,可以从绑定表单开始。根本没有理由使用池连接。如果您对如何执行这些操作的 Access 实现怀有敌意,请停止使用 ACCESS。