【问题标题】:MS Access with SQL Server back-end update fails without error带有 SQL Server 后端更新的 MS Access 失败且没有错误
【发布时间】: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 后端。

任何想法为什么我的初始陈述会默默地失败?谢谢!


更多测试证实了我之前的发现:

  1. 创建了一个新的 Access db,表 Inventory:ID (AutoNumber, PK), NumberOfBlocks (Integer), BlocksReserved (Integer), LastUser (Short Text 10)
  2. 在 SQL Server 中创建了一个表:

    [ID] [int] IDENTITY(1,1) 非空, [NumberOfBlocks] [smallint] NULL, [BlocksReserved] [smallint] NULL, [LastUser] nvarchar NULL, [RV] [时间戳] NOT NULL

  3. 设置ID为主键,链接SQL表,两者都输入测试数据。

  4. 在两张表上运行完全相同的代码(仅更改了表名):

    将 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。

标签: sql-server ms-access vba sql-update sqldatatypes


【解决方案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 字段作为更新的一部分,则不需要转换。
    猜你喜欢
    • 1970-01-01
    • 2017-01-28
    • 2013-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多