带有 SQL Server 后端更新的 MS Access 失败且没有错误
Posted
技术标签:
【中文标题】带有 SQL Server 后端更新的 MS Access 失败且没有错误【英文标题】:MS Access with SQL Server back-end update fails without error 【发布时间】:2019-08-11 19:54:15 【问题描述】:这个简单的 VBA 语句不能按预期工作:
strSQl = "UPDATE Inventory SET NumberOfBlocks = BlocksReserved, LastUser = 'Me' WHERE InventoryID = 1234;"
CurrentDb.Execute strSQl, dbFailOnError + dbSeeChanges
LastUser 更新了,但 NumberOfBlocks 保持不变,没有错误。
如果我在 SSMS 中或作为 Access 查询运行此语句,它会起作用。
如果我在 VBA 语句中使用变量 ..."SET NumberOfBlocks = " & intBlocksReserved & ",...,它可以工作。
恒定工作:..."SET NumberOfBlocks = 555"...
这个也有效:NumberOfBlocks = (BlocksReserved * 1)
NumberOfBlocks 和 BlocksReserved 都是 smallint 且不为 null;记录有一个时间戳/行版本字段。
环境:Access 2016 和 SQL 2016 后端。
任何想法为什么我的初始陈述会默默地失败?谢谢!
更多测试证实了我之前的发现:
-
创建了一个新的 Access db,表 Inventory:ID (AutoNumber, PK), NumberOfBlocks (Integer), BlocksReserved (Integer), LastUser (Short Text 10)
在 SQL Server 中创建了一个表:
[ID] [int] IDENTITY(1,1) 非空, [NumberOfBlocks] [smallint] NULL, [BlocksReserved] [smallint] NULL, [LastUser] nvarchar NULL, [RV] [时间戳] NOT NULL
设置ID为主键,链接SQL表,两者都输入测试数据。
在两张表上运行完全相同的代码(仅更改了表名):
将 strSQl 变暗为字符串
strSQl = "UPDATE Inventory SET NumberOfBlocks = BlocksReserved, LastUser = 'Me';" CurrentDb.Execute strSQl,dbFailOnError + dbSeeChanges
结果:
本地访问表:NumberOfBlocks = BlocksReserved, LastUser = 'Me'
链接的 SQL 表:NumberOfBlocks 不变,LastUser = 'Me'
更多注释:
将 SQL Server 中的数据类型更改为 int(而不是 smallint)并没有什么不同。但是,显式转换字段是有效的:
...SET NumberOfBlocks = CInt(BlocksReserved)...
就像
...SET NumberOfBlocks = (BlocksReserved * 1)...
我猜,这将我的帖子从一个问题变成了一个提醒......
【问题讨论】:
静默失败,因为 CurrentDb.Execute 是为这种行为而设计的。为什么要用同一张表中另一个字段的相同数据更新一个字段? 这条记录的字段比较多。我不得不拆分原始记录,即我首先插入了一个包含剩余可用库存数量的记录,这使得原始记录完全保留给该订单号,即它允许我们稍后更改或取消该订单。 为什么要保存“剩余可用库存数量”?评论allenbrowne.com/AppInventory.html 其背后的业务逻辑有点复杂,可能是我解释的不好——抱歉!但我的问题纯粹是技术问题:为什么“SET NumberOfBlocks = BlocksReserved”会失败,而“SET NumberOfBlocks = 50”或 SET NumberOfBlocks = (BlocksReserved * 1)” 有效。 由于其他人似乎忽略了您已经分享的细节(即,对我来说很明显您已经检查过数据类型等),我会冒险并责怪 Access。由于它没有将其作为传递执行,因此 Access 必须在发送到 SQL Server 之前分析和重建查询。抱歉,我不熟悉 SQL Server,但我知道您应该能够观察到从 Access 传递到服务器的查询。我怀疑 SQL Server 没有收到相同的查询。这并没有解释为什么会发生这种情况,而是将原因归结为 Access。 【参考方案1】:进一步的测试证实这是执行命令在以下情况下的错误:
这是一条 UPDATE 语句,其中一个整数字段被分配给另一个整数字段,例如 SET FieldA = FieldB(相同的数字数据类型) 它是 SQL Server 中的链接表。同样的 SQL 语句也可以正常工作
在 Access 中使用表或 在查询中使用时。经过测试的解决方法:
显式转换字段:SET FieldA = CInt(FieldB)...(或 CLng...) 使用任何计算:SET FieldA = FieldB * 1 使用变量:SET FieldA = " & intFieldB【讨论】:
【参考方案2】:这很有趣。我可以使用 Access 2010、SQL Server 2008 R2、ODBC Driver 17 for SQL Server 重现它。
但仅如果 (N)VARCHAR 列包含在 UPDATE
查询中!UPDATE AAA SET Smallint2 = Smallint1, Int2 = Int1;
有效。
CREATE TABLE AAA (
ID int IDENTITY(1,1) NOT NULL,
Smallint1 SMALLINT NULL,
Smallint2 SMALLINT NULL,
Int1 INT NULL,
Int2 INT NULL,
foo NVARCHAR(255) NULL,
RV TIMESTAMP NOT NULL,
CONSTRAINT PK_AAA PRIMARY KEY (ID)
)
GO
INSERT AAA (Smallint1, Smallint2, Int1, Int2, foo)
VALUES (1, 0, 77, 9999, 'asdf'),
(3456, NULL, NULL, 1234, 'null')
访问-VBA:
Sub TestAAA()
Dim strSql As String
strSql = "UPDATE AAA SET Smallint2 = Smallint1, Int2 = Int1;"
CurrentDb.Execute strSql, dbFailOnError + dbSeeChanges
Stop
' Requery table => UPDATE was successful!
' Edit and save values in Smallint1 / Int1
strSql = "UPDATE AAA SET Smallint2 = Smallint1, Int2 = Int1, foo = 'with NVARCHAR';"
CurrentDb.Execute strSql, dbFailOnError + dbSeeChanges
Stop
' Requery => Smallint2 / Int2 are not updated, "foo" is!
strSql = "UPDATE AAA SET Smallint2 = CInt(Smallint1), Int2 = CLng(Int1), foo = 'with Conversion';"
CurrentDb.Execute strSql, dbFailOnError + dbSeeChanges
' Requery => Smallint2 / Int2 are updated!
End Sub
结果:
初始状态 第一次更新后 手动编辑和第二次更新后 第三次更新后+----+-----------+-----------+-----------+-----------+-----------------+
| ID | Smallint1 | Smallint2 | Int1 | Int2 | foo |
+----+-----------+-----------+-----------+-----------+-----------------+
| 1 | 1 | 0 | 77 | 9999 | asdf |
| 2 | 3456 | | | 1234 | null |
| | | | | | |
| ID | Smallint1 | Smallint2 | Int1 | Int2 | foo |
| 1 | 1 | 1 | 77 | 77 | asdf |
| 2 | 3456 | 3456 | | | null |
| | | | | | |
| ID | Smallint1 | Smallint2 | Int1 | Int2 | foo |
| 1 | 222 | 1 | 988888888 | 77 | with NVARCHAR |
| 2 | 333 | 3456 | 999999999 | | with NVARCHAR |
| | | | | | |
| ID | Smallint1 | Smallint2 | Int1 | Int2 | foo |
| 1 | 222 | 222 | 988888888 | 988888888 | with Conversion |
| 2 | 333 | 333 | 999999999 | 999999999 | with Conversion |
+----+-----------+-----------+-----------+-----------+-----------------+
【讨论】:
我可以使用 SQL Server 2016 Developer 在 Access 2016 (365) 中确认您的观察结果:如果没有 nvarchar 字段作为更新的一部分,则不需要转换。以上是关于带有 SQL Server 后端更新的 MS Access 失败且没有错误的主要内容,如果未能解决你的问题,请参考以下文章
MS Access VBA 和 SQL Server - 记录集更新时 ODBC 调用失败
SQL Server 扩展属性 MS_SubdatasheetName
MS Access 2003 可以连接到的最新 SQL Server 后端是啥?