【问题标题】:Check if access table exists检查访问表是否存在
【发布时间】:2011-02-28 10:55:24
【问题描述】:

我想记录网站访问的 IP、日期时间、客户端和引用数据以访问数据库,但我计划将每天的日志数据记录在单独的表中,例如 06.06.2010 的日志将记录在 2010_06_06 命名表中.更改日期后,我将创建一个名为 2010_06_07 的表。但问题是这个表是否已经创建。

关于如何检查 Access 中是否存在表有什么建议吗?

【问题讨论】:

  • 您可能要考虑使用一个表,然后使用参数化查询来生成您的“每日”视图。这会给你更大的灵活性。例如,如果您想按周查看结果怎么办?使用查询,它是参数的简单日期更改。如果您有七个表,则必须物理地创建一个包含特定表的联合查询。

标签: sql ms-access ms-access-2007


【解决方案1】:

您可以使用隐藏系统表 MSysObjects 来检查表是否存在:

If Not IsNull(DlookUp("Name","MSysObjects","Name='TableName'")) Then
    'Table Exists

但是,我同意每天创建一个新表是一个非常糟糕的主意。

编辑:我应该补充一点,表的类型为 1、4 或 6,并且不同类型的其他对象可能与表具有相同的名称,所以最好说:

If Not IsNull(DlookUp("Name","MSysObjects","Name='TableName' And Type In (1,4,6)")) Then
    'Table Exists

但是,无法创建与查询同名的表,因此如果需要查找来测试名称,最好在类型列表中添加 5,即查询.

