Đố vui về ADO, DAO.

Liên hệ QC
lâu lắm không thấy ai viết bài
Hôm nay Mạnh hỏi 1 chút
thông thường khi ta sử dung ADO để lấy dữ liệu từ 1 Sheet file đóng lên hay lấy dữ liệu vào Mảng ta hay sử dụng 2 dòng code cơ bản sau
Mã:
Set cn = CreateObject("ADODB.Connection")
Set rst = CreateObject("ADODB.Recordset")
Vậy nếu ta chỉ sử dụng 1 dòng sau để Copy dữ liêu từ 1 Sheet lên hay lấy dữ cho vào mảng thì có chạy nhanh hơn 2 dòng trên kết hợp hay ko
và tại sao mong các Bạn chỉ dẫn
Mã:
Set rst = CreateObject("ADODB.Recordset")

Xin cảm ơn
 
Nhanh hay không chưa biết. Không có connection lấy gì đọc dữ liệu?
 
Nhanh hay không chưa biết. Không có connection lấy gì đọc dữ liệu?
Câu trả lời của Mình là ĐƯỢC .... TA không cần sử dụng connection hay chi tiết như sau ta vẫn có thể lấy dữ liệu lên Sheet hay mảng ok
Mã:
Set cn = CreateObject("ADODB.Connection")
Ta chỉ cần cơ bản 1 dòng sau là đủ để lấy dữ liệu lên Sheet hay lên Mảng
Mã:
Set rst = CreateObject("ADODB.Recordset")
Làm phiền @Hai Lúa Miền Tây cho xin 1 ý kiến cho bài 321 & 322 và bài này ... Mạnh Cảm Ơn
 
Câu trả lời của Mình là ĐƯỢC .... TA không cần sử dụng connection hay chi tiết như sau ta vẫn có thể lấy dữ liệu lên Sheet hay mảng ok
Mã:
Set cn = CreateObject("ADODB.Connection")
Ta chỉ cần cơ bản 1 dòng sau là đủ để lấy dữ liệu lên Sheet hay lên Mảng
Mã:
Set rst = CreateObject("ADODB.Recordset")
Làm phiền @Hai Lúa Miền Tây cho xin 1 ý kiến cho bài 321 & 322 và bài này ... Mạnh Cảm Ơn
Ta có thể khai báo và khởi tạo Object 1 trong 2 cái trên (Hoặc cn hoặc rst) đều có thể lấy được dữ liệu. Cho dù có dùng cách không khai báo và khởi tạo Object (Conection hay Recordset) thì theo tôi đã từng sử dụng thì tốc độ cũng không có khác biệt là mấy. Bởi vì nếu như anh không khởi tạo connection thì anh cũng phải dùng chuỗi kết nối với file nguồn trong thủ tục mở recordset.
 
Ta có thể khai báo và khởi tạo Object 1 trong 2 cái trên (Hoặc cn hoặc rst) đều có thể lấy được dữ liệu. Cho dù có dùng cách không khai báo và khởi tạo Object (Conection hay Recordset) thì theo tôi đã từng sử dụng thì tốc độ cũng không có khác biệt là mấy. Bởi vì nếu như anh không khởi tạo connection thì anh cũng phải dùng chuỗi kết nối với file nguồn trong thủ tục mở recordset.
Chính xác vậy và đây là code Mạnh Viết .. Nhờ HLMT coi dùm
Mã:
Private Sub CopyRecordset()
    Dim Rst As Object, SQL As String
    Dim Strcon As String, ExcelPath As String
    Dim RecCount  As Long
    ExcelPath = ThisWorkbook.Path & "\Data.xlsb"
    Set Rst = CreateObject("ADODB.Recordset")
    SQL = "select * from [Data_Nhap$]" ''Tuy chon Mo Rong de lay du lieu
    Strcon = ("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ExcelPath _
                & ";Extended Properties=""Excel 12.0 Xml;HDR=Yes;"";")
    Rst.Open SQL, Strcon, 3, 1
    RecCount = Rst.RecordCount
    MsgBox RecCount
    If Not Rst.EOF Then
        Cells.ClearContents
        Range("A1").CopyFromRecordset Rst
    End If
