在 Microsoft Access 中更新插入
我需要为 MS-Access 2000 编写一个 SQL 查询,以便更新行(如果存在),但如果不存在则插入。 (我相信这称为“upsert”)
即
如果行存在...
UPDATE Table1 SET (...) WHERE Column1='SomeValue'
如果它不存在...
INSERT INTO Table1 VALUES (...)
这可以在一个查询中完成吗?
I need to write an SQL query for MS-Access 2000 so that a row is updated if it exists, but inserted if it does not. (I believe this is called an "upsert")
i.e.
If row exists...
UPDATE Table1 SET (...) WHERE Column1='SomeValue'
If it does not exist...
INSERT INTO Table1 VALUES (...)
Can this be done in one query?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您可以通过使用带有
LEFT JOIN
的UPDATE
查询来模拟Access 中的更新插入。(编辑,2023 年 8 月)
有些人可能会发现这种形式更容易理解:
You can simulate an upsert in an Access by using an
UPDATE
query with aLEFT JOIN
.(Edit, August 2023)
Some people might find this form easier to understand:
假设Column1上有唯一索引,您可以使用
DCount
表达式来确定是否有零行或一行Column1 = 'SomeValue'。然后根据该计数INSERT
或UPDATE
。我更喜欢这种方法,而不是首先尝试
INSERT
,捕获 3022 键违规错误,然后执行UPDATE
来响应该错误。然而,我不能声称我的方法有巨大的好处。如果您的表包含自动编号字段,避免失败的INSERT
将阻止您不必要地消耗下一个自动编号值。我还可以避免在不需要时构建INSERT
字符串。 Access Cookbook 告诉我,字符串连接在 VBA 中是一项成本较高的操作,因此我寻找机会避免构建字符串,除非确实需要它们。此方法还将避免为不需要的 INSERT 创建锁。然而,这些理由对你来说可能都不是很有吸引力。老实说,我认为在这种情况下我的偏好可能是关于我“感觉正确”的。我同意 @David-W-Fenton 对 上一个堆栈溢出问题:“最好编写 SQL,这样您就不会尝试附加已经存在的值——即,从一开始就防止错误发生,而不是依赖数据库引擎来保存你从你自己开始。”
Assuming a unique index on Column1, you can use a
DCount
expression to determine whether you have zero or one row with Column1 = 'SomeValue'. ThenINSERT
orUPDATE
based on that count.I prefer this approach to first attempting an
INSERT
, trapping the 3022 key violation error, and doing anUPDATE
in response to the error. However I can't claim huge benefits from my approach. If your table includes an autonumber field, avoiding a failedINSERT
would stop you from expending the next autonumber value needlessly. I can also avoid building anINSERT
string when it's not needed. The Access Cookbook told me string concatenation is a moderately expensive operation in VBA, so I look for opportunities to avoid building strings unless they're actually needed. This approach will also avoid creating a lock for an unneededINSERT
.However, none of those reasons may be very compelling for you. And in all honesty I think my preference in this case may be about what "feels right" to me. I agree with this comment by @David-W-Fenton to a previous Stack Overflow question: "It's better to write your SQL so you don't attempt to append values that already exist -- i.e., prevent the error from happening in the first place rather than depending on the database engine to save you from yourself."
如果表具有唯一键,则可以进行“更新插入”。
Smart Access 的这个旧技巧是我最喜欢的技巧之一:
An "upsert" is possible, if the tables have a unique key.
This old tip from Smart Access is one of my favourites:
我通常先运行插入语句,然后检查是否发生错误 3022,这表明该行已经存在。所以像这样:
编辑1:
我想提一下,我在这里发布的内容是一个非常常见的解决方案,但您应该意识到,计划错误并将其用作程序正常流程的一部分通常被认为是一个坏主意,特别是如果有其他方法达到相同的结果。感谢 RolandTumble 指出了这一点。
I usually run the insert statement first and then I check to see if error 3022 occurred, which indicates the row already exists. So something like this:
Edit1:
I want to mention that what I've posted here is a very common solution but you should be aware that planning on errors and using them as part of the normal flow of your program is generally considered a bad idea, especially if there are other ways of achieving the same results. Thanks to RolandTumble for pointing this out.
您不需要捕获错误。相反,只需运行 INSERT 语句,然后检查
它是 1 还是 0,具体取决于情况。
注意:针对 CurrentDB 执行并不是一个好习惯。最好将数据库捕获到局部变量:
You don't need to catch the error. Instead, just run the INSERT statement and then check
It will either be 1 or 0, depending.
Note: It's not good practice to execute against CurrentDB. Better to capture the database to a local variable:
正如其他人提到的,您可以使用新表作为左侧来使用
UPDATE LEFT JOIN
进行UPSERT
。这将添加所有丢失的记录并更新匹配的记录,使已删除的记录保持不变。如果我们遵循 创建并运行更新查询文章 我们最终会得到如下所示的 SQL:
但是内部联接只会更新匹配的记录,不会添加新记录。因此,让我们将
INNER
更改为LEFT
:现在保存数据库的副本。在主数据库上运行此测试之前,请先在副本上运行测试。
As others have mentioned, You can
UPSERT
with anUPDATE LEFT JOIN
using the new table as the left hand side. This will add all missing records and update matching records, leaving deleted records intact.If we follow the Create and run an update query Article we will end up with SQL that looks like this:
but an inner join will only update matching records, it won't add new records. So let's change that
INNER
to aLEFT
:Now save a copy of the DB. Run a test on the copy before you run this on your primary DB.