You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

迁移至Azure SQL后MS Access更新链接视图遇写入冲突求助

问题概述

我有一个表单(子表单属性不影响问题),其记录源为多表链接视图。此前通过表单更新字段从未出现问题,但将本地SQL数据库迁移至Azure SQL并改用ODBC Driver 17 for SQL Server后,更新字段时频繁出现知名的Write Conflict错误。我曾多次通过确保所有bit字段有默认值且无NULL值解决此类问题,本次还为相关表添加了timestamp字段,但问题仍未解决。另有一个以单表视图为记录源的表单可正常更新,且当前表单无底层代码影响,仅修改单个值并通过写入按钮提交就会报错。我了解到有建议使用查询替代直接绑定视图/表,但该视图包含多个Access难以处理的关联,且此前多年一直正常运行,重构查询难度较大。此外,我已将视图简化为仅包含tblCard,但仍出现相同错误。恳请提供问题原因分析及解决方案建议。

问题根源排查方向
  • ODBC驱动兼容性问题:ODBC Driver 17和旧版驱动(或本地SQL使用的驱动)在并发检测、timestamp字段处理上逻辑不同,加上Azure SQL的网络延迟,容易让Access误判记录被修改。
  • 视图结构限制:就算简化成只包含tblCard,视图里的TOP (100) PERCENT、ORDER BY、自定义函数生成的字段(比如crdScope、orderdate)都会让Access无法正确生成更新语句,或者在比对原始数据时出现偏差。
  • timestamp字段解析差异:Azure SQL里的timestamp(实际是rowversion)生成逻辑和本地SQL有细微差别,Access更新前后比对timestamp值时,可能因为网络传输或驱动解析的问题导致不匹配。
  • 计算字段干扰:tblCard里的crdEntireNumber是计算字段,Access绑定表单时可能把它当成可更新字段,或者比对记录时包含这个字段,导致误报冲突。
  • 无意义自引用外键:tblCard上的FK_tblCard_tblCard是自引用主键的外键,虽然设置了NOCHECK,但可能干扰Access的记录锁定逻辑。
可行的解决办法

驱动与连接配置调整

  • 试试换回ODBC Driver 11或13,如果问题消失,说明是Driver 17的兼容性问题;如果必须用Driver 17,在连接字符串里加UseFMTONLY=No或DataTypeCompatibility=80,强制兼容旧版SQL Server的元数据解析规则。
  • 在Access的ODBC连接设置里开启“使用服务器端游标”,减少本地缓存数据和服务器端的不一致。

视图优化

  • 删掉视图里的TOP (100) PERCENT和ORDER BY,这两个子句会让Access把视图当成不可更新的结果集,排序需求在Access表单的“排序与筛选”里设置就行。
  • 视图里同时存在自定义函数生成的crdScope和tblCard原生的crdScope字段,直接用表原生的字段替换函数生成的,避免字段名冲突或Access混淆。
  • 移除视图里不需要的关联(比如tblCardTransaction、tblImageExported的LEFT JOIN),只保留tblCard的必要字段,降低Access解析更新语句的复杂度。

表结构调整

  • 检查tblCard的crdEntireNumber计算字段,确保Access识别它是只读的;要么在表单里取消这个字段的绑定,要么在视图里排除它。
  • 删掉tblCard上的FK_tblCard_tblCard自引用外键,这个外键没有实际业务作用,反而可能干扰Access的锁定逻辑。
  • 确认所有bit字段的默认值正确,表单里绑定的控件类型和字段匹配(比如用复选框而不是文本框)。

Access表单设置调整

  • 把表单的“记录锁定”改成“编辑的记录”,不要用“所有记录”,减少不必要的锁定冲突。
  • 关掉表单的“自动保存”,用代码手动提交更新,更新前先获取最新的timestamp值,确保比对一致。示例代码:
Dim rs As Recordset
Set rs = Me.RecordsetClone
rs.FindFirst "crdID = " & Me.crdID.Value
rs.Edit
rs!crdStatus = Me.crdStatus.Value
' 其他需要更新的字段同理赋值
rs.Update
Me.Requery

其他排查步骤

  • 用SQL Server Profiler(或Azure SQL的查询存储)捕获Access提交的更新语句,检查WHERE子句是否正确包含了主键和timestamp字段。
  • 直接在Azure SQL里用UPDATE语句修改记录,验证数据库层面有没有并发问题;如果数据库层面正常,那问题肯定出在Access和ODBC驱动的交互上。
相关SQL代码

视图:vewCardsLatestByPerson

CREATE VIEW [dbo].[vewCardsLatestByPerson]
AS
SELECT        TOP (100) PERCENT dbo.tblCard.crdID, 
dbo.tblCard.crdStatus, dbo.tblCard.crdDate, 
dbo.tblCard.crdExpiry, dbo.tblCard.crdType, dbo.tblCard.perID, 
dbo.tblCard.crdACode, dbo.tblCard.crdNumber, 
                     dbo.ufnGetCardScope(dbo.tblCard.crdID) AS 
crdScope, dbo.tblCard.crdColour, dbo.tblCard.logID, 
dbo.tblCard.crdWorkStationID, dbo.tblCard.crdUserID, 
                     CASE WHEN dbo.tblCard.crdStatus = 12 THEN 
'01-JAN-1800' ELSE dbo.tblCard.crdDateCreated END AS orderdate, 
dbo.tblCard.crdDateCreated, dbo.tblCard.batID, 
dbo.tblCard.crdMinor, dbo.tblCard.crdConditional, 
                     dbo.tblCard.crdCardEntireNumber, 
dbo.tblCard.crdUseIF, dbo.tblImageExported.ID, 
dbo.tblCardTransaction.trnDate, dbo.tblCard.jobReady
FROM            dbo.tblCard LEFT OUTER JOIN
                     dbo.tblCardTransaction ON dbo.tblCard.crdID 
= dbo.tblCardTransaction.crdID AND dbo.tblCardTransaction.ctyID = 
4 LEFT OUTER JOIN
                     dbo.tblImageExported ON 
dbo.tblCard.crdCardEntireNumber = dbo.tblImageExported.CardNumber
ORDER BY dbo.tblCard.perID, dbo.tblCard.crdID DESC
GO

表:tblCard