End Sub
Rem ==========
Private Sub GetDataGetRows()
    Dim Rst As Object, SQL As String
    Dim Strcon As String, ExcelPath As String
    Dim RecCount  As Long
    Dim dArr(), Arr(), i As Long, j As Long, k As Long
    ExcelPath = ThisWorkbook.Path & "\Data.xlsb"
    Set Rst = CreateObject("ADODB.Recordset")
    SQL = "select * from [Data_Nhap$]" ''Tuy chon Mo Rong de lay du lieu
    Strcon = ("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ExcelPath _
                & ";Extended Properties=""Excel 12.0 Xml;HDR=Yes;"";")
    Rst.Open SQL, Strcon, 3, 1
    RecCount = Rst.RecordCount
    MsgBox RecCount
    If Not Rst.EOF Then
        Arr = Rst.getrows(RecCount)
        ReDim dArr(1 To UBound(Arr, 2) + 1, 1 To UBound(Arr, 1) + 1)
        For i = 0 To UBound(Arr, 2)
            k = k + 1
            For j = 0 To UBound(Arr, 1)
                dArr(k, j + 1) = Arr(j, i)
            Next j
        Next i
        Cells.ClearContents
        Range("A2").Resize(UBound(dArr, 1), UBound(dArr, 2)) = dArr
    End If
End Sub
 
Chính xác vậy và đây là code Mạnh Viết .. Nhờ HLMT coi dùm
Mã:
Private Sub CopyRecordset()
    Dim Rst As Object, SQL As String
    Dim Strcon As String, ExcelPath As String
    Dim RecCount  As Long
    ExcelPath = ThisWorkbook.Path & "\Data.xlsb"
    Set Rst = CreateObject("ADODB.Recordset")
    SQL = "select * from [Data_Nhap$]" ''Tuy chon Mo Rong de lay du lieu
    Strcon = ("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ExcelPath _
                & ";Extended Properties=""Excel 12.0 Xml;HDR=Yes;"";")
    Rst.Open SQL, Strcon, 3, 1
    RecCount = Rst.RecordCount
    MsgBox RecCount
    If Not Rst.EOF Then
        Cells.ClearContents
        Range("A1").CopyFromRecordset Rst
    End If
End Sub
Rem ==========
Private Sub GetDataGetRows()
    Dim Rst As Object, SQL As String
    Dim Strcon As String, ExcelPath As String
    Dim RecCount  As Long
    Dim dArr(), Arr(), i As Long, j As Long, k As Long
    ExcelPath = ThisWorkbook.Path & "\Data.xlsb"
    Set Rst = CreateObject("ADODB.Recordset")
    SQL = "select * from [Data_Nhap$]" ''Tuy chon Mo Rong de lay du lieu
    Strcon = ("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ExcelPath _
                & ";Extended Properties=""Excel 12.0 Xml;HDR=Yes;"";")
    Rst.Open SQL, Strcon, 3, 1
    RecCount = Rst.RecordCount
    MsgBox RecCount
    If Not Rst.EOF Then
        Arr = Rst.getrows(RecCount)
        ReDim dArr(1 To UBound(Arr, 2) + 1, 1 To UBound(Arr, 1) + 1)
        For i = 0 To UBound(Arr, 2)
            k = k + 1
            For j = 0 To UBound(Arr, 1)
                dArr(k, j + 1) = Arr(j, i)
            Next j
        Next i
        Cells.ClearContents
        Range("A2").Resize(UBound(dArr, 1), UBound(dArr, 2)) = dArr
    End If
End Sub
Thì như tôi đã nói ở trên thôi, thông thường thì người ta bỏ khởi tạo recordset chứ ít ai bỏ khởi tạo connection. Dùng cách nào miễn mình quen và tránh xảy ra lỗi tiềm ẩn, kết quả đúng là được.
 
