LAP TRINH QUERY BANG SQL VA ADO
Chương 4: Chương 4: THAO TAC DU LiEU BANG QUERY
.Execute End With
'Ấn định tập hợp trả về cho một recordsel.
‘va in két qua ra cia so Immediate.
Set rst! = New ADODB.Recordset rst1.CursorType = adOpenStatic rst1.LockType = adLockReadOnly rstt.Open cmd
Debug.Print rstt.RecordCount For int1 = 1 To rst1.RecordCount
Debug.Print rsti("ProductName’) rst. MoveNext
Next int1 End Sub
Câu lệnh SELECT của MySelect3 hướng vào các field của hai bảng— không phải một bảng như trong ví dụ trước. Câu lệnh thực hiện liên kết bên trong vào bảng Produets và bang Order Details để tương hợp các field ProducHD ở cả hai bảng. Bởi vì câu lệnh SQL sử dụng từ khóa DISTINCT (phân biệt), nên các giá trị của field ProductName duge tra vé khéng tring lặp. Cuối cùng, liên kết bên trong cho phép thủ tục in tên sản phẩm mô tả tương ứng với mã ID của từng sản phẩm.
Ví Dụ Cách Sử Dụng SUM Và ORDER BY
Thủ tục dưới đây sử dụng hàm tập hợp SUM của SQL va cdc tùy chọn liên kết, sắp xếp. Nó tính tổng của giá mở rộng cho mỗi sản phẩm trong bảng Órder Deteiis. Kết quả trả về của câu lệnh được sắp xếp theo lợi nhuận của sản phẩm (từ cao đến thấp).
Sub MySelect4()
Dim cnn1 As New ADODB.Connection Dim emd1 As ADODB.Command
Dim rst1 As ADODB.Recordset, inti As Integer
"Tạo sự kết nối tới cơ sở dữ liệu khác.
cnn1.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
311
"Data Source=C: SAP rogram Files\Microsoft Office\OfficeV’ & _
"Samples\Northwind.mdb;"
‘Dinh nghĩa và thực thi lệnh để chọn các giá trị của field ProductName phan biệt từ một cặp các bảng liên kết, tính giá mỏ rộng
Set cmd1 = New ADODB.Command With cmd1
.ActiveConnection = cnn1
.CommandText = "Select Distinct Products.ProductName, * & _
"Sum([Order Details].[UnitPrice]*" &
"(Order Datails].[Quantity]ˆ" &
*(1-[Order Details].[Discount])) As [Extended Price] " &
“From Products Inner Join [Order Details] On” & _
“Products.ProductiD = [Order Details].ProductiD " & _
"Group By Products.ProductName " & _
“Order By Sum([Order Details].[UnitPrice]*" &
"[Order Details].{Quantity]*" & _
"(1-[Order Details].[Discount])) Desc"
.CommandType = adCmdText .Execute
End With
'Ấn định tập hợp trã về của câu lệnh select cho một recordset
va in két qua ra cita s6 Immediate.
Set rst1 = New ADODB. Recordset rst1.CursorType = adOpenKeyset rst1.Open cmd1
Debug.Print rst1.RecordCount For int1 = 1 To rst1.RecordCount
Debug.Print rst1("ProductName"), _ rst1.Fields("Extended Price") rst1.MoveNext
Next int1 End Sub
Thủ tục ÄMySelecf4 tạo một field tính toán. Thủ tục sử dung hàm SỮM với mệnh đề GROUP BY để tính tổng lợi nhuận của mỗi 312
Chuang 4: THAO TAC DU LIEU BANG QUERY
sản phẩm. Nếu không có mệnh đề GROUP BY, chương trình sẽ phải tạo field tính toán cho mỗi dòng trong bảng dữ liệu gốc nhưng nó không cung cấp kết quả tóm tắt theo nhóm. (Nó sẽ tính tổng lợi nhuận của tất cả các sản phẩm thay vì tổng lợi nhuận của mỗi loại sản phẩm)
Mệnh đề ORDER BY điều khiển trật tự sắp xếp của tập hợp trả về. Bạn có thể viết chương trình này ngắn gọn hơn (do tính giá mở rộng trùng lặp), tuy nhiên viết bằng cách này dễ hiểu và đơn giản cho chương trình đã tạo ra trong mạng lưới thiết kế query.
. Hàm Định Nghĩa Dữ Liệu
Có nhiều cách để tiếp cận định nghĩa dữ liệu bằng những câu lénh SQL. Phan này xem xét cách tạo một bảng với các query make-table như thế nào. Các query make-table là những query action để tạo bảng mới dựa vào tập hợp kết quả của một query đang tồn tại. Đây là một hàm định nghĩa đữ liệu.
Phần này còn giải thích cách tự động sửa đổi các field autoincrement với các từ khóa SQL ALTER TABLE va ALTER COLUMN. Jet 4 SQL giới thiệu một kiểu dữ liệu của ủeld định danh mới để làm dễ dàng cho mục tiêu này. Jet 4 hỗ trợ thiết lập các giá trị ban đầu và bước nhảy để đếm các field. (bạn có thể khởi tạo lại chúng bất kỳ lúc nào.) Các thủ tục ví dụ trong phần này tự kết thúc, nhưng chúng vẫn có giá trị nếu bạn xem xét chúng kỹ lưỡng hơn như đã trình bày trong Chuong 3. ALTER TABLE va ALTER COLUMN là một phần của tập hợp từ khóa (ví dụ CREATE TABLE, CREATE INDEX, và DROP) để hỗ trợ trực tiếp cho những hàm định nghĩa dữ liệu thông qua SQL.
SELECT...INTO
Cú pháp của m$t query make-table trong SQL nhu sau:
SELECT FieldList INTO NewTableName FROM RecordSource
313
Nếu bạn tạo một bảng mới trong một file cơ sở dữ liệu khác
so với cơ sở đữ liệu hiện hành, hãy thêm mệnh đề IN vào sau mệnh
đê INTO và trước mệnh đề FROM. Bạn sử dụng mệnh đề IN để chỉ ra đường dẫn và tên file cơ sở dữ liệu mà nó sẽ chứa đầu ra từ câu lệnh SELECT...INTO.
RecordSource có thể bao gồm một bảng, một query, hoặc một vài nguồn khác, nó chứa tất cả những field bạn muốn có trong bảng mới. Câu lệnh SELECT...INTO sao chép thiết kế của những field được chọn lựa và đữ liệu của chúng vào một bảng mới. Bạn không thể tạo bất kỳ một ủield mới nào bằng cõu lệnh SELECT...INTO.
Bạn có thể dễ đàng có được mẫu ban đầu của query kiểu này bằng cách tạo chúng trong khung nhìn Design rồi chuyển sang khung nhìn SQL và chép câu lệnh SQL vào thủ tục sử dụng đối tượng ADO. Với giải pháp này, bạn không phải thiết kế câu lệnh SQL.
Thủ tục dưới đây sử dụng một câu lệnh SELECT..INTO don giản. Nó sao lưu bảng FamilyMembers trong cơ sở dữ liệu hiện hành thành một bảng mới có tên là FMBachup.
Sub MyMakeTable()
Dim cnni As ADODB.Connection 'Nối kết tham chiếu.
Set cnni = CurrentProject.Connection
‘Thue thi SQL cho query maketable.
cenni.Execute "SELECT FamilyMembers,* INTO" & _
“FMBackup FROM FamilyMembers"
"Thủ tục này ngưng nếu FMBackup đã tồn tại.
End Sub
Đáng tiếc rằng, việc tạo và chạy một câu lệnh SELECT...
INTO lại phổ biến hơn so với hai câu lệnh này của ADO. Ví dụ, thủ tục này có thể ngưng nếu bảng FMBackup đã tồn tại. Nó cũng có thể ngưng nếu một người sử dụng khác mở cả hai bảng. Những lý
_—
Chuong 4: THAO TAC DU LIEU BANG QUERY
do này và các lý do phức tạp khác đòi hỏi phải có bẫy lỗi. Ví dụ đưới đây minh họa cách bắt đầu xử lý lỗi trong một ứng dụng để sử dụng thủ tục có câu lénh SELECT... . INTO nhu thé nao.
Sub MyMakeTable2() On Error GoTo Make2Err:
Dim cnnt As ADODB.Connection
‘Két néi tham chiéu.
Set cnn1 = CurrentProject.Connection
‘Kiém tra cdc Idi khong du kién truéc.
Err.Raise 1
‘Thuc thi SQL cho query make-table.
cnn1.Execute "SELECT FamilyMembers.* INTO” & _
"FMBackup FROM FamilyMembers"
Make2Exit:
'Đóng kết nối và cài đặt nó bang Nothing và thoát khỏi thủ tục.
cnn1.Close
Set cnn1 = Nothing Exit Sub
Make2Err:
‘Bay cho bảng có sẵn.
If Err.Number = -2147217900 Then cnn1.Execute “Drop Table FMBackup"
Resume Else
MsgBox “The program generated an unanticipated “ & _
“error. Its number and description are" & _ Err.Number & *: " & Err.Description, vbCritical, _
"Programming Microsoft Access 2000"
End lf
Resume Make2Exit End Sub
315
Thủ tục này thực hiện cùng một tác vụ giống như thủ tục gốc, nhưng nó không bị lỗi dù bảng #MBzckup đã tổn tại. Trình xử lý lỗi nhận ra loại lỗi này và tiến hành xóa bảng đã có trước khi thực hiện câu lệnh lại lần nữa. Nếu có một lỗi khác xảy ra, ứng dụng đưa ra thông tin cần thiết trong một hộp thông báo để người dùng có thể cung cấp chứng cứ cho người phát triển biết vấn để này.
Thủ tục bao gồm một số tính năng bẫy lỗi. Ngay sau khi thiết lập kết nối, chương trình có thể gọi phương pháp ?aise của đối tượng Err. Thủ tục này sử dụng đối tượng Err để tạo ra một lỗi giả tạo giúp cho thủ tục biết cách xử lý kịp thời những lỗi không biết trước được.
Ví dụ còn chấm dứt kết nối và thiết lập thuộc tính cho đối tượng ConnecHon là Nothing. Hai công việc này có cùng mục đích
và bổ sung cho nhau. Khi bạn chấm dứt một kết nối, tài nguyên sử dụng cho kết nối này được dùng cho phần còn lại của hệ thống. Tuy nhiên đếi tượng vẫn còn nằm trong bộ nhớ và thuộc tính của nó vẫn còn nguyên vẹn. Sau đó bạn có thể mở một đối tượng Connection giống như vậy với những thiết lập thuộc tính như cũ hoặc mới. Bạn phải thiết lập đối tuợng đó là Nothing để gỡ bỏ nó ra khỏi bộ nhớ.
Sử Dụng ALTER TABLE Và ALTER COLUMN Để Xác Lộp Lại Những Field Autoincrement.
Nhiều nhà phát triển Access hdo hức bởi có diéu khién mới để ho học hỏi thêm qua các kiểu dữ liệu Counter để làm việc như là các field định danh cho các record. ở Chương 3 đã trình bày cách thiết lập các giá trị ban đầu và bước nhảy cho một field Counter (đếm). Trong khi điều này rất ấn tượng, bạn phải hiểu đẩy đủ về cách điều khiến các field này hơn là chỉ thiết lập những giá trị ban đầu. Thủ tục dưới đây xác lập lại giá trị ban đầu và bước nhảy của kiểu dữ liệu Counter.
Sub ResetCounter(intStart, intStep) Dim cnn1 As ADODB.Connection
Chuang 4: THAO TAC DU LIEU BANG QUERY Dim strSQL
'Kết nối tham chiếu và thực thi SQL dé xem.
Set cnn1 = CurrentProject.Connection
'Tạo chuỗi SQL để các tham chiếu qua các đối số.
strSQL = "ALTER TABLE FamilyMemberNames " & _
*ALTER COLUMN FamiD Identity " & _
“( & intStart & "," & intStep & ")"
"Thực thi câu lệnh SQL dé cdp nhat counter.
cnn1.Execute strSQL End Sub
Tha tuc ResetCounter ở trên giải thích cách tạo một câu lệnh SQL năng động bằng cách nối thêm những thông số vào câu lệnh SQL. Quá trình này tương tự như truyền những giá trị vào một query parameter. Thi tuc ResetCounter xdc lap field FamID trong bang FamilyMemberNames va tạo hai thông số. Thông số thứ nhất là giá trị của field counter mới để cho record kế tiếp được thêm vào bảng; thông số thứ hai là giá trị bước nhảy cho những record mới tiếp theo. Bạn có thể chạy thủ tục bằng cách gõ đòng lệnh sau vào cửa sổ Immediate:
ResetCounter 2,2
Hai thông số này bắt buộc record kế tiếp khi thêm vào bảng cú giỏ trị của field FœmnùD là 2; Mỗi record thờm vào sẽ cú giỏ trị của fủeld FœmID lớn hơn giỏ trị của bước nhảy là 2. Hóy cẩn thận khi thiết lập giá trị ban đầu và bước nhảy bởi vì bạn có thể gây ra xung đột về khóa (chẳng hạn như trùng giá trị) điều đó sẽ ngăn cản người dùng nhận thêm record mới vào bảng. May mắn thay Access 2000 cho phép bạn kiểm tra những giá trị đã tén tai trong field counter bằng chương trình. Bởi vậy bạn có thể xây dựng chương trình báo đảm rằng vấn để đó sẽ không xảy ra, điều này sẽ thể hiện trong thủ tục kế tiếp.
317
Điểm chính của tha tuc ResetCounter 1A cau lénh SQL. Nhu bạn có thể thấy, thủ tục có ba thành phần tới hạn. Các từ khóa ALTER TABLE thay đối thiết kế của bảng chỉ định. Các từ khóa ALTER COLUMN thay đổi thiết kế của field chỉ định. Từ khóa IDENTITY cap nhat field counter cé các thông số chỉ rõ giá trị ban đầu và bước nhảy của field.
Thủ tục dưới đây SetResetCounter tuy đài nhưng nó không rắc rối nhiều. Nó dùng một phương pháp thao tác các giá trị của field counter để tránh xung đột về khóa. Hình 4-26 trình bày một bảng sau khi chạy thành công thủ tục Se(ResetCounter. Lưu ý rằng record đầu tiên có giá trị của field FamID là 2 và giá trị của field FamID của record sau được tăng thêm 2. Record thứ 3 có giá trị field FaniID là 8, nó vượt ra khỏi giá trị bước nhảy trước. Ngoài ra, với mỗi record thêm mới tiếp theo có giá trị field FœmID tăng thêm 4 so với giá trị trước. Việc thay đổi giá trị ban đầu và bước nhảy của field counter là kết quả của việc goi ham ResetCounter. Dong chữ trong field MyMemoField danh đấu sự thay đổi này.
BH FamduMemberNames: Iable zz . --
FamiD PersonName MyMemoField 2 Rick Dobson start, step = 2 4 Virginia Dobson
8 Glen Hill see my new start & step 12 Tony Hill
16 Shelly Hitt B (AutoNumber
Hinh 4-26. Bang FamilyMemberNames sau khi thực hiện thủ tục SetResetCounter.
Sub SetResetCounter()
Dim ennt As New ADODB.Connection Dim cmd1 As ADODB.Command
Dim rst1 As ADODB.Recordset, rst2 As New ADODB.Recordset Dim inti As Integer
318
Chuang 4: THAO TAC DU LIEU BANG QUERY
'Kết nối tham chiếu.
Set cnn1 = CurrentProject.Connection
'Xóa bảng FamilyMemberNames và tạo lại counter (bộ đếm) của bảng.
DoCmd.SetWarnings False
DoCmd.OpenQuery “qdlAllFamilyMemberNames"
DoCmd.SetWarnings True ResetCounter 2, 2
'Thêm một cặp record vào bảng FamilyMemberNames 'Tử bảng FamilyMembers với
các giá trị ban đầu và bước nhảy.
Set rst1 = New ADODB.Recordset
rs†1.Open “FamilyMemberNames", cnn1, adOpenKeysol, _ adLockOptimistic, adCmdTable
rst2.Open "FamilyMembers", cnn1, adOpenForwardOnly, _ adLockReadOnly, adCmdTable
For int1 = 1 To 2 rst†.AddNew
rstt(1) = rst2(1) & * " & rst2(2) ifint? = 1 Then
rstt("“MyMemoField") = “start, step = 2"
End If
rst2.MoveNext rst1.Update Next int†
rs†1.Close
'Định nghĩa và thực thí lệnh để chọn các gia tri field FamiD Với giỏ trị FamID cao nhất ở đầu --> giỏ trị counler ử cuối.
Set cmđ1 = New ADODB.Command With cmd1
-ActiveConnection = cnn1
-CommandText = "Select FamiD from FamilyMemberNames * & _
“Order By FamID Desc"
.CommandType = adCmdText .Execute
End With
319
| | | 1
1 ị
Ỉ ị ị ị ị }
ị ị
ị ị ị
j
‘Luu gia tri counter cudi va dùng nó để khỏi tao lại các giá trị ban đầu và bước nhảy.
Set rst1 = New ADODB.Recordset rs†1.CursorType = adOpenForwardOnly rst†.LockType = adLockReadOnly rst1.Open cmd1
int1 = rst1(0) rst1.Close
ResetCounter intt + int1, int1
'Thêm các record còn lại từ bằng FamilyMembers vào bảng FamilyMemberNames với
các giá trị ban đầu và bước nhảy.
rst†.Open "FamilyMemberNames", cnn1, adOpenKeyset, _ adLockOptimistic, adCmdTable
rst1(2) = "see my new start & step"
int1 = 3
Do Until rst2.EOF rstt.AddNew
rst1(1) = rst2(1) & " " & rst2(2) lf int1 = 3 Then
rst†(°MyMemoField") = _
"see my new start & step”
End If
rst2.MoveNext int1 = int1 +1 rst1 Update Loop
End Sub
Tha tuc SetResetCounter c6 6 phan phân cách với nhau bởi các chú thích. Phần thứ nhất thiết lập một kết nối với cơ sở dữ liệu hiện hành. Phân thứ 2 chạy một query delete để xóa tất cả các dong trong bang FamilyMemberNames, cho phép các lời cảnh báo của hệ thống có hiệu lực bằng cách gọi phương pháp SetWarnings, rồi khởi tạo lại giá trị ban đâu và giá trị buớc nhảy của counter cho bảng FemilyMemberNames bằng cách gọi thủ tục ReseCounter.
320
Chuang 4: THAO TAC DU LIEU BANG QUERY
Phần thứ ba dùng một vòng lặp For...Next dé sao chép hai record dau tién của bảng FamilyMembers vào bằng FamilyMember- Names. Cong cu cia cơ sở dữ liệu Jet tự động gán các giá trị của FamID cho hai record nay bằng cách sử dụng các giá trị ban đầu và bước nhảy đã được thiết lập ở phần truớc,
Phần thứ tư dùng một déi tuong Command trén bang FamilyMemberNames để tìm giá trị lớn nhất của field FamID. Khi câu lệnh thực thi, nó sắp xếp các record của bảng theo chiều giảm dần của field #œmID, nơi đặt giá trị lớn nhất của field FamID field, là khoá chính của bảng, ở đầu của kết quả trả về. Am hiểu giá trị này cho phép ứng dụng của bạn thiết lập một giá trị bắt đầu mới cho những record thêm vào mà không trùng với bất kỳ giá trị khóa nào trong bảng.
Phan thứ năm mở một recordset vào tập hợp trả về của lệnh và lưu trữ giỏ trị fủeld FamID trong record đầu tiờn của recordset.
Phần này còn thi hành thủ tục #ese¿Counter để thiết lập giá trị bắt đầu mới, nó lớn gấp hai lần so với giá trị lớn nhất của FamID và một kích thước bước nhảy mới bằng với giá trị lớn nhất của field FamID.
Phan cuối cùng thêm cdc record cdn lai cia bảng FamilyMembers vao bang FamilyMemberNames. Dé cing cé việc diộu khiển mềm dẻo cỏc fủield khúa chớnh counter, cột Äfemo chứa một. câu thông báo để chỉ rõ thủ tục Se(RetCounter thao tác field counter một cách tùy ý như thế nào.
Views Va Thủ Tục Lưu Trữ
Trước đây, các view và các thủ tục lưu trữ chỉ có những người quản lý cơ sở đữ liệu cao cấp (high-end) sử dụng, nhưng bây giờ có thể sử dụng trong Access 2000. Access 2000 thực thi các view không hỗ trợ những thông số như các query lưu trữ trả về các dòng. Access 2000 cung cấp các thủ tục lưu trữ cho hai loại query action lưu trữ và query parameter để làm việc hoặc như các query action hoặc như 321
query select. Bạn sẽ thấy, bạn có thể thực hiện chức năng của query parameter bằng cách truyền các hằng chuỗi tới một thủ tục để trộn với các giá trị chuyển vào trong một câu lệnh SQL và rồi thực hiện câu lệnh này.
View
Câu lệnh CREATE VIEW của SQL tạo một view bằng cách thêm một query select đã lưu vào cửa sổ Database ở đưới loại đối tượng Queries. (Trong một file để án của Access .adp, những view của bạn được lưu ở dưới loại đối tượng Vieios của cửa sổ Database).
Tiến trình tạo một query select lưu trữ với CREATE VIEW la truc tiếp hơn so với ADO, nó yêu cầu bạn trước tiên phải xây dựng một đối tượng Command và sau đó nối thêm nó vào tập hợp Vieus.
Thủ tục dưới đây giải thích cú pháp và thao tác của câu lệnh CREATE VIEW của SQL trong ADO.
Sub CreateView()
Dim cnn1 As ADODB.Connection 'Kết nối tham chiếu.
Set cnn1 = CurrentProject.Connection 'Thuc thi SQL cho view.
cnnt.Execute “Create View CategoryView as" & _
“SELECT * From Categories”
RefreshDatabaseWindow
"Thưởng trình thủ tục đơn giản này ngừng nếu CalegoryView đã có sẵn.
End Sub
Thủ tục thực hiện phương pháp Execute của kết nối và truyền cho nó một câu lệnh CREATE VIEW của SQL. Tên của query select được đặt ngay sau từ khóa CREATE VIEW và theo sau bởi từ khóa AS và câu lệnh SELECT của SQL. Câu lệnh SELECT có thể là bất kỳ câu lệnh SELECT chuẩn nào Cuối cùng, thủ tục gọi