【问题标题】:Does MS Access suppress primary key violations on Inserts?MS Access 是否会抑制插入时的主键违规?
【发布时间】:2011-08-18 23:13:50
【问题描述】:

我正在将 MS Access 数据库重写到 SQL 服务器,并在 Access 中发现了一个奇怪的问题,希望有人能提供帮助。

我有一个表,我们将其称为“主”表,并在帐户上有一个主键,该表已编入索引且不允许重复。看起来很简单,但我的问题是在插入数据时发生的。

我的 INSERT 查询是(为简洁起见,限制了字段数)

INSERT INTO Main (Account, SentDate, Amount)
SELECT C.Account, C.SentDate, C.Amount
FROM 
    (CALLS C LEFT JOIN Bals B ON C.Account = B.ACCT_ID) 
LEFT JOIN AggAnt A ON C.Account = A.Account

问题是这样的,如果我运行查询的 SELECT 部分,我会得到 2365 条记录,但是当我运行 INSERT 时,我会得到 2364 条记录。所以我做了一些检查,发现一个帐户重复,记录之间的差异是 SentDate 和 Amount。但是 Access 只插入其中一条记录,而不是抛出任何类型的错误消息或任何东西。查询中没有任何内容显示选择最近的日期等。

样本数据:

Account    SentDate   Amount
12345678   8/1/2011   123.00
23456789   8/1/2011   45678.00
34567890   8/1/2011   7850.00
45678912   8/1/2011   635.00
45678912   5/1/2011   982.00
56789123   8/1/2011   2639.00

在示例中,当我运行 INSERT 时,我有一个重复的帐户 45678912,我没有收到任何错误,并且我得到了 2011 年 8 月 1 日的记录。

当这违反了桌面上的 PK 时,为什么 Access 不抛出错误? Access 中是否有一些怪癖来选择一条记录并跳过另一条记录?

我完全被这个问题难住了,所以任何帮助都会很棒。

【问题讨论】:

    标签: sql ms-access primary-key


    【解决方案1】:

    您是如何运行查询的?如果您使用的是DoCmd.RunSQL,请切换到使用DAO 数据库对象的.Execute 方法,并使用dbFailOnError

    Dim db As DAO.Database
    Dim strInsert As String
    strInsert = "your insert statement"
    Set db = CurrentDb
    db.Execute strInsert, dbFailOnError
    Set db = Nothing
    

    编辑:如果 Main 是指向 SQL Server 表的 ODBC 链接,我会检查 db.Execute strInsert, dbFailOnError 之后的 Errors Collection (DAO)

    【讨论】:

    • 我目前使用 DoCmd.OpenQuery "queryname", acViewNormal, acEdit 运行我的查询并且没有错误,但它也通过双击它运行查询我仍然没有错误并且运行成功.
    • 要求您确认时显示的是哪个数字?
    • 它没有显示任何奇怪的部分。
    • 如果您没有收到确认对话框,“您将要追加 2365 行。”这让我想知道 SetWarnings 是否为 False。您的应用程序中是否有任何地方,也许它没有被设置回 True?
    • SetWarnings 再次来袭!我们应该强调这一点,作为对其他人的警告。您可以提交该决议作为答案并接受该决议而不是我的。那太好了,因为我鄙视 SetWarnings False!
    【解决方案2】:

    在 HansUp 向我指出检查 SetWarnings = false 的方向之后。我发现它隐藏在我的代码中,这就是为什么没有关于由于主键违规而未插入记录的警告消息的原因。

    请注意,请确保您希望禁止显示这些消息。

    【讨论】:

    • 在 Access 中执行 SQL 的唯一可靠方法是使用 .Execute strSQL, dbFailOnError。 DoCmd.OpenQuery 和 DoCmd.RunSQL 都是应该避免的,因为当您关闭 SetWarnings 时,您不知道隐藏了哪些错误。我编写了一个函数 SQLRun(),作为我多次发布的 DoCmd.RunSQL 的替代品。它只是.Execute, strSQL, dbFailOnError 的包装,因此您不必每次都编写错误处理程序。在 SO 上搜索并尝试一下。
    • 感谢您将我指向您的功能。我会看看未来的使用。我当前的应用程序正在重写,我不会对已经非常不稳定的应用程序进行任何代码更改。
    • @David-W-Fenton:“在 Access 中执行 SQL 的唯一可靠方法......”......使用 DAO 时。
    【解决方案3】:

    访问 [更新] 一条记录并跳过 其他的?

    是的,您可以在引擎级别控制此行为(如果使用 OLE DB,也可以在记录集级别)。

    对于 OLE DB(例如 ADO),设置为 Jet OLEDB:Global Partial Bulk Ops

    确定 Jet 数据库引擎在 SQL DML 批量处理时的行为 操作失败。当设置为允许部分完成批量 操作,可能会发生不一致的更改,因为对某些操作 记录可能成功,其他记录可能失败。当设置为不允许 批量操作部分完成,所有更改都回滚,如果 发生一个错误。 Jet OLEDB:全球部分批量操作 可以按记录集覆盖属性设置 设置 Jet OLEDB:Partial Bulk Ops 属性 Properties Recordset 对象的集合。

    注意默认是不允许部分完成批量操作。

    【讨论】:

    • 但这是 Jet 在没有明确告诉 Access 忽略 IGNORE 错误时的默认行为(这是您在使用 OpenQuery 或 RunSQL 并关闭 SetWarnings 时所做的事情)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多