Содержание
- 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: