Содержание
- 1 A Recordset That Does Not Support the RecordCount Property
- 2 A Recordset That Supports the RecordCount Property
- 3 Assigning Recordsets Dynamically to a form
- 4 Build a string text from result set
- 5 Creating a Custom Recordset
- 6 Creating a Disconnected Recordset
- 7 Dynamic Recordset
- 8 Filling a Combo Box with a Disconnected Recordset
- 9 Looping Through a Recordset
- 10 Move cursor in result set
- 11 Refreshing Recordset Data
- 12 Retrieve data from Recordset by table column name
- 13 Row order in Dynamic Recordset
- 14 Set Index and seek the recordset
- 15 Set recordset to form
- 16 Snapshot Recordset
- 17 The Sort Property of the Recordset Object
- 18 The Supports Method of the Recordset Object
- 19 Using the AbsolutePosition Property
- 20 Using the Bookmark Property
- 21 Using the EOF Property to Determine the Bounds of a Recordset
- 22 Whether Records Are Returned in a Recordset
A Recordset That Does Not Support the RecordCount Property
<source lang="vb">
Sub CountRecordsBad()
Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.ActiveConnection = CurrentProject.Connection rst.Open "Select * from Employees" Debug.Print rst.RecordCount "Prints -1 rst.Close Set rst = Nothing
End Sub
</source>
A Recordset That Supports the RecordCount Property
<source lang="vb">
Sub CountRecordsGood()
Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.ActiveConnection = CurrentProject.Connection rst.CursorType = adOpenStatic rst.Open "Select * from Employees" Debug.Print rst.RecordCount "Prints Record count rst.Close Set rst = Nothing
End Sub
</source>
Assigning Recordsets Dynamically to a form
<source lang="vb">
Sub runFormNY()
Dim con As ADODB.Connection
Dim myRecordset As Recordset
Dim strFrmNm As String
Set myRecordset = New ADODB.Recordset
myRecordset.CursorType = adOpenKeyset
myRecordset.LockType = adLockOptimistic
Set con = New ADODB.Connection
con.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:mydb.mdb;"
myRecordset.Open "SELECT * FROM Employees", con
strFrmNm = "frmCustomer"
DoCmd.OpenForm strFrmNm
Set Application.Forms(strFrmNm).Recordset = myRecordset
myRecordset.Close
con.Close
Set myRecordset = Nothing
Set con = Nothing
End Sub
</source>
Build a string text from result set
<source lang="vb">
Sub MyFirstConnection4()
Dim myConnection As ADODB.Connection
Dim myRecordset As ADODB.Recordset
Dim strSQL As String
Dim strOutput As String
strSQL = "SELECT FirstName, LastName FROM Employees"
Set myConnection = CurrentProject.Connection
Set myRecordset = New ADODB.Recordset
myRecordset.Open strSQL, myConnection
Do Until myRecordset.EOF
strOutput = strOutput + myRecordset.Fields("FirstName") & " " & _
myRecordset.Fields("LastName") & vbCrLf
myRecordset.MoveNext
Loop
myRecordset.Close
msgBox strOutput
myConnection.Close
Set myConnection = Nothing
Set myRecordset = Nothing
End Sub
</source>
Creating a Custom Recordset
<source lang="vb">
Sub Custom_Recordset()
Dim myRecordset As ADODB.Recordset
Dim strFile As String
Dim strFolder As String
strFolder = "C:"
strFile = Dir(strPath & "*.*")
Set myRecordset = New ADODB.Recordset
With myRecordset
Set .ActiveConnection = Nothing
.CursorLocation = adUseClient
With .Fields
.Append "Name", adVarChar, 255
.Append "Size", adDouble
.Append "Modified", adDBTimeStamp
End With
.Open
" Add a new record to the recordset
.AddNew Array("Name", "Size", "Modified"), _
Array("fileName.txt", 100, #9/9/1999#)
.MoveFirst
" Print the contents of the recordset to the Immediate window
Do Until .EOF
Debug.Print !Name & vbTab & !Size & vbTab & !Modified
.MoveNext
Loop
.Close
End With
Set myRecordset = Nothing
End Sub
</source>
Creating a Disconnected Recordset
<source lang="vb">
Sub Rst_Disconnected()
Dim conn As ADODB.Connection
Dim myRecordset As ADODB.Recordset
Dim strConn As String
Dim strSQL As String
Dim strRst As String
strSQL = "Select * From Orders where CustomerID = "VINET""
strConn = "Provider=Microsoft.Jet.OLEDB.4.0;"
strConn = strConn & "Data Source = " & CurrentProject.Path & "mydb.mdb"
Set conn = New ADODB.Connection
conn.ConnectionString = strConn
conn.Open
Set myRecordset = New ADODB.Recordset
Set myRecordset.ActiveConnection = conn
" retrieve the data
myRecordset.CursorLocation = adUseClient
myRecordset.LockType = adLockBatchOptimistic
myRecordset.CursorType = adOpenStatic
myRecordset.Open strSQL, , , , adCmdText
Set myRecordset.ActiveConnection = Nothing
myRecordset.MoveFirst
Debug.Print myRecordset.Fields(0) & " was " & myRecordset.Fields(1) & " before."
myRecordset.Fields("CustomerID").Value = "OCEAN"
myRecordset.Update
strRst = myRecordset.GetString(adClipString, , ",")
Debug.Print strRst
End Sub
</source>
Dynamic Recordset
<source lang="vb">
Sub exaRecordsetPosition()
Dim db As Database
Dim rsDyna As Recordset
Set db = CurrentDb
Set rsDyna = db.OpenRecordset("Books", dbOpenDynaset)
rsDyna.MoveFirst
Do While Not rsDyna.EOF
Debug.Print rsDyna!PubID & " / " & rsDyna!Title
Debug.Print rsDyna.AbsolutePosition
Debug.Print Format$(rsDyna.PercentPosition
rsDyna.MoveNext
Loop
rsDyna.Close
End Sub
</source>
Filling a Combo Box with a Disconnected Recordset
<source lang="vb">
Private Sub Form_Load()
Dim myRecordset As ADODB.Recordset
Dim strRowSource As String
Dim strName As String
strName = CurrentProject.Path & "Companies.rst"
Set myRecordset = New ADODB.Recordset
With myRecordset
.CursorLocation = adUseClient
.Open strName, , , , adCmdFile
Do Until .EOF
strRowSource = strRowSource & myRecordset!CompanyName & ";"
.MoveNext
Loop
With Me.cboCompany
.RowSourceType = "Value List"
.RowSource = strRowSource
End With
.Close
End With
Set myRecordset = Nothing
End Sub
</source>
Looping Through a Recordset
<source lang="vb">
Sub LoopThroughRecordset(rst As ADODB.Recordset, rg As Range)
Dim nColumnOffset As Integer
Dim fld As ADODB.Field
With rst
Do Until .EOF
nColumnOffset = 0
For Each fld In .Fields
rg.Offset(0, nColumnOffset).Value = fld.Value
nColumnOffset = nColumnOffset + 1
Next
Set rg = rg.Offset(1, 0)
.MoveNext
Loop
End With
Set fld = Nothing
End Sub
</source>
Move cursor in result set
<source lang="vb">
Sub MyFirstConnection3()
Dim myConnection As ADODB.Connection
Dim myRecordset As ADODB.Recordset
Dim strSQL As String
strSQL = "SELECT FirstName, LastName FROM Employees"
Set myConnection = CurrentProject.Connection
Set myRecordset = New ADODB.Recordset
myRecordset.Open strSQL, myConnection
Do Until myRecordset.EOF
Debug.Print myRecordset.Fields("FirstName") & " " & _
myRecordset.Fields("LastName")
myRecordset.MoveNext
Loop
myRecordset.Close
myConnection.Close
Set myConnection = Nothing
Set myRecordset = Nothing
End Sub
</source>
Refreshing Recordset Data
<source lang="vb">
Sub PersistRecordset()
Dim strFileName As String strFileName = "c:test.txt" Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.ActiveConnection = CurrentProject.Connection rst.CursorType = adOpenStatic rst.LockType = adLockOptimistic rst.Open Source:="Select * from Employees ", Options:=adCmdText On Error Resume Next Kill strFileName "Save the recordset rst.Save strFileName, adPersistADTG rst.Close Set rst = Nothing
End Sub
</source>
Retrieve data from Recordset by table column name
<source lang="vb">
Sub MyFirstConnection()
Dim myConnection As ADODB.Connection
Dim myRecordset As ADODB.Recordset
Set myConnection = CurrentProject.Connection
Set myRecordset = New ADODB.Recordset
myRecordset.Open "select * from employees", myConnection
Do Until myRecordset.EOF
Debug.Print myRecordset.Fields("FirstName"), _
myRecordset.Fields("LastName")
myRecordset.MoveNext
Loop
myRecordset.Close
myConnection.Close
Set myConnection = Nothing
Set myRecordset = Nothing
End Sub
</source>
Row order in Dynamic Recordset
<source lang="vb">
Sub exaRecordsetMove()
Dim db As Database
Dim rsTable As Recordset
Dim rsDyna As Recordset
Set db = CurrentDb
Set rsTable = db.OpenRecordset("Books")
Debug.Print "Books indexed by PubID/Title:"
rsTable.Index = "PubTitle"
rsTable.MoveFirst
Do While Not rsTable.EOF
Debug.Print rsTable!PubID & " / " & rsTable!Title
rsTable.MoveNext
Loop
Debug.Print "Dynaset-type recordset order:"
Set rsDyna = db.OpenRecordset("Books", dbOpenDynaset)
rsDyna.MoveFirst
Do While Not rsDyna.EOF
Debug.Print rsDyna!PubID & " / " & rsDyna!Title
rsDyna.MoveNext
Loop
rsTable.Close
rsDyna.Close
End Sub
</source>
Set Index and seek the recordset
<source lang="vb">
Sub exaRecordsetSeek()
Dim db As Database
Dim rsTable As Recordset
Set db = CurrentDb
Set rsTable = db.OpenRecordset("Books")
rsTable.Index = "Title"
rsTable.Seek ">=", "On"
If Not rsTable.NoMatch Then
Debug.Print rsTable!Title
Else
Debug.Print "No title beginning with word "On"."
End If
rsTable.Close
End Sub
</source>
Set recordset to form
<source lang="vb">
Private Sub Form_Open(Cancel As Integer)
Dim con As ADODB.Connection
Dim myRecordset As ADODB.Recordset
Dim strFrmNm As String
Set myRecordset = New ADODB.Recordset
myRecordset.CursorType = adOpenKeyset
myRecordset.LockType = adLockOptimistic
Set con = New ADODB.Connection
con.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=C:store.mdb;"
myRecordset.Open "SELECT * FROM tblCustomer", con
Set Me.Recordset = myRecordset
myRecordset.Close
con.Close
Set myRecordset = Nothing
Set con = Nothing
End Sub
</source>
Snapshot Recordset
<source lang="vb">
Sub exaRecordsets()
Dim db As Database
Dim rsTable As Recordset
Dim rsDyna As Recordset
Dim rsSnap As Recordset
Set db = CurrentDb
Set rsTable = db.OpenRecordset("Employees")
Debug.Print "TableCount: " & rsTable.RecordCount
Set rsDyna = db.OpenRecordset("Employees", dbOpenDynaset)
Debug.Print "DynaCount: " & rsDyna.RecordCount
rsDyna.MoveLast
Debug.Print "DynaCount: " & rsDyna.RecordCount
Set rsSnap = db.OpenRecordset("Employees", dbOpenSnapshot)
Debug.Print "SnapCount: " & rsSnap.RecordCount
rsSnap.MoveLast
Debug.Print "SnapCount: " & rsSnap.RecordCount
rsTable.Close
rsDyna.Close
rsSnap.Close
End Sub
</source>
The Sort Property of the Recordset Object
<source lang="vb">
Sub SortRecordset()
Dim intCounter As Integer
Dim rst As ADODB.Recordset
Set rst = New ADODB.Recordset
rst.ActiveConnection = CurrentProject.Connection
rst.CursorLocation = adUseClient
rst.Open "Select * from Employees"
Debug.Print "NOT Sorted!!!"
Do Until rst.EOF
Debug.Print rst("EmployeeID")
rst.MoveNext
Loop
Debug.Print "Now Sorted!!!"
rst.Sort = "[EmployeeID]"
Do Until rst.EOF
Debug.Print rst("EmployeeID")
rst.MoveNext
Loop
rst.Close
Set rst = Nothing
End Sub
</source>
The Supports Method of the Recordset Object
<source lang="vb">
Sub SupportsMethod()
Dim rst As ADODB.Recordset
Set rst = New ADODB.Recordset
rst.ActiveConnection = CurrentProject.Connection
rst.CursorType = adOpenStatic
rst.LockType = adLockOptimistic
rst.CursorLocation = adUseServer
rst.Open Source:="Select * from Employees ", _
Options:=adCmdText
Debug.Print "Bookmark " & rst.Supports(adBookmark)
Debug.Print "Update Batch " & rst.Supports(adUpdateBatch)
Debug.Print "Move Previous " & rst.Supports(adMovePrevious)
Debug.Print "Seek " & rst.Supports(adSeek)
rst.Close
Set rst = Nothing
End Sub
</source>
Using the AbsolutePosition Property
<source lang="vb">
Sub FindPosition()
Dim strSQL As String
Dim rst As ADODB.Recordset
Set rst = New ADODB.Recordset
rst.ActiveConnection = CurrentProject.Connection
rst.CursorType = adOpenStatic
rst.Open "Select * from Products"
strSQL = "[ProductID] = " & 1
rst.Find strSQL
"If record is found, print its position
If rst.EOF Then
msgBox lngValue & " Not Found"
Else
Debug.Print rst.AbsolutePosition
End If
rst.Close
Set rst = Nothing
End Sub
</source>
Using the Bookmark Property
<source lang="vb">
Sub UseBookmark()
Dim strSQL As String
Dim vntPosition As Variant
Dim rst As ADODB.Recordset
Set rst = New ADODB.Recordset
rst.ActiveConnection = CurrentProject.Connection
rst.CursorType = adOpenStatic
rst.Open "Select * from Products"
vntPosition = rst.Bookmark
Do Until rst.EOF
Debug.Print rst("ProductID")
rst.MoveNext
Loop
rst.Bookmark = vntPosition
Debug.Print rst("ProductID")
rst.Close
Set rst = Nothing
End Sub
</source>
Using the EOF Property to Determine the Bounds of a Recordset
<source lang="vb">
Sub DetermineLimits()
Dim rst As ADODB.Recordset
Set rst = New ADODB.Recordset
rst.ActiveConnection = CurrentProject.Connection
rst.CursorType = adOpenStatic
rst.Open "Select * from Employees"
Do Until rst.EOF
Debug.Print rst("EmployeeID")
rst.MoveNext
Loop
rst.Close
End Sub
</source>
Whether Records Are Returned in a Recordset
<source lang="vb">
Sub CheckARecordset()
Dim rst As ADODB.Recordset
Set rst = New ADODB.Recordset
rst.ActiveConnection = CurrentProject.Connection
rst.CursorType = adOpenStatic
rst.Open "Select * from Employees"
If Not rst.RecordCount Then
msgBox "Recordset Empty...Unable to Proceed"
End If
rst.Close
Set rst = Nothing
End Sub
</source>
Замечания
Объект Recordset представляет набор записей в основной таблице или набор записей, который получается в результате выполнения запроса.
Объекты Recordset используются для обработки данных в базе данных на уровне записи. При работе с объектами доступа к данным (DAO) почти все операции выполняются с помощью объектов Recordset. Каждый объект Recordset состоит из записей (строк) и полей (столбцов). Существуют объекты Recordset пяти типов:
- Объект Recordset типа таблицы — программное представление основной таблицы; используется для добавления, изменения или удаления записей из отдельной таблицы базы данных (только в рабочей области Microsoft Jet).
- Объект Recordset типа динамического набора записей — набор обновляемых записей, полученный в результате выполнения запроса. Объект Recordset типа динамического набора записей позволяет добавлять, изменять или удалять записи в основной таблице или таблицах. В объекте Recordset этого типа динамического набора могут содержаться поля из одной или нескольких таблиц базы данных. Этот тип объектов соответствует указателю ключевого набора записей ODBC.
- Объект Recordset типа статического набора записей — статическая копия набора записей, используемая для поиска данных или создания отчетов. Объект Recordset типа статического набора записей может содержать поля из одной или нескольких таблиц базы данных, но не допускает обновления полей. Этот тип объектов соответствует указателю статического набора записей ODBC.
- Объект Recordset типа статического набора записей с последовательным доступом — аналогичен статическому набору записей с тем лишь исключением, что в нем отсутствует указатель. Пользователь имеет возможность прокручивать записи только вперед. Это повышает быстродействие в ситуациях, когда достаточен однократный проход по набору записей. Этот тип объектов соответствует указателю набора записей с последовательным доступом ODBC.
- Объект Recordset динамического типа результирующий набор записей запроса по одной или нескольким основным таблицам, в котором допускается добавление, изменение или удаление записей. В таком объекте Recordset отображаются записи, добавляемые, удаляемые или изменяемые в основных таблицах другими пользователями. Этот тип объектов соответствует динамическому указателю ODBC (только в рабочей области ODBCDirect).
При создании нового объекта Recordset тип объекта определяется с помощью аргумента тип метода OpenRecordset.
В рабочей области Microsoft Jet, если аргумент тип не задан, механизм DAO пытается создать тип объекта Recordset с максимально возможными функциональными характеристиками, начиная с таблицы. Если таблицу создать не удается, делается попытка создать динамический набор записей, затем статический набор записей и наконец, набор записей с последовательным доступом.
В рабочей области ODBCDirect, если аргумент тип не задан, механизм DAO пытается создать тип объекта Recordset, обеспечивающий максимально быстрое выполнение запроса, начиная с набора записей с последовательным доступом. Если объект этого типа создать невозможно, механизм DAO делает попытку создать статический набор записей, затем динамический набор записей, и наконец, объект Recordset динамического типа.
При создании объекта Recordset на основе неприсоединенного объекта TableDef в рабочей области Microsoft Jet создаются объекты Recordset типа таблицы. На основе присоединенных таблиц или таблиц в базах данных ODBC, подключенных к ядру Microsoft Jet, могут быть созданы только объекты Recordset типа динамического набора записей или статического набора записей.
Новый объект Recordset автоматически добавляется в семейство Recordsets при открытии объекта и автоматически удаляется из семейства при закрытии объекта.
При описании в программе объекта Recordset и содержащего его объекта Database с помощью объектных переменных необходимо обеспечить, чтобы эти переменные имели одинаковую область определения или одинаковое время жизни. Например, при описании общей переменной, представляющей объект Recordset, необходимо обеспечить, чтобы переменная, представляющая объект Database, содержащий объект Recordset, также была общей, либо описать эту переменную в процедуре Sub или Function с ключевым словом Static.
В приложении допускается определение произвольного числа объектных переменных, представляющих объект Recordset. Разные объекты Recordset могут иметь доступ к одним таблицам, запросам и полям без возникновения конфликтов.
Объекты Recordset типа динамического набора записей, статического набора записей и статического набора записей с последовательным доступом сохраняются в локальной оперативной памяти. Если в оперативной памяти не хватает места, ядро базы данных Microsoft Jet сохраняет избыточные данные в каталоге временных файлов на диске. Если и этот объем окажется недостаточным, возникает перехватываемая ошибка.
Объекты Recordset по умолчанию помещаются в семейство Fields. Используемым по умолчанию свойством объекта Field является свойство Value (значение). Эти используемые по умолчанию характеристики позволяют упростить программу.
Если созданный объект Recordset содержит записи, то текущей записью становится первая запись. Если записи в объекте отсутствуют, свойство RecordCount получает значение 0, а свойства BOF и EOF значение True.
Изменить положение указателя текущей записи позволяют методы MoveNext, MovePrevious, MoveFirst и MoveLast. Для объектов Recordset типа статического набора записей с последовательным доступом поддерживается только метод MoveNext. При выполнении цикла по всем записям с помощью методов Move («прохода» по объекту Recordset) свойства BOF и EOF используются для проверки начальной и конечной границы объекта Recordset.
Для объектов Recordset типа динамического статического набора записей в рабочей области Microsoft Jet допускается также использование методов группы Find, таких как FindFirst, позволяющих найти запись, удовлетворяющую определенным условиям. Если запись не обнаруживается, свойство NoMatch получает значение True. Для объектов Recordset типа таблицы допускается сканирование записей с помощью метода Seek.
Тип созданного объекта Recordset задается свойством Type, а возможность изменения записей в объекте определяется свойством Updatable.
Сведения о структуре основной таблицы, такие как имя и тип данных каждого поля (объект Field) и индекса (объект Index) сохраняются в объекте TableDef.
При ссылках на объект Recordset используют его порядковый номер в семействе или значение свойства Name (имя):
Recordsets(0)
Recordsets("имя")
Recordsets![имя]
Для одного источника данных или базы данных допускается открытие нескольких объектов Recordset, что приводит к образованию повторяющихся имен в семействе Recordsets. В этом случае необходимо присваивать объекты Recordset объектным переменным и ссылаться на них по именам переменных.
Пример
Следующая программа открывает объект Recordset типа статического набора записей с последовательным доступом, демонстрирует его доступность только для чтения, а затем осуществляет проход по объекту Recordset с помощью метода MoveNext.
Sub dbOpenForwardOnlyX()
Dim dbsNorthwind As Database
Dim rstEmployees As Recordset
Dim fldLoop As Field
Set dbsNorthwind = OpenDatabase("Борей.mdb")
' Открывает набор записей с последовательным доступом.
' Для перемещения по этому объекту Recordset могут
' использоваться только методы MoveNext и Move.
Set rstEmployees = dbsNorthwind.OpenRecordset("Сотрудники", dbOpenForwardOnly)
With rstEmployees
Debug.Print "Набора записей с последовательным доступом: " & .Name & ", Updatable = " & .Updatable
Debug.Print " Field - DataUpdatable"
' Отображает семейство Fields, печатает свойства Name
' и DataUpdatable каждого объекта Field.
For Each fldLoop In .Fields
Debug.Print " " & fldLoop.Name & " - " & fldLoop.DataUpdatable
Next fldLoop
Debug.Print " Данные"
' Печатает данные из набора записей.
Do While Not .EOF
Debug.Print " " & !Имя & " " & !Фамилия
.MoveNext
Loop
.Close
End With
dbsNorthwind.Close
End Sub
Чтобы подключиться к файлу Excel, нам потребовалось: создать именованный диапазон в книге Excel;
создать источник данных ODBC с именем ExcelVolumes;
написать три строки кода, начиная с создания объекта Connection до вызова его метода Open.
9.5.1. Открытие Recordset
Обычно следующий после установки соединения этап — это создание объекта Recordset и работа с ним.
Что такое объект Recordset? Само слово Recordset расшифровывается как Set of Records, т. е. набор записей. Проще всего представить его как таблицу (аналогичную таблицам в Excel), которая находится в оперативной памяти компьютера. Однако у Recordset есть принципиальные отличия от таблиц
Excel:
Excel не следит за «строгостью» таблиц. На предприятиях часто можно встретить таблицы, в середину которых вставлены, например, промежуточные итоги по группам или заметки. Recordset — это «строгая» таблица. В ней четко определены столбцы и строки и разрывов она не допускает (хотя какие-то значения на пересечении строк и столбцов вполне могут быть пустыми);
в таблице Excel в одном столбце без проблем можно использовать самые разные значения — числовые, даты и времени, строковые, формулы и т. п. В Recordset для каждого столбца определяется тип данных и значения в этом столбце должны соответствовать этому типу данных.
Recordset обычно создается на основе данных, полученных с источника (но может быть создан и заполнен вручную), в которых предусмотрены столбцы (Fields) и строки (Rows). Создание объекта Recordset и заполнение его данными с источника в самом простом варианте выглядит так (подразумевается, что мы открыли при помощи объекта cn соединение с учебной базой данных
Northwind на SQL Server):
Dim rs As New ADODB.Recordset rs.Open «customers», cn
Убедиться, что Recordset действительно создан и существует, можно, например, при помощи строки:
MsgBox rs.GetString
|
Работа с базами данных и применение объектной модели ADO |
175 |
При открытии Recordset вполне могут возникнуть ошибки, поэтому рекомендуется использовать обработчик ошибок. Специальной коллекции Errors в Recordset не предусмотрено, а значит, придется обойтись стандартным объектом Err.
В нашем примере мы открыли таблицу Customers целиком. Однако это не единственный (и не лучший) способ извлечения данных с источника. Для метода Open() рекомендуется использовать запрос на языке SQL. Например, в нашем случае можно было бы использовать такой код:
rs.Open «select * from dbo.customers», cn
Запрос использовать лучше, потому что:
есть возможность указать фильтр Where (условие обязательно заключать в одинарные кавычки) и скачать в Recordset не все записи, а только удовлетворяющие вашему условию;
есть возможность точно так же ограничить число возвращаемых столбцов — снова сокращение объема передаваемых данных и уменьшение расхода памяти;
есть возможность использовать функции SQL, сортировку на источнике данных и множество полезных дополнительных возможностей.
Очень часто в реальных приложениях текст запроса «склеивается» из кусочков, которые поступают из разных мест. Например, пользователь выбрал в раскрывающемся списке имя заказчика, и для события Change этого списка тут же сработала процедура, которая выполнила запрос на SQL Server, получив данные только для этого заказчика, и присвоила полученные значения другим элементам управления. В нашем случае соответствующая строка кода может выглядеть так:
rs.Open «select * from dbo.customers Where CompanyName = » & «‘» _ & ComboBox1.Value & «‘» , cn
Набор символов «‘» — это одинарная кавычка внутри двух двойных. Такая конструкция нужна, чтобы текст запроса мог выглядеть, например, так:
select * from dbo.customers Where CompanyName = ‘Alfreds Futterkiste’
Причина проста — в языке SQL строковые значения нужно заключать в одинарные кавычки.
Если вы ответственны не только за создание клиентского приложения, но и за проектирование базы данных, бывает очень удобно предусмотреть запрос данных только через представления. Это позволит более гибко управлять системой безопасности и в случае необходимости перестройки базы данных
(например, разбиения главной таблицы на текущую и архивную) сэкономить множество времени.
И еще один практический момент. Конечно, для работы с базами данных знать язык запросов SQL очень полезно. Литературы по нему очень много, и его вполне реально освоить за несколько дней. Однако, если вы — обычный пользователь и не имеете об языке SQL никакого представления, ничего страшного. Просто открывайте таблицы целиком без всяких запросов, а все остальное можно будет сделать средствами VBA.
9.5.2. Настройки курсора
и другие параметры открытия Recordset
При открытии объекта Recordset можно определить еще несколько важных его свойств (их можно определить как напрямую перед открытием, так и передать как дополнительные параметры методу Open()).
Первое свойство — CursorType, тип курсора. Это свойство определяется только перед открытием Recordset (после открытия оно доступно только для чтения). Курсор можно представить себе как указатель на записи в Recordset. В зависимости от типа курсора мы определяем возможности работы с Recordset и производительность выполняемых операций (чем больше возможностей, тем меньше производительность, и наоборот). Можно задавать следующие значения:
•adOpenForwardOnly — это значение используется по умолчанию. Оно
оптимизировано для достижения максимальной производительности (его возможности будут минимальными). Курсор может двигаться только вперед, а изменения, вносимые другими пользователями, видны не будут;
•adOpenStatic — то же самое, что и предыдущее значение, за исключе-
нием того, что курсор может двигаться во всех направлениях;
•adOpenKeyset — позволяет двигаться курсору в любом направлении,
видны только изменения существующих записей другими пользователями (удаление старых записей и добавление новых не видны);
•adOpenDynamic — обеспечивает максимальные возможности: позволяет
двигаться в любых направлениях, видны любые изменения в записях, производимые другими пользователями. К сожалению, провайдер Microsoft.Jet.OLEDB.4.0 этот тип курсора не поддерживает, поэтому с Access и Excel его использовать не получится.
Свойство Recordset.RecordCount нормально функционирует только для курсоров типа adOpenStatic и adOpenKeyset. Для курсоров типа
|
Работа с базами данных и применение объектной модели ADO |
177 |
adOpenForwardOnly и adOpenDynamic оно возвращает −1, поскольку драйвер подключения не может определить количество записей.
Второе важное свойство — CursorLocation. Оно определяет, где будет создан курсор — на сервере или на клиенте. По умолчанию используется значение adUseServer (создавать на сервере). Второе значение — adUseClient (создавать на клиенте). В целом, практически во всех ситуациях удобнее и производительнее использовать серверные курсоры, за одним исключением — в реализации серверных курсоров на разных источниках данных много отличий, поэтому если вы планируете работать с разными источниками, имеет смысл подумать о клиентских курсорах.
Третье важное свойство — LockType. Это свойство определяет тип блокировок, которые будут наложены на записи на источнике, помещенные в Recordset. Можно использовать следующие значения:
•adLockReadOnly — записи в Recordset будут доступны только для чте-
ния, вы не сможете их изменять. Это значение используется по умолчанию;
•adLockPessimistic — наиболее надежный, с точки зрения целостности
данных, вид блокировки. Вы можете изменять записи в Recordset, но при начале изменения записи она блокируется на источнике таким образом, что другие пользователи не смогут обратиться к ней ни на чтение, ни на запись, пока вы не вызовете методы Update() или
CancelUpdate();
•adLockOptimistic — это значение позволяет выиграть в производитель-
ности за счет проигрыша в надежности обеспечения целостности данных. Запись на источнике блокируется только на время выполнения метода Update(). Остальные пользователи могут одновременно с вами читать и изменять данные на источнике;
•adLockBatchOptimistic — то же самое, что и adLockOptimistic, но вме-
сто немедленного обновления по одной записи используется пакетное обновление. В ситуации, когда изменяется большое число записей, такое решение позволяет выиграть в производительности.
Первый параметр метода Open() в наших примерах был как именем таблицы, так и командой SQL (могут использоваться и другие варианты). Поскольку драйвер OLE DB не знает, чем может быть передаваемый текст, он взаимодействует с сервером баз данных, чтобы определить это. На практике такое выяснение может сильно тормозить работу приложения, поэтому имеет смысл перед открытием Recordset явно указать тип передаваемых параметров. Это делается при помощи параметра Options, который передается этому методу.
Return to VBA Code Examples
In this tutorial, we will learn how to open a Recordset, count the number of records in the Recordset, loop through the Recordset, add a record, update a record, read a value from a record, and delete a record.
We have an Access Table, called ProductsT shown below:
Opening a Recordset
We first need to establish the database we intend to use, in this case it is the currently opened database. We can then use the CurrentDB.OpenRecordSet method to open/create our Recordset.
In order to create a Recordset that will allow us to manipulate the data in the table called ProductsT, we would use the following code:
CurrentDb.OpenRecordset ("ProductsT")
Counting the number of Records using VBA
Once you have created a Recordset, you would more than likely want to do something useful with it or manipulate the data in it in some way. You can count the number of records in your dataset (in this case the table called ProductsT) using the following code:
MsgBox CurrentDb.OpenRecordset("ProductsT").RecordCount
Looping through a RecordSet using VBA
The following code loops through our RecordSet:
Sub RecordSet_Loop ()
Dim ourDatabase As Database
Dim ourRecordset As Recordset
Set ourDatabase = CurrentDb
Set ourRecordset = ourDatabase.OpenRecordset("ProductsT")
Do Until ourRecordset.EOF
MsgBox ourRecordset!ProductID
ourRecordset.MoveNext
Loop
End Sub
Adding a record to a RecordSet
Use the Recordset.AddNew method to add a new record to the RecordSet:
Sub RecordSet_Add()
With CurrentDb.OpenRecordset("ProductsT")
.AddNew
![ProductID] = 8
![ProductName] = "Product HHH"
![ProductPricePerUnit] = 10
![ProductCategory] = "Toys"
![UnitsInStock] = 15
.Update
End With
End Sub
The result is:
Updating a Recordset
You have to use the Recordset.AddNew or Recordset.Edit method. After this statement you must use the Recordset.Update method in order to keep the changes.
Reading Values from a Record
You have to use the Recordset.FindFirst method to make a record, the current record. You then have to use Recordset.Fields to specify which field to look at.
Sub RecordSet_ReadValue ()
Dim ourDatabase As Database
Dim ourRecordset As Recordset
Set ourDatabase = CurrentDb
Set ourRecordset = ourDatabase.OpenRecordset("ProductsT", Type:=RecordsetTypeEnum.dbOpenDynaset)
With ourRecordset
.FindFirst "ProductName = " & "'Product CCC'"
If .NoMatch Then
MsgBox "No Match Found"
Else
MsgBox ourRecordset.Fields("ProductCategory")
End If
End With
End Sub
The result is:
VBA Coding Made Easy
Stop searching for VBA code online. Learn more about AutoMacro — A VBA Code Builder that allows beginners to code procedures from scratch with minimal coding knowledge and with many time-saving features for all users!
Learn More
Deleting a Record from a Recordset
In order to delete a record from a Recordset you have to first make it the current record using the Recordset.FindFirst method. You can then delete it using the Recordset.Delete method. The following code shows how to delete record 2 in the data set:
Sub RecordSet_DeleteRecord ()
Dim ourDatabase As Database
Dim ourRecordset As Recordset
Set ourDatabase = CurrentDb
Set ourRecordset = ourDatabase.OpenRecordset("ProductsT", Type:=RecordsetTypeEnum.dbOpenDynaset)
With ourRecordset
.FindFirst "ProductName = " & "'Product BBB'"
If .NoMatch Then
MsgBox "No Match Found"
Else
ourRecordset.Delete
End If
End With
'Re-open Table
DoCmd.Close acTable, "ProductsT"
DoCmd.OpenTable "ProductsT"
End Sub
The result is:






