1

我想使用 DAO 对 Access 数据库执行查询列表。“Database.Execute()”方法似乎适用于此,它只能执行“操作查询”,即不返回结果集的查询(MSDN 参考)。对于返回记录的查询,可以使用“Database.OpenRecordset()”。如果传递了错误类型的查询,这两种方法都会抛出异常。

在列表中同时拥有操作查询和选择查询,我如何预先决定哪些会返回记录,哪些不会?

4

5 回答 5

1

请注意,无论查询是否返回结果集,都可以使用 ADO Execute 方法。

但是您真的要执行所有“查询”吗?如果它们包含 SQL DDL 怎么办?假设您PROCEDURE使用此 SQL DDL 代码创建了一个:

CREATE PROCEDURE qryDropMe AS DROP PROCEDURE qryDropMe;

;)

于 2009-09-09T15:33:33.593 回答
1

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
于 2009-09-09T18:41:41.673 回答
1

受@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;

谢谢大家的有用答案和评论。

于 2009-09-10T08:21:14.837 回答
0

为什么不捕捉抛出的异常并分析它?

你有什么方法可以使用 beginTrans/Rollback 指令吗?然后您可以发送您的 SQL 命令,收集错误,然后回滚您的事务,让您的数据库保持不变。

使用 ADO 连接怎么样,比 ADO 连接更智能,连接保存一个“错误”集合并返回一些其他数据,如受影响的记录数?

于 2009-09-10T04:51:26.777 回答
-1

此信息适用于查询类型。所以:

  • 所有执行SELECT ... FROM ...的查询都是选择查询
  • 所有INSERTUPDATEDELETE都是操作查询

您只需检查查询 sql 命令文本以查看它是否以上述任何关键字开头并采取相应措施。

于 2009-09-09T15:27:43.747 回答