Khi mở một file để đọc, ADO coi như đó là một CSDL, và nó cần tạo một connection để kết nối. Cái lệnh Open mà bạn thấy nó chính thức gồm luôn Open Connection và Excute Command (lệnh SQL).
Khi chỉ cần đọc một lần, cái connection có thể được hiểu ngầm (implicit, trái với tường minh là explicit), đọc xong rồi bỏ. Kiểu giống như sử dụng các đối tượng bằng lệnh With CreateObject(...) - End With, cái Object đó được thành lập và bỏ sau lệnh End With.
Lý do tại sao phải mở connection tường minh (khai báo và set 1 cái object connection):
1. Khi cần đọc nhiều lần: một lần connect vào CSDL tốn tài nguyên, vì vậy nếu đọc nhiều lần thì nên giữ lại. Sau khi đọc xong thì đóng lại (huỷ đi). Hầu hết công việc mà các bạn làm ở đây chỉ đọc mỗi file 1 lần cho nên bạn chưa thấy nhu cầu này.
2. Khi CSDL thuộc loại có nhiều thủ tục (ví dụ SQL Server có admin của nó, chỉ cho phép 1 số tình trạng kết nối). Ngừoi dùng cần phân biệt lúc kết nối và lúc lấy dữ liệu để có thể debug hoặc bẫy lỗi.
3. Hầu hết các CSDL quan trọng không cho phép truy vấn bằng lệnh SQL suông. Gọi SQL sẽ dẫn đến việc phá hoại (SQL attack). Cách duy nhất mà admin cho phép là gọi thủ tục (stored procedure) và chi tiết thì được nạp qua tham số. Trong trường hợp này, cái object connection tường minh nó giúp bạn làm việc dễ hơn.

(*) cũng giống như biến, bạn không bắt buộc phải khai báo. Bạn hoàn toàn có thể để dùng đến đâu VBA tự lập biến đến đó.
Lý do bạn khai báo biến là vì muốn kiểm soát cho dễ. Lý do code của bạn không cần dựng connection tường minh là vì giai đoạn sử dụng rất ngắn, trung bình khoảng chục dòng code.
 
Khi mở một file để đọc, ADO coi như đó là một CSDL, và nó cần tạo một connection để kết nối. Cái lệnh Open mà bạn thấy nó chính thức gồm luôn Open Connection và Excute Command (lệnh SQL).
Khi chỉ cần đọc một lần, cái connection có thể được hiểu ngầm (implicit, trái với tường minh là explicit), đọc xong rồi bỏ. Kiểu giống như sử dụng các đối tượng bằng lệnh With CreateObject(...) - End With, cái Object đó được thành lập và bỏ sau lệnh End With.
Lý do tại sao phải mở connection tường minh (khai báo và set 1 cái object connection):
1. Khi cần đọc nhiều lần: một lần connect vào CSDL tốn tài nguyên, vì vậy nếu đọc nhiều lần thì nên giữ lại. Sau khi đọc xong thì đóng lại (huỷ đi). Hầu hết công việc mà các bạn làm ở đây chỉ đọc mỗi file 1 lần cho nên bạn chưa thấy nhu cầu này.
2. Khi CSDL thuộc loại có nhiều thủ tục (ví dụ SQL Server có admin của nó, chỉ cho phép 1 số tình trạng kết nối). Ngừoi dùng cần phân biệt lúc kết nối và lúc lấy dữ liệu để có thể debug hoặc bẫy lỗi.
3. Hầu hết các CSDL quan trọng không cho phép truy vấn bằng lệnh SQL suông. Gọi SQL sẽ dẫn đến việc phá hoại (SQL attack). Cách duy nhất mà admin cho phép là gọi thủ tục (stored procedure) và chi tiết thì được nạp qua tham số. Trong trường hợp này, cái object connection tường minh nó giúp bạn làm việc dễ hơn.

(*) cũng giống như biến, bạn không bắt buộc phải khai báo. Bạn hoàn toàn có thể để dùng đến đâu VBA tự lập biến đến đó.
Lý do bạn khai báo biến là vì muốn kiểm soát cho dễ. Lý do code của bạn không cần dựng connection tường minh là vì giai đoạn sử dụng rất ngắn, trung bình khoảng chục dòng code.
Cảm ơn Bạn ... tại vì chưa hiểu sâu xa bản chất của vấn đề nên mới hỏi để học tập nghiên cứu thêm ... vậy là phần nào hiểu chút chút :p:D
 
