Sql 检查访问表是否存在

Sql 检查访问表是否存在,sql,ms-access,ms-access-2007,Sql,Ms Access,Ms Access 2007,我想记录网站访问的IP、datetime、客户端和引用方数据以访问数据库,但我计划每天在单独的表中记录日志数据,例如,2010年6月6日的日志将记录在2010年6月6日命名的表中。更改日期后,我将创建一个名为2010_06_07的表。但问题是这个表是否已经创建 有没有关于如何检查Access中是否存在表的建议?这里有另一个解决方案,它比在所有表上循环要快一点 Public Function doesTableExist(strTableName As String) As Boolean

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


有没有关于如何检查Access中是否存在表的建议?

这里有另一个解决方案,它比在所有表上循环要快一点

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

您可以使用隐藏的系统表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个,即查询。

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

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
Public Function TableExists(strTableName为字符串,可选ysnRefresh为布尔值,可选db为DAO.Database)为布尔值
'最初基于Telletables.MDB中的Tony Toews函数,http://www.granite.ab.ca/access/temptables.htm
'根据测试,当传递现有数据库变量时,这是最快的
关于错误转到错误处理程序
将tdf调暗为DAO.TableDef
如果db为空,则设置db=CurrentDb()
如果为ysnRefresh,则为db.TableDefs.Refresh
设置tdf=db(strTableName)
TableExists=True
现存的:
设置tdf=无
退出功能
错误处理程序:
选择案例错误编号
案例3265
TableExists=False
其他情况
MsgBox Err.Number&“:”&Err.Description,vbCritical,“mdlBackup.TableExists()中的错误”
结束选择
恢复原状
端函数
公共函数TableExists2(strTableName为字符串,可选ysnRefresh为布尔值,可选db为DAO.Database)为布尔值
关于错误转到错误处理程序
将bolCleanupDB设置为布尔值
将tdf调暗为DAO.TableDef
如果db什么都不是,那么
Set db=CurrentDb()
bolCleanupDB=True
如果结束
如果为ysnRefresh,则为db.TableDefs.Refresh
对于以db.TableDefs为单位的每个tdf
如果tdf.name=strTableName,则
TableExists2=True
退出
如果结束
下一个tdf
现存的:
设置tdf=无
如果是bolCleanupDB,那么
Set db=Nothing
如果结束
退出功能
错误处理程序:
MsgBox错误号&“:”错误描述,vbCritical,“mdlBackup.TableExists1()中的错误”
恢复原状
端函数
公共函数TableExists3(strTableName作为字符串_
可选数据库(作为DAO.Database)作为布尔值
'根据测试,当未传递现有数据库变量时,这是最快的
关于错误转到错误处理程序
作为字符串的Dim strSQL
Dim rs作为DAO.Recordset
如果db为空,则设置db=CurrentDb()
strSQL=“从MSysObjects中选择MSysObjects.Name”
strSQL=strSQL&“其中MSysObjects.Name=“&Chr(34)&strTableName&Chr(34)
strSQL=strSQL&“和MSysObjects.Type=6;”
Set rs=db.OpenRecordset(strSQL)
TableExists3=(rs.RecordCount 0)
现存的:
如果不是(rs什么都不是),那么
rs.Close
设置rs=无
如果结束
退出功能
错误处理程序:
MsgBox错误编号&“:”&错误说明,vbCritical_
“TableExists1()中出现错误”
恢复原状
端函数
公共子TestTableExists(strTableName为字符串,intLoopCount为整数)
Dim dteStart As Date
作为整数的Dim i
将结果设置为布尔值
dteStart=Now()
对于i=0到intLoopCount
bolResults=TableExists(strTableName,CurrentDB())
接下来我
Debug.Print“TableExists(&intLoopCount&)”:&Format(现在()-dteStart,“nn:ss”)
dteStart=Now()
对于i=0到intLoopCount
bolResults=TableExists2(strTableName,CurrentDB())
接下来我
Debug.Print“TableExists2(&intLoopCount&)”:&Format(Now()-dteStart,“nn:ss”)
dteStart=Now()
对于i=0到intLoopCount
bolResults=TableExists3(strTableName,CurrentDB())
接下来我
Debug.Print“TableExists3(&intLoopCount&)”:&Format(Now()-dteStart,“nn:ss”)
端接头

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

根据我的结果,我的假设是,这些表不一定在执行
CREATE
DROP
时更新,或者并发性问题阻碍了我获得准确的结果

我发现以下方法更可靠:

公共函数表存在(数据库为Access.Application_
tableName(作为字符串)作为布尔值
'假定该表不存在。
TableExists=False
'定义迭代器以查询对象模型。
可调为整数
'循环浏览对象目录并与搜索词进行比较。
对于iTable=0,请访问database.CurrentData.AllTables.Count-1
如果database.CurrentData.AllTables(iTable).Name=tableName,则
TableExists=True
退出功能
如果结束
下一个
端函数

除非有惊人数量的表集合,否则迭代应该没有运行时问题。

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

  • 它们不处理“坏”链接表的情况,即链接表指向不存在的db或表
  • 由于链接表可能很大,我们必须能够用快速查询来检查它们
下面是我的简单但更完整的解决方案:

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
您甚至可以使用以下版本在外部访问数据库中检查表:

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

您可能需要考虑使用一个表,然后使用参数化查询生成