【讨论】:

  • 我对答案进行了一些扩展。
  • 谢谢。如果有一个sql查询会更容易,但我认为没有这样的事情:)(
  • 有:SELECT [Name] FROM MSysObjects WHERE [Name]='TableName' 并输入 (1,4,6)
【解决方案2】:

这是另一种解决方案,比遍历所有表要快一些。

Public Function doesTableExist(strTableName As String) As Boolean
    Dim db As DAO.Database
    Dim td As DAO.TableDef
    Set db = CurrentDb
    On Error Resume Next
    Set td = db.TableDefs(strTableName)
    doesTableExist = (Err.Number = 0)
    Err.Clear
End Function

【讨论】:

  • 抱歉,这是 0 的赋值吗? doesTableExist = (Err.Number = 0)我有点困惑这条线是什么意思
  • Err.Number = 0 是一个比较。它产生一个布尔值,然后将其分配给dosTableExist。
【解决方案3】:

几年前,我测试了各种方法来确定表是否存在。以下是我实现时的所有代码,包括我的简单测试例程。

Public Function TableExists(strTableName As String, Optional ysnRefresh As Boolean, Optional db As DAO.Database) As Boolean
' Originally Based on Tony Toews function in TempTables.MDB, http://www.granite.ab.ca/access/temptables.htm
' Based on testing, when passed an existing database variable, this is the fastest
On Error GoTo errHandler
  Dim tdf As DAO.TableDef

  If db Is Nothing Then Set db = CurrentDb()
  If ysnRefresh Then db.TableDefs.Refresh
  Set tdf = db(strTableName)
  TableExists = True

exitRoutine:
  Set tdf = Nothing
  Exit Function

errHandler:
  Select Case Err.Number
    Case 3265
      TableExists = False
    Case Else
      MsgBox Err.Number & ": " & Err.Description, vbCritical, "Error in mdlBackup.TableExists()"
  End Select
  Resume exitRoutine
End Function

Public Function TableExists2(strTableName As String, Optional ysnRefresh As Boolean, Optional db As DAO.Database) As Boolean
On Error GoTo errHandler
  Dim bolCleanupDB As Boolean
  Dim tdf As DAO.TableDef

  If db Is Nothing Then
     Set db = CurrentDb()
     bolCleanupDB = True
  End If
  If ysnRefresh Then db.TableDefs.Refresh
  For Each tdf In db.TableDefs
    If tdf.name = strTableName Then
       TableExists2 = True
       Exit For
    End If
  Next tdf

exitRoutine:
  Set tdf = Nothing
  If bolCleanupDB Then
     Set db = Nothing
  End If
  Exit Function

errHandler:
  MsgBox Err.Number & ": " & Err.Description, vbCritical, "Error in mdlBackup.TableExists1()"
  Resume exitRoutine
End Function

Public Function TableExists3(strTableName As String, _
     Optional db As DAO.Database) As Boolean
' Based on testing, when NOT passed an existing database variable, this is the fastest
On Error GoTo errHandler
  Dim strSQL As String
  Dim rs As DAO.Recordset

  If db Is Nothing Then Set db = CurrentDb()
  strSQL = "SELECT MSysObjects.Name FROM MSysObjects "
  strSQL = strSQL & "WHERE MSysObjects.Name=" & Chr(34) & strTableName & Chr(34)
  strSQL = strSQL & " AND MSysObjects.Type=6;"
  Set rs = db.OpenRecordset(strSQL)
  TableExists3 = (rs.RecordCount <> 0)

exitRoutine:
  If Not (rs Is Nothing) Then
     rs.Close
     Set rs = Nothing
  End If
  Exit Function

errHandler:
  MsgBox Err.Number & ": " & Err.Description, vbCritical, _
     "Error in TableExists1()"
  Resume exitRoutine
End Function

Public Sub TestTableExists(strTableName As String, intLoopCount As Integer)
  Dim dteStart As Date
  Dim i As Integer
  Dim bolResults As Boolean

  dteStart = Now()
  For i = 0 To intLoopCount
    bolResults = TableExists(strTableName, , CurrentDB())
  Next i
  Debug.Print "TableExists (" & intLoopCount & "): " & Format(Now() - dteStart, "nn:ss")

  dteStart = Now()
  For i = 0 To intLoopCount
    bolResults = TableExists2(strTableName, , CurrentDB())
  Next i
  Debug.Print "TableExists2 (" & intLoopCount & "): " & Format(Now() - dteStart, "nn:ss")

  dteStart = Now()
  For i = 0 To intLoopCount
    bolResults = TableExists3(strTableName, CurrentDB())
  Next i
  Debug.Print "TableExists3 (" & intLoopCount & "): " & Format(Now() - dteStart, "nn:ss")
End Sub

【讨论】:

  • TableExists & TableExists2 处理(mysql odbc)链接表;但是 TableExists3 没有。
【解决方案4】:

我发现查询系统表或 tabledef 不可靠,并且在经常创建和删除表的脚本中引入了不可预测的行为。

根据我的结果,我的假设是这些表不一定在执行 CREATEDROP 的确切时刻更新,或者并发问题使我无法获得准确的结果。

我发现以下方法更可靠:

Public Function TableExists(theDatabase As Access.Application, _
    tableName As String) As Boolean

    ' Presume that table does not exist.
    TableExists = False

    ' Define iterator to query the object model.
    Dim iTable As Integer

    ' Loop through object catalogue and compare with search term.
    For iTable = 0 To theDatabase.CurrentData.AllTables.Count - 1
        If theDatabase.CurrentData.AllTables(iTable).Name = tableName Then
            TableExists = True
            Exit Function
        End If
    Next iTable

End Function

除非存在数量惊人的表集合,否则应该不会出现运行时问题迭代。

【讨论】:

    【解决方案5】:

    这个问题很老了,但我发现没有一个答案是令人满意的,因为:

    • 它们不处理“坏”链接表的情况,其中链接表指向不存在的数据库或表。
    • 由于链接表可能很大,我们必须能够通过快速查询来检查它们。

    所以这是我的简单但更完整的解决方案:

    Function isTableOk(tblName As String) As Boolean
    'works with local or linked tables
        Dim db As DAO.Database, rs As DAO.Recordset
        Dim sSql As String
        sSql = "SELECT TOP 1 ""xxx"" AS Expr1 FROM [" & tblName & "]"
    
        On Error Resume Next
        Err.Clear
        Set db = CurrentDb
        Set rs = db.OpenRecordset(sSql)
        isTableOk = (Err.Number = 0)
        rs.Close
    End Function
    

    您甚至可以使用此版本检查 外部 Access db 中的表:

    Function isTableOk(tblName As String, Optional dbName As String) As Boolean
    'works with local or linked tables, or even tables in external db (if dbName is provided)
    
        Dim db As DAO.Database, rs As DAO.Recordset
        Dim sSql As String
    
        Set db = CurrentDb
        sSql = "SELECT TOP 1 'xxx' AS Expr1 FROM [" & tblName & "]"
        If Len(dbName) > 0 Then 'external db 
            sSql = sSql & " IN '" & dbName & "'"
        End If
        Err.Clear
        On Error Resume Next
        Set rs = db.OpenRecordset(sSql)
        isTableOk = (Err.Number = 0)
        rs.Close
    End Function
    

    【讨论】:

    • 抱歉,isTableOk = (Err.Number = 0) 这行是什么意思?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-02
    • 2013-05-30
    相关资源
    最近更新 更多