Cảm ơn Bạn ... tại vì chưa hiểu sâu xa bản chất của vấn đề nên mới hỏi để học tập nghiên cứu thêm ... vậy là phần nào hiểu chút chút :p:D
Nói nôm na như thế này. Khi anh cần nhập, xuất hàng thì anh phải mở của kho để nhập xuất, nếu trong phiên làm việc có nhiều lần nhập xuất và việc nhập xuất đó liên tục thì anh vẫn phải để cửa kho cho người ta nhập xuất. Khi hết phiên làm việc mới đóng cửa kho, không phải khi vừa nhập hoặc vừa xuất xong thì đóng cửa kho và mở cửa kho liên tục, làm như vậy vẫn được nhưng hãy suy nghĩ lại có ổn không. Tương tự trong ứng dụng liên quan đến CSDL người ta thường khai báo và mở kết nối 1 lần (Mở cửa kho), sau đó thực hiện thêm, xóa, lấy, chỉnh sửa... (Nhập xuất hàng). Khi kết thúc ứng dụng thì đóng kết nối (Đóng cửa kho). Dĩ nhiên phải lưu ý việc ứng dụng đã chạy nhưng không dùng thì ta phải đặt thời gian thích hợp ở Server hoăc ở ứng dụng để hủy kết nối nhằm giảm tải cho Server.
 
Nói nôm na như thế này. Khi anh cần nhập, xuất hàng thì anh phải mở của kho để nhập xuất, nếu trong phiên làm việc có nhiều lần nhập xuất và việc nhập xuất đó liên tục thì anh vẫn phải để cửa kho cho người ta nhập xuất. Khi hết phiên làm việc mới đóng cửa kho, không phải khi vừa nhập hoặc vừa xuất xong thì đóng cửa kho và mở cửa kho liên tục, làm như vậy vẫn được nhưng hãy suy nghĩ lại có ổn không. Tương tự trong ứng dụng liên quan đến CSDL người ta thường khai báo và mở kết nối 1 lần (Mở cửa kho), sau đó thực hiện thêm, xóa, lấy, chỉnh sửa... (Nhập xuất hàng). Khi kết thúc ứng dụng thì đóng kết nối (Đóng cửa kho). Dĩ nhiên phải lưu ý việc ứng dụng đã chạy nhưng không dùng thì ta phải đặt thời gian thích hợp ở Server hoăc ở ứng dụng để hủy kết nối nhằm giảm tải cho Server.
Mạnh hiểu rồi vậy nên nó mới đẻ ra cái dòng sau phải ko ?!
Mã:
If Cnn.State <> 1 Then
 
Chính xác vậy và đây là code Mạnh Viết .. Nhờ HLMT coi dùm
Mã:
Private Sub CopyRecordset()
    Dim Rst As Object, SQL As String
    Dim Strcon As String, ExcelPath As String
    Dim RecCount  As Long
    ExcelPath = ThisWorkbook.Path & "\Data.xlsb"
    Set Rst = CreateObject("ADODB.Recordset")
    SQL = "select * from [Data_Nhap$]" ''Tuy chon Mo Rong de lay du lieu
    Strcon = ("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ExcelPath _
                & ";Extended Properties=""Excel 12.0 Xml;HDR=Yes;"";")
    Rst.Open SQL, Strcon, 3, 1
    RecCount = Rst.RecordCount
    MsgBox RecCount
    If Not Rst.EOF Then
        Cells.ClearContents
        Range("A1").CopyFromRecordset Rst
    End If
End Sub
Rem ==========
Private Sub GetDataGetRows()
    Dim Rst As Object, SQL As String
    Dim Strcon As String, ExcelPath As String
    Dim RecCount  As Long
    Dim dArr(), Arr(), i As Long, j As Long, k As Long
    ExcelPath = ThisWorkbook.Path & "\Data.xlsb"
    Set Rst = CreateObject("ADODB.Recordset")
    SQL = "select * from [Data_Nhap$]" ''Tuy chon Mo Rong de lay du lieu
    Strcon = ("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ExcelPath _
                & ";Extended Properties=""Excel 12.0 Xml;HDR=Yes;"";")
    Rst.Open SQL, Strcon, 3, 1
    RecCount = Rst.RecordCount
    MsgBox RecCount
    If Not Rst.EOF Then
        Arr = Rst.getrows(RecCount)
        ReDim dArr(1 To UBound(Arr, 2) + 1, 1 To UBound(Arr, 1) + 1)
        For i = 0 To UBound(Arr, 2)
            k = k + 1
            For j = 0 To UBound(Arr, 1)
                dArr(k, j + 1) = Arr(j, i)
            Next j
        Next i
        Cells.ClearContents
        Range("A2").Resize(UBound(dArr, 1), UBound(dArr, 2)) = dArr
    End If
End Sub
bạn có thể cho mình xin file đính kèm dùng code này hoạt động để học hỏi thêm được không ạ.
 
