我想使用 DAO 对 Access 数据库执行查询列表。“Database.Execute()”方法似乎适用于此,它只能执行“操作查询”,即不返回结果集的查询(MSDN 参考)。对于返回记录的查询,可以使用“Database.OpenRecordset()”。如果传递了错误类型的查询,这两种方法都会抛出异常。
在列表中同时拥有操作查询和选择查询,我如何预先决定哪些会返回记录,哪些不会?
请注意,无论查询是否返回结果集,都可以使用 ADO Execute 方法。
但是您真的要执行所有“查询”吗?如果它们包含 SQL DDL 怎么办?假设您PROCEDURE
使用此 SQL DDL 代码创建了一个:
CREATE PROCEDURE qryDropMe AS DROP PROCEDURE qryDropMe;
;)
Access 维护一个名为 MSysObjects 的隐藏系统表,其中包括一个字段(标志),该字段存储一个指示查询类型的值。您可以使用列表中的每个查询名称尝试以下函数,并使用返回值来确定是使用 Database.Execute() 还是 Database.OpenRecordset()
该函数需要 MSysObjects 的读取权限。我听说过一些 Access 2007 用户被拒绝读取 MSysObjects 的报告。但是,我在 Access 2007 中没有遇到过这个问题。
我测试了几种查询类型以确定标志值。如果您的其中一个查询是我未测试的类型,则该函数将返回 Flags 值无法识别。您可以修改函数以包含该标志类型。
我测试的唯一 DDL 查询是 DROP TABLE (Flags = 96)。
另外,请注意,并非所有“SELECT ... FROM ...”查询都是出于您的目的选择查询(返回记录集)。诸如“SELECT fields INTO newtable FROM oldtable;”之类的查询 不返回记录,并且 Access UI 将其分类为生成表查询。
Public Function QueryType(ByVal pQueryName As String) As String
Dim lngFlags As Long
Dim strType As String
Dim strCriteria As String
strCriteria = "[Name] = """ & pQueryName & """ And [Type] = 5"
lngFlags = DLookup("Flags", "MSysObjects", strCriteria)
Select Case lngFlags
Case 0
strType = "Select"
Case 16
strType = "Crosstab"
Case 32
strType = "Delete"
Case 48
strType = "Update"
Case 64
strType = "Append"
Case 80
strType = "Make Table"
Case 96
strType = "Drop Table"
Case 128
strType = "Union"
Case Else
strType = "Flags " & CStr(lngFlags) & " unrecognized"
End Select
QueryType = strType
End Function
受@HansUp 回答的启发,我对 DAO 接口提供的 QueryDef 结构进行了更多调查。该结构具有“类型”属性,我可以使用它来区分不同的查询类型 ( MSDN )。我最终得到了以下实现:
function TAccessDatabase.SQLExec(AName, AQuery: String): Integer;
var
I: Integer;
QDef: QueryDef;
QDefExists: Boolean;
begin
Result := 0;
// Lookup querydef in the database
QDefExists := False;
for I := 0 to DB.QueryDefs.Count - 1 do
begin
QDef := DB.QueryDefs[I];
if QDef.Name = AName then
begin
QDefExists := True;
break; //-->
end;
end;
// Create query def if it doesn't exists
if not QDefExists then
begin
QDef := DB.CreateQueryDef(AName, AQuery);
// Refresh is required to get the correct QDef.Type_
DB.QueryDefs.Refresh;
end;
// Execute the query only if it is not a SELECT
if QDef.Type_ <> dbQSelect then
begin
db.Execute(AQuery, dbInconsistent);
Result := DB.RecordsAffected;
end;
end;
谢谢大家的有用答案和评论。
为什么不捕捉抛出的异常并分析它?
你有什么方法可以使用 beginTrans/Rollback 指令吗?然后您可以发送您的 SQL 命令,收集错误,然后回滚您的事务,让您的数据库保持不变。
使用 ADO 连接怎么样,比 ADO 连接更智能,连接保存一个“错误”集合并返回一些其他数据,如受影响的记录数?
此信息适用于查询类型。所以:
您只需检查查询 sql 命令文本以查看它是否以上述任何关键字开头并采取相应措施。