CREATE TABLE [dbo].[tblCard](
    [crdID] [int] IDENTITY(1,1) NOT NULL,
    [crdStatus] [smallint] NOT NULL,
    [crdDate] [smalldatetime] NOT NULL,
    [crdExpiry] [smalldatetime] NOT NULL,
    [crdType] [int] NOT NULL,
    [perID] [int] NOT NULL,
    [crdACode] [nchar](3) NOT NULL,
    [crdNumber] [int] NOT NULL,
    [crdScope] [nchar](3) NOT NULL,
    [crdColour] [nchar](1) NOT NULL,
    [logID] [int] NULL,
    [crdWorkStationID] [nchar](25) NULL,
    [crdUserID] [nchar](100) NULL,
    [crdDateCreated] [datetime] NULL,
    [batID] [int] NULL,
    [crdMinor] [bit] NOT NULL,
    [crdConditional] [bit] NOT NULL,
    [crdEntireNumber]  AS (calculated field)
    [crdUseIF] [bit] NOT NULL,
    [crdIssuer] [nvarchar](50) NULL,
    [issBatID] [int] NULL,
    [crdVersion] [nvarchar](10) NULL,
    [NewFormat] [bit] NOT NULL,
    [CASA] [bit] NOT NULL,
    [jobReady] [bit] NOT NULL,
    [CRN] [nvarchar](10) NULL,
    [BatchID] [int] NULL,
    [timestamp] [timestamp] NOT NULL,
 CONSTRAINT [PK_tblCard] PRIMARY KEY CLUSTERED 
(
    [crdID] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[tblCard] ADD  CONSTRAINT [DF_tblCard_crdStatus]  DEFAULT ((0)) FOR [crdStatus]
GO

ALTER TABLE [dbo].[tblCard] ADD  CONSTRAINT [DF_tblCard_crdDate]  DEFAULT ('1/1/2000') FOR [crdDate]
GO

ALTER TABLE [dbo].[tblCard] ADD  CONSTRAINT [DF_tblCard_crdExpiry]  DEFAULT ('1/1/2000') FOR [crdExpiry]
GO

ALTER TABLE [dbo].[tblCard] ADD  CONSTRAINT [DF_tblCard_crdType]  DEFAULT ((0)) FOR [crdType]
GO

ALTER TABLE [dbo].[tblCard] ADD  CONSTRAINT [DF_tblCard_crdNumber]  DEFAULT ((0)) FOR [crdNumber]
GO

ALTER TABLE [dbo].[tblCard] ADD  CONSTRAINT [DF_tblCard_crdDateCreated]  DEFAULT ((sysdatetimeoffset() AT TIME ZONE 'AUS Eastern Standard Time')) FOR [crdDateCreated]
GO

ALTER TABLE [dbo].[tblCard] ADD  CONSTRAINT [DF_tblCard_crdMinor]  DEFAULT ((0)) FOR [crdMinor]
GO

ALTER TABLE [dbo].[tblCard] ADD  CONSTRAINT [DF_tblCard_crdConditional]  DEFAULT ((0)) FOR [crdConditional]
GO

ALTER TABLE [dbo].[tblCard] ADD  CONSTRAINT [DF_tblCard_crdUseICAO]  DEFAULT ((0)) FOR [crdUseICAO]
GO

ALTER TABLE [dbo].[tblCard] ADD  CONSTRAINT [DF_tblCard_NewFormat]  DEFAULT ((1)) FOR [NewFormat]
GO

ALTER TABLE [dbo].[tblCard] ADD  CONSTRAINT [DF_tblCard_CASA]  DEFAULT ((0)) FOR [CASA]
GO

ALTER TABLE [dbo].[tblCard] ADD  CONSTRAINT [DF_tblCard_jobReady]  DEFAULT ((0)) FOR [jobReady]
GO

ALTER TABLE [dbo].[tblCard]  WITH NOCHECK ADD  CONSTRAINT [FK_tblCard_tblCard] FOREIGN KEY([crdID])
REFERENCES [dbo].[tblCard] ([crdID])
GO

ALTER TABLE [dbo].[tblCard] CHECK CONSTRAINT [FK_tblCard_tblCard]
GO

表:tblCardTransaction

CREATE TABLE [dbo].[tblCardTransaction](
    [trnID] [int] IDENTITY(1,1) NOT NULL,
    [trnDate] [datetime] NOT NULL,
    [ctyID] [int] NULL,
    [trnDetails] [nvarchar](500) NULL,
    [crdID] [int] NOT NULL,
    [trnwkstationID] [nvarchar](50) NULL,
    [trnUserID] [nvarchar](50) NULL,
    [timestamp] [timestamp] NOT NULL,
 CONSTRAINT [PK_tblCardTransaction] PRIMARY KEY CLUSTERED 
(
    [trnID] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

表:tblImageExported

CREATE TABLE [dbo].[tblImageExported](
    [Number] [nvarchar](50) NOT NULL,
    [ID] [nvarchar](50) NOT NULL,
    [perName] [nvarchar](100) NOT NULL,
    [ImportFileName] [nvarchar](256) NOT NULL,
    [timestamp] [timestamp] NULL,
 CONSTRAINT [PK_tblImageExported] PRIMARY KEY CLUSTERED 
(
    [Number] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

内容的提问来源于stack exchange,提问作者ibeme99

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 22:15:55