Как получить идентификатор вновь вставленной записи с помощью Excel VBA?
кажется достаточно распространенной проблемой, но большинство решений относятся к объединению нескольких команд SQL, что, по моему мнению, не может быть сделано с ADO/VBA (я буду рад быть показан неправильно в этом отношении, однако).
в настоящее время я вставляю свою новую запись, а затем запускаю запрос select, используя (Я надеюсь) достаточно полей, чтобы гарантировать, что только недавно вставленная запись может быть возвращена. Мои базы данных редко доступны более чем одному человеку за раз (незначительный риск другой вставки происходит между запросами) и из-за структуры таблиц идентификация новой записи обычно довольно проста.
теперь я пытаюсь обновить таблицу, которая не имеет много сфер, где уникальность, кроме искусственного первичного ключа. Это означает, что есть риск, что новая запись может быть не уникальной, и я ненавижу добавлять поле только для того, чтобы заставить уникальность.
каков наилучший способ вставить запись в таблицу доступа, а затем запросить новый первичный ключ из Excel в такой ситуации?
Спасибо за ответы. Я пытался получить @@IDENTITY
работает, но это всегда возвращает 0, используя код ниже.
Private Sub getIdentityTest()
Dim myRecordset As New ADODB.Recordset
Dim SQL As String, SQL2 As String
SQL = "INSERT INTO tblTasks (discipline,task,owner,unit,minutes) VALUES (""testDisc3-3"",""testTask"",""testOwner"",""testUnit"",1);"
SQL2 = "SELECT @@identity AS NewID FROM tblTasks;"
If databaseConnection Is Nothing Then
createDBConnection
End If
With databaseConnection
.Open dbConnectionString
.Execute (SQL)
.Close
End With
myRecordset.Open SQL2, dbConnectionString, adOpenStatic, adLockReadOnly
Debug.Print myRecordset.Fields("NewID")
myRecordset.Close
Set myRecordset = Nothing
End Sub
что-нибудь отвечает?
однако, учитывая предостережения, любезно предоставленные Рено (ниже), кажется, почти столько же риска с использованием @@IDENTITY
как и любой другой метод, поэтому я прибегла к помощи SELECT MAX
сейчас. Для дальнейшего использования, хотя мне было бы интересно узнать, что не так с моим попытка выше.
6 ответов
о вашем вопросе:
теперь я пытаюсь обновить таблицу не имеет особого смысла своеобразие, другие, чем в искусственный первичный ключ. Это средство есть риск, что новый рекорд может быть, не уникальна, и я ненавижу добавьте поле, чтобы заставить уникальность.
если вы are использование автоинкремента для вашего первичного ключа, тогда у вас есть уникальность, и вы можете использовать SELECT @@Identity;
получить значение последнего идентификатора автоматически (см. предупреждения ниже).
если вы не С помощью autoincrement, и вы вставляете записи из Access, но вы хотите получить последний из Excel:
-
убедитесь, что ваш первичный ключ сортируется, поэтому вы можете получить последний, используя такой запрос:
SELECT MAX(MyPrimaryField) FROM MyTable; SELECT TOP 1 MyPrimaryField FROM MyTable ORDER BY MyPrimaryField DESC;
-
или, если сортировка вашего основного поля не даст вам последнего, вы необходимо добавить поле DateTime (скажем
InsertedDate
) и сохранить текущую дату и время каждый раз, когда вы создаете новую запись в этой таблице, чтобы вы могли получить последний, как это:SELECT TOP 1 MyPrimaryField FROM MyTable ORDER BY InsertedDate DESC;
в любом из этих случаев, я думаю, вы найдете добавление первичного ключа AutoIncrement как гораздо проще иметь дело с:
это не будет стоить вам много
это будет гарантировать вам уникальность вашей записи не задумываясь об этом
это облегчит вам выбор самой последней записи, либо с помощью
@@Identity
или через сортировку по первичному ключу или получениеMax()
.
Из Excel
чтобы получить данные в Excel, у вас есть несколько вариантов:
создайте ссылку данных с помощью запроса, чтобы вы могли использовать результат непосредственно в ячейке или диапазон.
-
запрос от VBA:
Sub GetLastPrimaryKey(PrimaryField as string, Table as string) as variant Dim con As String Dim rs As ADODB.Recordset Dim sql As String con = "Provider=Microsoft.ACE.OLEDB.12.0;" & _ "Data Source= ; C:\myDatabase.accdb" sql = "SELECT MAX([" & PrimaryField & "]) FROM [" & MyTable & "];" Set rs = New ADODB.Recordset rs.Open sql, con, adOpenStatic, adLockReadOnly GetLastPrimaryKey = rs.Fields(0).Value rs.Close Set rs = Nothing End Sub
примечание о @@Identity
вы должны быть осторожнее с оговорками при использовании @@Identity
в стандартных базах данных Access (*):
он работает только с полями идентификации AutoIncrement.
он доступен только при использовании ADO и run
SELECT @@IDENTITY;
он возвращает последний используемый счетчик,но это все таблицы. Вы не можете использовать его для возврата счетчика для определенной таблицы в MS Access (насколько я знаю, если вы укажете таблицу с помощью
FROM mytable
, оно просто игнорируется).
Короче говоря, возвращаемое значение может быть совсем не тем, которое вы ожидаете.вы должны запросить его сразу после
INSERT
чтобы свести к минимуму риск получения неправильного ответа.
Это означает, что если вы вставляете ваши данные в одно время и должны получить последний идентификатор в другое время (или в другом месте), это не сработает.и последнее, но не менее важное: переменная устанавливается только тогда, когда записи вставляются через программный код.
Это означает, что запись была добавлена через пользовательский интерфейс,@@IDENTITY
не будет.
(*): просто для ясности, @@IDENTITY
ведет себя по-другому и более предсказуемо, если вы используете режим ANSI-92 SQL для своего база данных.
Проблема в том, что ANSI 92 имеет немного другой синтаксис, чем
ароматизатор ANSI 89 поддерживается Access и предназначен для повышения совместимости с SQL Server при использовании Access в качестве интерфейса.
если искусственный ключ является автономером, вы можете использовать @@identity.
обратите внимание, что в обоих этих примерах транзакция изолирована от других событий, поэтому возвращаемый идентификатор является только что вставленным. Вы можете проверить это, приостановив код в Debug.Печать db.RecordsAffected или Debug.Распечатайте lngRecs и вставьте запись вручную в Table1, продолжите код и обратите внимание, что возвращается идентификатор не записи, вставленной вручную, а предыдущей записи вставляется кодом.
DAO пример
'Reference: Microsoft DAO 3.6 Object Library '
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb
db.Execute ("INSERT INTO table1 (field1, Crdate ) " _
& "VALUES ( 46, #" & Format(Date, "yyyy/mm/dd") & "#)")
Debug.Print db.RecordsAffected
Set rs = db.OpenRecordset("SELECT @@identity AS NewID FROM table1")
Debug.Print rs.Fields("NewID")
пример ADO
Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Set cn = CurrentProject.Connection
cn.Execute ("INSERT INTO table1 (field1, Crdate ) " _
& "VALUES ( 46, #" & Format(Date, "yyyy/mm/dd") & "#)"), lngRecs
Debug.Print lngRecs
rs.Open "SELECT @@identity AS NewID FROM table1", cn
Debug.Print rs.Fields("NewID")
Re: " Я попытался заставить @ @ IDENTITY работать, но это всегда возвращает 0, используя приведенный ниже код."
ваш код отправляет SQL
и SQL2
через различные объекты подключения. Я не думаю @@identity
вернет все, кроме нуля, если вы не спросите из того же соединения, где вы выполнили свой INSERT
заявление.
попробуйте изменить это:
myRecordset.Open SQL2, dbConnectionString, adOpenStatic, adLockReadOnly
в:
myRecordset.Open SQL2, databaseConnection, adOpenStatic, adLockReadOnly
вот мое решение, которое не использует @@index или MAX.
Const connectionString = "Provider=SQLOLEDB; Data Source=SomeSource; Initial Catalog=SomeDB; User Id=YouIDHere; Password=YourPassword"
Const RecordsSQL = "SELECT * FROM ThatOneTable"
Private Sub InsertRecordAndGetID()
Set connection = New ADODB.connection
connection.connectionString = connectionString
connection.Open
Set recordset = New ADODB.recordset
recordset.Open SQL, connection, adOpenKeyset, adLockOptimistic
With recordset
.AddNew
!Field1 = Value1
!Field2 = Value2
End With
recordset.MoveLast
ID = recordset.Fields("id")
End Sub
наслаждайтесь!
попробовать следующий код.Добавить кнопку на лист из блока управления и вставьте следующий код в окно кода
Private Sub CommandButton1_Click()
MsgBox GetLastPrimaryKey
End Sub
Private Function GetLastPrimaryKey() As String
Dim con As String
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim sql As String
con = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\myaccess.mdb;Persist Security Info=False"
sql = "SELECT MAX(id) FROM tblMyTable"
Set cn = New ADODB.Connection
Set rs = New ADODB.Recordset
cn.Open con
rs.Open sql, cn, 3, 3, 1
If rs.RecordCount <> 0 Then
GetLastPrimaryKey = rs.Fields(0).Value
End If
rs.Close
cn.Close
Set rs = Nothing
Set cn = Nothing
End Function
8 лет опоздал на вечеринку... Проблемы заключается в том, что вы используете dbConnectionString для создания новая подключение. @@identity зависит от используемого соединения.
во-первых, не закрывайте исходное соединение
'.Close
заменить
myRecordset.Open SQL2, dbConnectionString, adOpenStatic, adLockReadOnly
подключение вы ранее использовали для вставки
myRecordset.Open SQL2, databaseConnection, adOpenStatic, adLockReadOnly
и Вы были бы все готово. Фактически, вам даже не нужно указывать таблицу:
SQL2 = "SELECT @@identity AS NewID"