Проверьте, существует ли таблица доступа - PullRequest
16 голосов
/ 06 июня 2010

Я хочу регистрировать данные посещений веб-сайта по IP-адресу, дате и времени, клиенту и рефереру для доступа к базе данных, но я планирую регистрировать данные журнала каждый день в отдельных таблицах, например, журналы за 06.06.2010 будут регистрироваться в 2010_06_06 именованной таблице , Когда дата изменится, я создам таблицу с именем 2010_06_07. Но проблема в том, что эта таблица уже создана.

Любые предложения, как проверить, существует ли таблица в Access?

Ответы [ 5 ]

36 голосов
/ 07 июня 2010

Вы можете использовать скрытую системную таблицу 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, то есть запрос, в список типов. .

7 голосов
/ 08 июня 2010

Я проверил различные методы, чтобы выяснить, существует ли таблица несколько лет назад. Вот код для всех них, которые я реализовал, включая мою простую процедуру тестирования.

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
6 голосов
/ 07 июня 2010

Вот еще одно решение, оно будет немного быстрее, чем зацикливание всех таблиц.

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
2 голосов
/ 18 июня 2015

Я обнаружил, что запросы к системным таблицам или определениям таблиц ненадежны и привносят непредсказуемое поведение в сценарии, где таблицы регулярно создаются и удаляются.

Исходя из моих результатов, я предполагаю, что эти таблицы не обязательно обновляютсяв тот момент, когда выполняется CREATE или DROP, или из-за проблем параллелизма я не могу получить точный результат.

Я считаю следующий метод более надежным:

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

Не должно быть итерации во время выполнения, если только не существует потрясающе огромного набора таблиц.

1 голос
/ 19 июня 2019

Этот вопрос довольно старый, но я обнаружил, что ни один ответ не удовлетворяет, потому что:

  • они не обрабатывают случай «плохих» связанных таблиц, когда связанная таблица указывает на несуществующую базу данных или таблицу.
  • , поскольку связанные таблицы потенциально огромны, мы должны иметь возможность проверить их с помощью быстрого запроса.

Итак, вот мое простое, но более полное решение:

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

Вы даже можете проверить таблицу в external 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
...