我需要为MS-Access 2000编写SQL查询,以便在存在时更新行,但如果不存在则插入。 (我相信这被称为“upsert”)
即
如果存在行...
UPDATE Table1 SET (...) WHERE Column1='SomeValue'
如果它不存在......
INSERT INTO Table1 VALUES (...)
这可以在一个查询中完成吗?
答案 0 :(得分:7)
您可以使用UPDATE
LEFT JOIN
查询来模拟Access中的upsert。
update b
left join a on b.id=a.id
set a.f1=b.f1
, a.f2=b.f2
, a.f3=b.f3
答案 1 :(得分:5)
假设 Column1 上有唯一索引,您可以使用DCount
表达式来确定 Column1 ='SomeValue'是否有零行或一行。然后根据该计数INSERT
或UPDATE
。
If DCount("*", "Table1", "Column1 = 'SomeValue'") = 0 Then
Debug.Print "do INSERT"
Else
Debug.Print "do UPDATE"
End If
我更喜欢这种方法,首先尝试INSERT
,捕获3022密钥违规错误,然后执行UPDATE
以响应错误。但是我无法从我的方法中获得巨大的利益。如果您的表包含自动编号字段,则避免失败的INSERT
会阻止您不必要地消耗下一个自动编号值。我还可以避免在不需要时构建INSERT
字符串。 Access Cookbook 告诉我字符串连接在VBA中是一个中等昂贵的操作,所以我寻找机会避免构建字符串,除非实际需要它们。此方法还可以避免为不需要的INSERT
创建锁定。
然而,这些原因中没有一个对你很有吸引力。老实说,我认为我在这种情况下的偏好可能与我的“感觉正确”有关。我同意@David-W-Fenton对previous Stack Overflow question的评论:“最好编写SQL,这样就不会尝试追加已存在的值 - 即防止错误发生首先,而不是依靠数据库引擎来节省你自己。“
答案 2 :(得分:4)
" upsert"如果表格具有唯一键,则可能。
来自 Smart Access 的旧提示是我的最爱之一:
使用一个查询更新和附加记录
作者:Alan Biggs
您是否知道可以在Access中使用更新查询进行更新 并同时添加记录?如果你有两个,这很有用 表的版本,tblOld和tblNew,并且您想要集成 从tblNew变为tblOld。
请按照以下步骤操作:
创建更新查询并添加两个表。加入两个表 将tblNew的关键字段拖到tblOld的匹配字段上。
双击关系并选择包含来自tblNew的所有记录的连接选项以及仅包含来自tblNew的记录的连接选项 tblOld。
从tblOld中选择所有字段并将它们拖到QBE网格上。
对于每个字段,在tblNew.FieldName中的“更新到”单元格类型中,其中FieldName与tblOld的字段名称匹配。
从“视图”菜单中选择“查询属性”,并将“唯一记录”更改为“假”。 (这会关闭SQL中的DISTINCTROW选项 视图。如果你留下这个,你只能获得一个空白记录 结果,但您希望添加每个新记录的一个空白记录 to tblOld。)
- 醇>
运行查询,您将看到对tblNew的更改现在位于tblOld中。
这只会添加已添加到tblNew的tblOld记录。 在tblNew中没有出现的记录仍将保留在tblNew中 tblOld。
答案 3 :(得分:3)
我通常首先运行insert语句然后检查是否发生了错误3022,这表明该行已经存在。所以像这样:
On Error Resume Next
CurrentDb.Execute "INSERT INTO Table1 (Fields) VALUES (Data)", dbFailOnError
If Err.Number = 3022 Then
Err.Clear
CurrentDb.Execute "UPDATE Table1 SET (Fields = Values) WHERE Column1 = 'SomeValue'", dbFailOnError
ElseIf Err.Number <> 0 Then
'Handle the error here
Err.Clear
End If
<强> EDIT1:强>
我想提一下,我在这里发布的是一个非常常见的解决方案,但你应该知道,计划错误并将它们作为程序正常流程的一部分通常被认为是一个坏主意,特别是如果还有其他方法达到相同的结果。感谢RolandTumble指出这一点。
答案 4 :(得分:3)
您无需捕获错误。相反,只需运行INSERT语句,然后检查
CurrentDb.RecordsAffected
取决于它是1还是0。
注意:对CurrentDB执行是不好的做法。最好将数据库捕获到局部变量:
Dim db As DAO.Database
Set db = CurrentDb
db.Execute(INSERT...)
If db.RecordsAffected = 0 Then
db.Execute(UPDATE...)
End If