Chính xác vậy và đây là code Mạnh Viết .. Nhờ HLMT coi dùm
Mã:
Private Sub CopyRecordset()
    Dim Rst As Object, SQL As String
    Dim Strcon As String, ExcelPath As String
    Dim RecCount  As Long
    ExcelPath = ThisWorkbook.Path & "\Data.xlsb"
    Set Rst = CreateObject("ADODB.Recordset")
    SQL = "select * from [Data_Nhap$]" ''Tuy chon Mo Rong de lay du lieu
    Strcon = ("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ExcelPath _
                & ";Extended Properties=""Excel 12.0 Xml;HDR=Yes;"";")
    Rst.Open SQL, Strcon, 3, 1
    RecCount = Rst.RecordCount
    MsgBox RecCount
    If Not Rst.EOF Then
        Cells.ClearContents
        Range("A1").CopyFromRecordset Rst
    End If
End Sub
Rem ==========
Private Sub GetDataGetRows()
    Dim Rst As Object, SQL As String
    Dim Strcon As String, ExcelPath As String
    Dim RecCount  As Long
    Dim dArr(), Arr(), i As Long, j As Long, k As Long
    ExcelPath = ThisWorkbook.Path & "\Data.xlsb"
    Set Rst = CreateObject("ADODB.Recordset")
    SQL = "select * from [Data_Nhap$]" ''Tuy chon Mo Rong de lay du lieu
    Strcon = ("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ExcelPath _
                & ";Extended Properties=""Excel 12.0 Xml;HDR=Yes;"";")
    Rst.Open SQL, Strcon, 3, 1
    RecCount = Rst.RecordCount
    MsgBox RecCount
    If Not Rst.EOF Then
        Arr = Rst.getrows(RecCount)
        ReDim dArr(1 To UBound(Arr, 2) + 1, 1 To UBound(Arr, 1) + 1)
        For i = 0 To UBound(Arr, 2)
            k = k + 1
            For j = 0 To UBound(Arr, 1)
                dArr(k, j + 1) = Arr(j, i)
            Next j
        Next i
        Cells.ClearContents
        Range("A2").Resize(UBound(dArr, 1), UBound(dArr, 2)) = dArr
    End If
End Sub




Em cảm ơn anh kiều mạnh nhiều ạ
Cảm ơn anh về cái code trên ^^
 
Câu trả lời của Mình là ĐƯỢC .... TA không cần sử dụng connection hay chi tiết như sau ta vẫn có thể lấy dữ liệu lên Sheet hay mảng ok
Mã:
Set cn = CreateObject("ADODB.Connection")
Ta chỉ cần cơ bản 1 dòng sau là đủ để lấy dữ liệu lên Sheet hay lên Mảng
Mã:
Set rst = CreateObject("ADODB.Recordset")
Làm phiền @Hai Lúa Miền Tây cho xin 1 ý kiến cho bài 321 & 322 và bài này ... Mạnh Cảm Ơn
Xin nói thêm là nếu như ta dùng trên cùng 1 file thì không cần phải mở kết nối hay khai báo chuỗi kết nối.
Vậy phương pháp để lấy dữ liệu bằng cách này là như thế nào. Mời các bạn cho ý kiến nhé.
 
Tôn chỉ ở diễn đàn này là code ngắn và nhanh. Luật code rõ ràng, dễ kiểm soát lỗi là điều thứ yếu.
Với tôn chỉ ấy thì phương pháp "implicit connection" (để cho recordset nó tự kết nối lấy "đằng sau hậu trường") là phương pháp lý tưởng.
Hết.
 
Lần chỉnh sửa cuối:
Tôn chỉ ở diễn đàn này là code ngắn và nhanh. Luật code rõ ràng, dễ kiểm soát lỗi là điều thứ yếu.
Với tôn chỉ ấy thì phương pháp "implicit connection" (để cho recordset nó tự kết nối lấy "đằng sau hậu trường") là phương pháp lý tưởng.
Hết.
Không dùng kết nối nhé anh, code chưa chắc là ngắn gọn. Nhưng tốc độ thì hơn hẳn so với cách thông thường. Ở máy cà tàng của em thì với dữ liệu 1.048.576 dòng thì nó cho ra kết quả trong vòng 15~20 giây. Trong khi đó với cách mở kết nối thì hơn 80 giây mới có kết quả.
 
Web KT
Back
Top Bottom