Thảo luận về bài: ADO căn bản "Kết nối truy vấn CSDL từ file Excel đến file Access." (1 người xem)

  • Thread starter Thread starter ThuNghi
  • Ngày gửi Ngày gửi
Liên hệ QC

Người dùng đang xem chủ đề này

ThuNghi

Hãy cho rồi sẽ nhận!
Thành viên đã mất
Tham gia
16/8/06
Bài viết
3,808
Được thích
4,449
Để topic ADO căn bản: Kết nối truy vấn CSDL từ file Excel đến file Access. được liên tục, các bạn nếu có thảo luận xin thảo luận ở đây nhé

----------
Ta có file tblData gồm 20 field và hiển nhiên ta có thể có danh sách field Name như sau:
- ArrFieldName=Arr("A","B",...,"X")
Vậy có thế viết dòng code để lấy câu SQL chỉ lấy field 1,3, 12 thôi, tránh nhập sai tên field thì thế nào trong câu select sau.
Có thể viết code tạo câu SQL?
lsSQL = "SELECT SUPPLIER, [MATERIAL NAME], [COLOR NAME] " & _
"FROM tblData"
Cám ơn.
 
Chỉnh sửa lần cuối bởi điều hành viên:
Code kết nối với CSDL ví dụ file Access có tên là CSDL.mdb với Pass là 1234 , code kết nối sẽ như sau:

Mã:
Public cnn As New ADODB.Connection
Sub Moketnoi()
Set cnn = New ADODB.Connection
Dim strCNString As String
strCNString = "Data Source=" & ThisWorkbook.Path & "\CSDL.mdb"
With cnn
    [COLOR=#ff0000].Provider = "Microsoft Jet 4.0 OLE DB Provider"[/COLOR]
    [COLOR=#ff0000].ConnectionString = strCNString[/COLOR]
    .Properties("Jet OLEDB:Database Password") = "1234"
    [COLOR=#ff0000].CursorLocation = adUseClient[/COLOR]
    .Open

End With

End Sub
.
Nếu có thời gian Hai Lúa vui lòng giải thích thêm mấy dòng màu đỏ trên với
Mã:
.ConnectionString = strCNString
.CursorLocation = adUseClient
Mấy cái này dùng để làm gì? Không có nó có được không?
Còn cái này:
Mã:
.Provider = "Microsoft Jet 4.0 OLE DB Provider"
Liệu có liên quan đến version Office không?
 
Xin hỏi ngoài lề, sau đó nhờ SMod xóa.
Ta có file tblData gồm 20 field và hiển nhiên ta có thể có danh sách field Name như sau:
- ArrFieldName=Arr("A","B",...,"X")
Vậy có thế viết dòng code để lấy câu SQL chỉ lấy field 1,3, 12 thôi, tránh nhập sai tên field thì thế nào trong câu select sau.
Có thể viết code tạo câu SQL?

Cám ơn.
Anh thử như sau nhé.

ArrFieldName= Array("ID", "PONO", "W_HDATE", "TP", "[MATERIAL NAME]", "[SPEC 2]", "[COLOR NAME]", "POQTY", "INPUTQTY", "BALANCE", "UNIT", "PRICE", "M_UNIT", "AMOUNT", "ORIGIN", "SUPPLIER", "REMARK")
lsSQL = "SELECT " & ArrFieldName(15) & "," & ArrFieldName(4) & "," & ArrFieldName(6) & " " & _
"FROM tblData"

Nếu có thời gian Hai Lúa vui lòng giải thích thêm mấy dòng màu đỏ trên với
Mã:
.ConnectionString = strCNString '
.CursorLocation = adUseClient
Mấy cái này dùng để làm gì? Không có nó có được không?
Còn cái này:
Mã:
.Provider = "Microsoft Jet 4.0 OLE DB Provider"
Liệu có liên quan đến version Office không?

.ConnectionString = strCNString
Nó là

.ConnectionString ="Data Source=" & ThisWorkbook.Path & "\CSDL.mdb"

==> Đường dẫn kết nối với CSDL, nếu không có sẽ không được Thầy à.

.Provider = "Microsoft Jet 4.0 OLE DB Provider"
==> Thầy tham khảo link http://msdn.microsoft.com/en-us/library/office/aa140022(v=office.10).aspx

.CursorLocation = adUseClient
==> Thầy tham khảo link http://visualbasic.freetutes.com/learn-vb6-advanced/lesson9/p13.html
 
Lần chỉnh sửa cuối:
Hãy tiếp tục đề tài này đi Hai Lúa Miền Tây! Đề tài này rất hữu ích.

1./ Lấy tất cả các cột có trong bảng:

Mã:
Sub LayDuLieuTatCaCot()
On Error GoTo loi


Dim lsSQL As String: Dim rst As New ADODB.Recordset
If cnn.State <> 1 Then Moketnoi


    lsSQL = "SELECT * " & _
            "FROM tblData"
            
    rst.Open lsSQL, cnn, adOpenStatic, adLockReadOnly
    Cells.ClearContents
    [SIZE=4][COLOR=#0000cd][B]Range("A5").CopyFromRecordset [/B][/COLOR][COLOR=#ff0000][B]rst[/B][/COLOR][/SIZE]
    
rst.Close
Set rst = Nothing
cnn.Close
Set cnn = Nothing
Exit Sub
loi:
MsgBox Err.Description
End Sub

Giả sử rst chỉ có 1 giá trị và giá trị đó mình muốn nó hiện trên MsgBox mà không thông qua copy ở đâu đó, tức là chuyển trực tiếp giá trị có được từ rst lên MsgBox thì phải làm sao?
 
Chỉnh sửa lần cuối bởi điều hành viên:
1./ Hãy tiếp tục đề tài này đi Hai Lúa Miền Tây! Đề tài này rất hữu ích.
2./ Giả sử rst chỉ có 1 giá trị và giá trị đó mình muốn nó hiện trên MsgBox mà không thông qua copy ở đâu đó, tức là chuyển trực tiếp giá trị có được từ rst lên MsgBox thì phải làm sao?
3./ Em thử rồi Thầy ơi, bị lỗi!
1./ Nếu các anh chị quan tâm và không chê em hứa sẽ tiếp tục.
2./ Anh muốn cái MsgBox đó hiển thỉ giá trị 1 cột hay là nhiều cột, từng giá trị có trong từng cell?
3./ Cho em xem thử đoạn code của anh được không?
 
1./ Nếu các anh chị quan tâm và không chê em hứa sẽ tiếp tục.
2./ Anh muốn cái MsgBox đó hiển thỉ giá trị 1 cột hay là nhiều cột, từng giá trị có trong từng cell?
3./ Cho em xem thử đoạn code của anh được không?

HÀM KẾT NỐI:

Mã:
Option Explicit
Public gcnObj As Object
Public Const DBName = "CSDLTienLuong.mdb"

Global Const adStateClosed = 0
Global Const adStateOpen = 1
Global Const adStateConnecting = 2
Global Const adStateExecuting = 4
Global Const adStateFetching = 8
[COLOR=#006400]''=========================================================================================[/COLOR]

Function ConnectingString() As String
    Dim sAppPath As String
    sAppPath = ThisWorkbook.Path
    ConnectingString = "Driver={Microsoft Access Driver (*.mdb)}; Dbq=" & sAppPath & "\" & DBName & "; UID=Admin; PWD=;"
End Function
[COLOR=#006400]''=========================================================================================[/COLOR]

Function AccConn() As Boolean
    On Error GoTo ErrorHandle
    Set gcnObj = CreateObject("ADODB.Connection")
    With gcnObj
        .Mode = 3
        .ConnectionTimeout = 30
        .CursorLocation = 3
        .ConnectionString = ConnectingString()
        .Open
    End With
    
    AccConn = True
    gcnObj.Close

ErrorExit:
    Exit Function
    
ErrorHandle:
    AccConn = False
    Err.Clear
    Resume ErrorExit
End Function

THỦ TỤC MUỐN GÁN VÀO MSGBOX:

Mã:
Sub AccToExKiemTraPhep()
    On Error Resume Next
    If AccConn = False Then
        MsgBox "Loi ket noi", vbOKOnly + vbExclamation, "THÔNG BÁO"
    Else
        On Error GoTo ErrorHandle
        
        Dim sSQL As String
        Dim adoCommand As Object, oRs As Object
        
        gcnObj.Open
                      
        sSQL = "SELECT Sum(NgayPhep) " _
             & "FROM TB_LuongThucTe " _
             & "WHERE MaTinhLuong = 'TM00001'"
        
        Set adoCommand = CreateObject("ADODB.Command")
        
        With adoCommand
            .CommandType = 1
            .ActiveConnection = gcnObj
            .CommandText = sSQL
        End With
            
        Set oRs = CreateObject("ADODB.Recordset")
        
        oRs.Open adoCommand, , 3, 4
        
        If oRs.EOF Then
            MsgBox "Không có record nào!", vbOKOnly + vbInformation, "THÔNG BÁO"
        Else

[COLOR=#006400]            [B]''THAY VÌ:[/B]
            ''================================================================[/COLOR]

[COLOR=#0000cd]            Dim Phep As Range
            Set Phep = Sheet1.Range("B1")
                Phep.Clear[/COLOR]
        
[COLOR=#0000cd]            Phep.CopyFromRecordset oRs
            MsgBox "So ngay phep da nghi la: " & Phep
            Phep.Clear
 [/COLOR]           
[B][COLOR=#006400]            ''THÌ: (KHÔNG THÔNG QUA BIẾN Phep)
[/COLOR][/B][COLOR=#006400]            ''================================================================[/COLOR][B][COLOR=#006400]
           [/COLOR][COLOR=#ff0000] ''MsgBox "So ngay phep da nghi la: " & oRs[/COLOR][COLOR=#006400]
   [/COLOR][/B]     End If
            
ErrorHandle:
        Set adoCommand = Nothing
        Set oRs = Nothing
        Set Phep = Nothing
        If Not gcnObj Is Nothing Then
            If (gcnObj.State And adStateOpen) = adStateOpen Then
                gcnObj.Close
            End If
            Set gcnObj = Nothing
        End If
    End If
End Sub
 

File đính kèm

Lần chỉnh sửa cuối:
Hãy tiếp tục đề tài này đi Hai Lúa Miền Tây! Đề tài này rất hữu ích.



Giả sử rst chỉ có 1 giá trị và giá trị đó mình muốn nó hiện trên MsgBox mà không thông qua copy ở đâu đó, tức là chuyển trực tiếp giá trị có được từ rst lên MsgBox thì phải làm sao?

Góp chút với A Dom nha,
1/Nếu biết chắc rst chỉ có 1 giá trị (1 record) thì có thể

Mã:
...........
rst.movefirst
msgbox rst.fields(0)
...........

(Mình chưa test vì không có mẫu, lâu quá không nhớ là fields(0) hay Fields(1) nữa )

2/Nếu không chắc thì phải làm như sau:

Mã:
.........................
dim Tb as string
rst.movefist
do while not rst.eof()
tb=tb& rst.fields(0) & chr(10)
rst.movenext
loop
msgbox tb
........................

Code mình viết tại khung trả lời có thể không chuẩn, bạn hiệu chỉnh.
 
Theo tôi biết kết quả Rec là 1 arr thì sao chỉ lấy thành 1 biến được.
Code trên có thể vận dụng chút xíu
PHP:
if oRs.EOF Then
            MsgBox "Không có record nào!", vbOKOnly + vbInformation, "THÔNG BÁO"
        Else
          Dim Arr
          If oRs.RecordCount = 1 Then
            Arr = oRs.getrows
            MsgBox "So ngay phep da nghi la: " & Arr(0, 0)
          Else
            Exit Sub
          End If
 
Theo tôi biết kết quả Rec là 1 arr thì sao chỉ lấy thành 1 biến được.
Code trên có thể vận dụng chút xíu
PHP:
if oRs.EOF Then
            MsgBox "Không có record nào!", vbOKOnly + vbInformation, "THÔNG BÁO"
        Else
          Dim Arr
          If oRs.RecordCount = 1 Then
            Arr = oRs.getrows
            MsgBox "So ngay phep da nghi la: " & Arr(0, 0)
          Else
            Exit Sub
          End If

OK, theo cách của anh thì làm ra đúng kết quả. Chỉ vì mình nghĩ 1 giá trị thì nó không phải là mảng nên mình không gán vào (giờ mới ngộ ra nhiều vấn đề hihiil).

Sau khi kiểm tra và test thử, cả 2 cách của anh Sealand và anh ThuNghi đều cho ra kết quả đúng:

Anh Sealand:

PHP:
                oRs.MoveFirst
                MsgBox "So ngay phep da nghi la: " & oRs.Fields(0)


Anh ThuNghi:

PHP:
            Dim SoNgayPhep As Variant
                SoNgayPhep = oRs.GetRows
                MsgBox "So ngay phep da nghi la: " & SoNgayPhep(0, 0)

-----------------------------------------------------

Thử về thời gian thì thấy cách của Anh Seland là nhanh hơn, có lẽ do nó thực hiện trực tiếp.
 
Chỉnh sửa lần cuối bởi điều hành viên:
Lần chỉnh sửa cuối:
Hic, em làm thử như sau:

PHP:
Sub LayDuLieuDK()
On Error GoTo loi
Dim lsSQL As String: Dim rst As New ADODB.Recordset
If cnn.State <> 1 Then Moketnoi
    lsSQL = "SELECT * " & _
            "FROM tblData " & _
            "Where [balance] <0 and [origin] like 'VIETNAM'"
            
    rst.Open lsSQL, cnn, adOpenStatic, adLockReadOnly
    Cells.ClearContents
    Range("A5").CopyFromRecordset rst
    
rst.Close
Set rst = Nothing
cnn.Close
Set cnn = Nothing
Exit Sub
loi:
MsgBox Err.Description
End Sub
 
Thảo luận

Vì mình có thắc mắc về mệnh đề HAVING, nên đã tìm hiểu như sau:

The HAVING Clause

The HAVING clause was added to SQL because the WHERE keyword could not be used with aggregate functions.

Mệnh đề HAVING được thêm vào SQL bởi vì từ khóa WHERE không có khả năng dùng được với chức năng tổng hợp.

Cú pháp SQL HAVING:

Mã:
SELECT column_name, aggregate_function(column_name)
FROM table_name
WHERE column_name operator value
GROUP BY column_name
HAVING aggregate_function(column_name) operator value
 
Hic, em làm thử như sau:

PHP:
Sub LayDuLieuDK()
On Error GoTo loi
Dim lsSQL As String: Dim rst As New ADODB.Recordset
If cnn.State <> 1 Then Moketnoi
    lsSQL = "SELECT * " & _
            "FROM tblData " & _
            "Where [balance] <0 and [origin] like 'VIETNAM'"
            
    rst.Open lsSQL, cnn, adOpenStatic, adLockReadOnly
    Cells.ClearContents
    Range("A5").CopyFromRecordset rst
    
rst.Close
Set rst = Nothing
cnn.Close
Set cnn = Nothing
Exit Sub
loi:
MsgBox Err.Description
End Sub

Hoàn toàn chính xác.
Cũng với dữ liệu như nói ở trên các bạn tiếp tục lọc những loại vật tư của VIETNAM và có ngày W_HDATE trong khoảng từ ngày 08/06/2012 đến 20/07/2012
 
Vì mình có thắc mắc về mệnh đề HAVING, nên đã tìm hiểu như sau:

The HAVING Clause

The HAVING clause was added to SQL because the WHERE keyword could not be used with aggregate functions.

Mệnh đề HAVING được thêm vào SQL bởi vì từ khóa WHERE không có khả năng dùng được với chức năng tổng hợp.

Cú pháp SQL HAVING:

Mã:
SELECT column_name, aggregate_function(column_name)
FROM table_name
WHERE column_name operator value
GROUP BY column_name
HAVING aggregate_function(column_name) operator value
Như em đã đề cập Topic bên kia, mình có thể dùng Where nhé, Sao ở trên vừa where và vừa having? 1 loại là được rồi. Cái này em chưa đề cập là vì chưa đến phần tính toán.
 
Như em đã đề cập Topic bên kia, mình có thể dùng Where nhé, Sao ở trên vừa where và vừa having? 1 loại là được rồi. Cái này em chưa đề cập là vì chưa đến phần tính toán.

Uh, có thể mình "cầm đèn chạy trước ô tô", Hai lúa xem bài này xong thì xóa bài này và bài trước luôn nhé!

Mình trích từ trang này, tham khảo và thực hành trên file của Hai Lúa sẽ rất hay đấy:

http://www.w3schools.com/sql/sql_having.asp
 
Lần chỉnh sửa cuối:
Mình trích từ trang này, tham khảo và thực hành trên file của Hai Lúa sẽ rất hay đấy:

http://www.w3schools.com/sql/sql_having.asp
Em ví dụ trên file em nhé. Dùng where không dùng having vẫn được.

SELECT ORIGIN, Sum(AMOUNT) AS SumOfAMOUNT, TP
FROM tblData
WHERE ORIGIN Like 'KOREA' AND TP Like 'A'
GROUP BY ORIGIN, TP;

Còn dùng Having sẽ như sau:

SELECT ORIGIN, Sum(AMOUNT) AS SumOfAMOUNT, TP
FROM tblData
GROUP BY ORIGIN, TP
having ORIGIN Like 'KOREA' AND TP Like 'A'
 
Lần chỉnh sửa cuối:
Lần chỉnh sửa cuối:
Em ví dụ trên file em nhé. Dùng where không dùng having vẫn được.



Còn dùng Having sẽ như sau:
Vậy HLMT làm thử
PHP:
SELECT ORIGIN, Sum(AMOUNT) AS SumOfAMOUNT, TP
 FROM tblData
 WHERE ORIGIN Like 'KOREA' AND TP Like 'A'
 GROUP BY ORIGIN, TP;
Lọc sum(Amount) > 1000 thì phải dùng having , dùng where hình như kg OK
PHP:
SELECT ORIGIN, Sum(AMOUNT) AS SumOfAMOUNT, TP
 FROM tblData
 WHERE ORIGIN Like 'KOREA' AND TP Like 'A' and sum(AMOUNT) > 1000
 GROUP BY ORIGIN, TP;
 
Vậy HLMT làm thử
PHP:
SELECT ORIGIN, Sum(AMOUNT) AS SumOfAMOUNT, TP
 FROM tblData
 WHERE ORIGIN Like 'KOREA' AND TP Like 'A'
 GROUP BY ORIGIN, TP;
Lọc sum(Amount) > 1000 thì phải dùng having , dùng where hình như kg OK
PHP:
SELECT ORIGIN, Sum(AMOUNT) AS SumOfAMOUNT, TP
 FROM tblData
 WHERE ORIGIN Like 'KOREA' AND TP Like 'A' and sum(AMOUNT) > 1000
 GROUP BY ORIGIN, TP;
Hoàn toàn đúng thế anh à, do HLMT không chịu kiểm tra kỹ trước khi viết. Anh muốn lọc theo điều kiện sau khi tính toán? Cột Sum(AMOUNT) là sau khi tính toán, do vậy nó phải nằm sau cái GroupBy, mà nằm sau Group By thì phải dùng Having.
P/S: HLMT nên kiểm tra kỹ trước khi viết nhé.
 
Bay giờ em muốn tính tổng số lượng của các mục B4; III; V; VII; VIII của hồ sơ có maHS là T10 với điều kiện là Dottrinh=2. thì câu lệnh viết như thế nào. mong các anh chị hướng dẫn giúp.
MaHS​
|
Mamuc​
|
SoLuong​
|
Dottrinh​
|
T10|A2|
300​
|
1​
|
T10|B4|
3666​
|
1​
|
T10|B4|
4082​
|
1​
|
T10|IV|
1​
|
1​
|
T10|VII|
1​
|
1​
|
T10|VII|
3​
|
1​
|
T12|B3|
2400​
|
1​
|
T12|B4|
4733​
|
1​
|
T12|B4|
1529​
|
1​
|
T12|III|
63,75​
|
1​
|
T12|IV|
0,785​
|
1​
|
T12|IV|
61​
|
1​
|
T12|IV|
16,96​
|
1​
|
T12|V|
1​
|
1​
|
T12|V|
3​
|
1​
|
T12|VII|
2400​
|
1​
|
T12|VII|
4​
|
1​
|
T10|B4|
1030​
|
2​
|
T10|III|
55,83​
|
2​
|
T10|V|
30​
|
2​
|
T10|V|
25​
|
2​
|
T10|VII|
3190​
|
2​
|
T10|VIII| |
2​
|
 

File đính kèm

Lần chỉnh sửa cuối:
Bay giờ em muốn tính tổng số lượng của các mục B4; III; V; VII; VIII của hồ sơ có maHS là T10 với điều kiện là Dottrinh=2. thì câu lệnh viết như thế nào. mong các anh chị hướng dẫn giúp.
2​
Có phải bạn muốn kết quả như bên dưới:

1.jpg
 
Bay giờ em muốn tính tổng số lượng của các mục B4; III; V; VII; VIII của hồ sơ có maHS là T10 với điều kiện là Dottrinh=2. thì câu lệnh viết như thế nào. mong các anh chị hướng dẫn giúp.
Dùng tạm code này thử, đang nghĩ cách rút gọn phần or.
PHP:
Sub SumSQL()
Dim strPath$, mySQL$
Dim Cnn As New ADODB.Connection
Dim Rcs As New ADODB.Recordset
'-------------------------------------------------------------------------
'Tuy chon Loai BC combobox phu hop SQL text sau menh de Where
strPath = ThisWorkbook.FullName
Set Cnn = New ADODB.Connection
'Tao Ket noi voi file du lieu nguon:
Cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strPath & _
                            ";Persist Security Info=False; Extended Properties=Excel 8.0;"
'---------------------------------------------------------------------------
mySQL = "SELECT * FROM [DATA$]" & Chr(10)
mySQL = mySQL & "where MaHS='T10' AND Dottrinh=2 and" & Chr(10)
mySQL = mySQL & "(Mamuc='B4' or Mamuc='III' or Mamuc='V' or Mamuc='VII' or Mamuc='VIII')" & Chr(10)
'B4; III; V; VII; VIII
Rcs.Open mySQL, Cnn, adOpenKeyset, adLockOptimistic
'---------------------------------------------------------------------------
With Sheets("Report")
  .Range("A2:D100").ClearContents
  .[A2].CopyFromRecordset Rcs
End With
'Refresh lai hai bien cnEx va Rcs:
Rcs.Close: Set Rcs = Nothing
Cnn.Close: Set Cnn = Nothing
End Sub
Thay thế câu
PHP:
mySQL = mySQL & "(Mamuc='B4' or Mamuc='III' or Mamuc='V' or Mamuc='VII' or Mamuc='VIII')" & Chr(10)
Thành
PHP:
mySQL = mySQL & "instr('B4; III; V; VII; VIII',Mamuc)"
 

File đính kèm

Lần chỉnh sửa cuối:
Cám ơn anh nhiều.

Nhưng sao mục V không có cộng gọp lại anh Tuấn ơi
giống như kết quả của " ExcelCongCuTuyetVoiCuaBan".

Với lại em muốn lấy từng Recordset để đưa số lượng từng mã mục vào từng textbox nên "CopyFromRecordset Rcs" thì chắc không đưa vào được rồi
 
Lần chỉnh sửa cuối:
PHP:
Cám ơn anh nhiều.

Nhưng sao mục V không có cộng gọp lại anh Tuấn ơi
giống như kết quả của " ExcelCongCuTuyetVoiCuaBan".

Với lại em muốn lấy từng Recordset để đưa số lượng từng mã mục vào từng textbox nên "CopyFromRecordset Rcs" thì chắc không đưa vào được rồi
Sửa câu SQL lại
PHP:
mySQL = "SELECT MaHS, Mamuc, sum(Soluong) FROM [DATA$]" & Chr(10)
mySQL = mySQL & "where MaHS='T10' AND Dottrinh=2 and" & Chr(10)
mySQL = mySQL & "instr('B4; III; V; VII; VIII',Mamuc)" & Chr(10)
mySQL = mySQL & "group by MaHs, Mamuc, Dottrinh;"
Còn muốn đưa vào gì thì dùng for i và Arr=rcs.GetRows
 
Cám ơn anh nhiều.

Nhưng sao mục V không có cộng gọp lại anh Tuấn ơi
giống như kết quả của " ExcelCongCuTuyetVoiCuaBan".

Với lại em muốn lấy từng Recordset để đưa số lượng từng mã mục vào từng textbox nên "CopyFromRecordset Rcs" thì chắc không đưa vào được rồi
Câu lệnh:

SELECT MaHS, Mamuc, Sum(SoLuong)
FROM [Sheet1$]
WHERE Dottrinh=2
GROUP BY MaHS, Mamuc;
 
Lần chỉnh sửa cuối:
Hình như còn thiếu 1 DK là T10 anh à.

Vậy sửa lại như vầy (dựa vào file của anh ThuNghi):

Mã:
    mySQL = "SELECT MaHS, Mamuc, Sum(SoLuong) " _
          & "FROM [DATA$] " _
          & "WHERE Dottrinh = 2 AND MaHS='T10' " _
          & "AND (Mamuc='B4' Or Mamuc='III' Or Mamuc='V' " _
          & "Or Mamuc='VII' Or Mamuc='VIII') " _
          & "GROUP BY MaHS, Mamuc"

hoặc:

Mã:
    mySQL = "SELECT MaHS, Mamuc, Sum(SoLuong) " _
          & "FROM [DATA$] " _
          & "WHERE Dottrinh = 2 " _
          & "GROUP BY MaHS, Mamuc " _
          & "HAVING MaHS='T10' AND (Mamuc ='B4' " _
          & "Or Mamuc='III' Or Mamuc='V' " _
          & "Or Mamuc='VII' Or Mamuc='VIII');"

Còn tác giả muốn chuyển giá trị vào TextBox như thế nào thì đưa file mẫu lên nhé!
 
Lần chỉnh sửa cuối:
Với bài vừa rồi có nhiều điều kiện OR và nếu điều kiện nhiều hơn nữa thì mình OR mệt xỉu luôn!

Vì vậy có ý kiến là nên dùng vòng lặp sẽ hay hơn:

Mã:
        Dim arr, str As String, i As Long
        arr = Array("'III'", "'V'", "'VII'", "'VIII'")
        str = "Dottrinh = 2 AND MaHS='T10' AND (Mamuc='B4'"
        
        For i = 0 To UBound(arr)
            str = str & " Or Mamuc=" & arr(i)
        Next
        
        str = str & ") "
    
    
[COLOR=#0000cd]    mySQL = "SELECT MaHS, Mamuc, Sum(SoLuong) " _
          & "FROM [DATA$] " _
          & "WHERE " & [/COLOR][COLOR=#ff0000][B]str [/B][/COLOR][COLOR=#0000cd]_
          & "GROUP BY MaHS, Mamuc"
          [/COLOR]
 
Với bài vừa rồi có nhiều điều kiện OR và nếu điều kiện nhiều hơn nữa thì mình OR mệt xỉu luôn!

Vì vậy có ý kiến là nên dùng vòng lặp sẽ hay hơn:

Mã:
        Dim arr, str As String, i As Long
        arr = Array("'III'", "'V'", "'VII'", "'VIII'")
        str = "Dottrinh = 2 AND MaHS='T10' AND (Mamuc='B4'"
        
        For i = 0 To UBound(arr)
            str = str & " Or Mamuc=" & arr(i)
        Next
        
        str = str & ") "
    
    
[COLOR=#0000cd]    mySQL = "SELECT MaHS, Mamuc, Sum(SoLuong) " _
          & "FROM [DATA$] " _
          & "WHERE " & [/COLOR][COLOR=#ff0000][B]str [/B][/COLOR][COLOR=#0000cd]_
          & "GROUP BY MaHS, Mamuc"
          [/COLOR]
Sao kg dùng Instr cho khỏe
vd
PHP:
sTxt = "B4;III;V;VII;VIII"

PHP:
mySQL = "SELECT MaHS, Mamuc, sum(Soluong) FROM [DATA$]" & Chr(10)
mySQL = mySQL & "where MaHS='T10' AND Dottrinh=2 and" & Chr(10)
mySQL = mySQL & "instr('" & sTxt & "',Mamuc)" & Chr(10)
 
Sao kg dùng Instr cho khỏe
vd
PHP:
sTxt = "B4;III;V;VII;VIII"


Nghĩ cũng lạ, mình để dấu chấm phẩy, hay để dấu phẩy, máy nó hiểu tất tần tật!

PHP:
    sTxt = "B4,III,V,VII,VIII"

Mà Anh ThuNghi có thể giải thích cho em biết hàm InStr này khi ứng dụng với code này được không?
 
Lần chỉnh sửa cuối:
Nghĩ cũng lạ, mình để dấu chấm phẩy, hay để dấu phẩy, máy nó hiểu tất tần tật!

PHP:
    sTxt = "B4,III,V,VII,VIII"

Mà Anh ThuNghi có thể giải thích cho em biết hàm InStr này khi ứng dụng với code này được không?
Khổ ghê, hàm Instr trong VBA chớ gì.
PHP:
    sTxt = "B4,III,V,VII,VIII"
Nếu thay dấu , = " " thì nó cũng OK
Mục địch để phân biệt III hay VIII thôi.
Đúng ra phải có thêm tham số 0,1 hay 2 nữa
Chớ dòng trên nó sẽ tìm thấy III trong VIII nên sẽ sai đó.

Hiện tại chưa biết cách vận dụng thông số compare nên vận dụng như sau thì mới phân biệt III và VIII trong hàm instr.
PHP:
sTxt = "B4;III;V;VII;VIII;"
và câu SQL như sau:
PHP:
MySql = MySql & "instr('" & sTxt & "',Mamuc & ';' )" & Chr(10)
Thêm 1 dấu ; để phân biệt III; và VIII;
 
Lần chỉnh sửa cuối:
Hình như là còn bài số #15 của anh hai lúa chưa được giải đáp.
Nhờ HL giải thích giúp, nếu dùng biến trung gian eD và fD thì OK nhưng dùng thẳng CVDate(fDate) và CVDate(eDate) thì kg được.
PHP:
Sub LayDuLieuDK2()
On Error GoTo loi
Dim lsSQL As String: Dim rst As New ADODB.Recordset
Dim sXuatXu$, fDate$, eDate$
Dim eD&, fD&
sXuatXu = "VietNam"
eDate = "20/07/2012"
fDate = "08/06/2012"
eD = CVDate(eDate): fD = CVDate(fDate)
If cnn.State <> 1 Then Moketnoi
  lsSQL = "SELECT *" & Chr(10)
  lsSQL = lsSQL & "FROM tblData" & Chr(10)
  lsSQL = lsSQL & "Where [origin] LIKE '" & sXuatXu & "'" & Chr(10)
  lsSQL = lsSQL & "and [W_HDATE] >=" & fD & Chr(10)
  lsSQL = lsSQL & "and [W_HDATE] <=" & eD
  rst.Open lsSQL, cnn, adOpenStatic, adLockReadOnly
With Sheets("BC")
  .Cells.ClearContents
  .Range("A5").CopyFromRecordset rst
End With
rst.Close
Set rst = Nothing
cnn.Close
Set cnn = Nothing
Exit Sub
loi:
MsgBox Err.Description
End Sub
 
Nhờ HL giải thích giúp, nếu dùng biến trung gian eD và fD thì OK nhưng dùng thẳng CVDate(fDate) và CVDate(eDate) thì kg được.
PHP:
Sub LayDuLieuDK2()
On Error GoTo loi
Dim lsSQL As String: Dim rst As New ADODB.Recordset
Dim sXuatXu$, fDate$, eDate$
Dim eD&, fD&
sXuatXu = "VietNam"
eDate = "20/07/2012"
fDate = "08/06/2012"
eD = CVDate(eDate): fD = CVDate(fDate)
If cnn.State <> 1 Then Moketnoi
  lsSQL = "SELECT *" & Chr(10)
  lsSQL = lsSQL & "FROM tblData" & Chr(10)
  lsSQL = lsSQL & "Where [origin] LIKE '" & sXuatXu & "'" & Chr(10)
  lsSQL = lsSQL & "and [W_HDATE] >=" & fD & Chr(10)
  lsSQL = lsSQL & "and [W_HDATE] <=" & eD
  rst.Open lsSQL, cnn, adOpenStatic, adLockReadOnly
With Sheets("BC")
  .Cells.ClearContents
  .Range("A5").CopyFromRecordset rst
End With
rst.Close
Set rst = Nothing
cnn.Close
Set cnn = Nothing
Exit Sub
loi:
MsgBox Err.Description
End Sub

Em nghĩ anh rào 2 dấu # ở hai đầu ngày ( #dd/mm/yyyy# )
 
Đã test với rào # rồi. Nếu # thì nó sẽ chưa hiểu dd/mm/yyyy mà nó hiểu mm/dd/yyyy
Trong file gồm có các code.

Đúng vậy, cấu trúc của nó luôn là #M/D/Y#. Tại quen tay nên đánh nhầm.

(Cấu trúc month/day/year này theo dạng quy chuẩn của Microsoft Jet Database Engine)
 
Lần chỉnh sửa cuối:
Đã test với rào # rồi. Nếu # thì nó sẽ chưa hiểu dd/mm/yyyy mà nó hiểu mm/dd/yyyy
Trong file gồm có các code.

Với dạng bài này, nếu dùng trực tiếp điều kiện thì code sẽ như vầy:

Mã:
Sub LayDuLieu02_1()
    On Error GoTo Loi
    Dim lsSQL As String: Dim rst As New ADODB.Recordset
    
    If cnn.State <> 1 Then Moketnoi
    
[COLOR=#0000cd][B]    lsSQL = "SELECT * FROM tblData " _
          & "WHERE [ORIGIN] = 'VIETNAM' " _
          & "AND [W_HDATE] >= #6/8/12# " _
          & "AND [W_HDATE] <= #7/20/12#;"
[/B] [/COLOR]   
    rst.Open lsSQL, cnn, adOpenStatic, adLockReadOnly
    
    With Sheets("BC")
        .Cells.ClearContents
        .Range("A5").CopyFromRecordset rst
    End With
    
    rst.Close
    Set rst = Nothing
    cnn.Close
    Set cnn = Nothing
    Exit Sub
    
Loi:
    MsgBox Err.Description
End Sub

Tuy nhiên, tôi thích đưa dữ liệu gián tiếp hơn, bằng cách thông qua các INPUTBOX, nhằm đa dạng hóa điều kiện nhập vào:

Cũng giống như các Parameter của Access, tôi dùng InputBox (Nếu dùng trực tiếp trên Access thì không cần đặt InputBox làm gì, nhưng với ADO thì không làm sao cho nó hiển thị cái Parameter này nên phải dùng đến InputBox).

Mã:
Sub LayDuLieu02_2()
    On Error GoTo Loi
    Dim lsSQL As String: Dim rst As New ADODB.Recordset
    Dim IptXuatXu As String, IptfDate As Date, IpteDate As Date
    
[B][COLOR=#0000cd]    IptXuatXu = InputBox("ORIGIN", "INPUT ORIGIN")
    
    If IptXuatXu = "" Then Exit Sub
    
    IptfDate = InputBox("START DATE", "INPUT START DATE")
    
    IpteDate = InputBox("END DATE", "INPUT END DATE")
 [/COLOR][/B]   
    If cnn.State <> 1 Then Call Moketnoi
    
[COLOR=#800080]    lsSQL = "SELECT * FROM tblData " _
          & "WHERE [ORIGIN] LIKE [B]'[/B][/COLOR][B][COLOR=#ff0000]%[/COLOR][/B][COLOR=#800080][B]"[/B] & IptXuatXu & [B]"[/B][/COLOR][B][COLOR=#ff0000]%[/COLOR][/B][COLOR=#800080][B]'[/B] " _
          & "AND [W_HDATE] >= #" & Format(IptfDate, "m/d/yyyy") & "# " _
          & "AND [W_HDATE] <= #" & Format(IpteDate, "m/d/yyyy") & "#;"[/COLOR]
        
    rst.Open lsSQL, cnn, adOpenStatic, adLockReadOnly
    
    With Sheets("BC")
      .Cells.ClearContents
      .Range("A5").CopyFromRecordset rst
    End With
    
    rst.Close
    Set rst = Nothing
    cnn.Close
    Set cnn = Nothing

Exit Sub

Loi:
    MsgBox Err.Description
End Sub

Khi các InputBox nhập ngày tháng, với năm hiện hành chúng ta chỉ cần điền [ngày/tháng] (theo kiểu mặc định của hệ thống nếu ngày trước tháng sau, hoặc ngược lại), nhưng nếu điều kiện không phải năm hiện hành thì ta điền đấy đủ [ngày/tháng/năm] (theo cấu trúc mặc định hệ thống).

VỚI SQL TRONG ACCESS CHỈ ĐƠN GIẢN NHƯ VẦY:

Mã:
SELECT *FROM tblData
WHERE [ORIGIN] LIKE [B]'[COLOR=#ff0000]*[/COLOR]'[/B] & [XUAT XU:] & [B]'[COLOR=#ff0000]*[/COLOR]'[/B]
AND [W_HDATE]>=[TU NGAY:] 
AND [W_HDATE]<=[DEN NGAY:];

Các bạn để ý thấy tôi sử dụng dấu phần trăm (%) và dấu sao (*), với 2 dấu này, với toán tử LIKE được xem như là dò tìm cụm từ nào đó trong toàn bộ điều kiện cần tìm.

VD: Cần tìm VIETNAM ta có thể gõ: VIE hoặc NAM hoặc IET v.v...

Tại sao lúc thì % lúc thì * , là vì với Access ta chỉ được dùng dấu * cho SQL thôi, còn với ADO thì ta phải dùng dấu % nó mới chạy đúng như ta mong đợi.
 
lsSQL = "SELECT * FROM tblData " _ & "WHERE [ORIGIN] LIKE '%" & IptXuatXu & "%' " _ & "AND [W_HDATE] >= #" & Format(IptfDate, "m/d/yyyy") & "# " _ & "AND [W_HDATE] <= #" & Format(IpteDate, "m/d/yyyy") & "#;"
khi thực hiện trong access đã chọn format theo kiểu"dd/mm/yyyy", nhưng trong Excel khi chọn format kiểu "dd/mm/yyyy" thì lại không select được vậy bác nghĩa?
 
lsSQL = "SELECT * FROM tblData " _ & "WHERE [ORIGIN] LIKE '%" & IptXuatXu & "%' " _ & "AND [W_HDATE] >= #" & Format(IptfDate, "m/d/yyyy") & "# " _ & "AND [W_HDATE] <= #" & Format(IpteDate, "m/d/yyyy") & "#;"
khi thực hiện trong access đã chọn format theo kiểu"dd/mm/yyyy", nhưng trong Excel khi chọn format kiểu "dd/mm/yyyy" thì lại không select được vậy bác nghĩa?


Nếu bạn dùng code đó, bạn gõ ngày tháng bình thường vào InputBox theo định dạng của hệ thống máy tính (Control Panel) của bạn. Ví dụ, tôi cài kiểu ngày tháng trong máy là dd/mm/yyyy thì tôi gõ trong InputBox là dd/mm/yyyy, còn tôi cài hệ thống là mm/dd/yyyy thì tôi gõ trong InputBox là mm/dd/yyyy.

Bạn phải nhập đúng theo kiểu ngày mà hệ thống máy tính của bạn đã cài đặt. Còn việc xử lý dữ liệu sẽ thuộc về code, không liên quan gì hết vì nó đã định dạng lại cho đúng chuẩn: Format(IpteDate, "m/d/yyyy")


Dù là trong Access, hay Excel thì cấu trúc về ngày tháng trong SQL cũng không thay đổi:

#M/D/YYYY#

Xem lại bại này: http://www.giaiphapexcel.com/forum/...ile-Excel-đến-file-Access&p=429179#post429179
 
Lần chỉnh sửa cuối:
Khi làm việc với dữ liệu ngày trong ADO, kinh nghiệm của tôi là nên dùng hàm DateSerial để chuyển định dạng ngày và đưa vào câu truy vấn.

Lê Văn Duyệt
 
Với Excel có thể làm điều tôi sắp trình bày bằng VBA dễ dàng. Nhưng với Access phải làm câu lệnh ADO thế nào?

Giả sử tôi có một Table NhanVien với 4 field: MaNV, TenNV, NoiLamViec, SoLuong

Tôi muốn đại loại như vầy:

SELECT MaNV, TenNV, Sum(SoLuong) AS TongSoLuong, [NoiLamViec] & " (" & [SoLuong] & ")" AS DienGiai
FROM NhanVien
GROUP BY MaNV, TenNV;


Ví dụ Nhân viên Y có mã XXX, làm việc tại 4 nơi (có 4 records cho mỗi nơi), tại A có số lượng là 4, B là 5, C là 6 và D là 7

Thì kết quả sẽ là:

MaNV: XXX
TenNV: YYY
TongSoLuong: 22
DienGiai: A (4), B (5), C (6), D (7)

Kết quả cột DienGiai thì phải làm thế nào? Xin được hướng dẫn.

Cảm ơn rất nhiều!

===================================

Đã post lại File ở bài này: http://www.giaiphapexcel.com/forum/...ile-Excel-đến-file-Access&p=431460#post431460
 
Lần chỉnh sửa cuối:
Cái này để cho HLMT. :)

Lê Văn Duyệt
 
Với Excel có thể làm điều tôi sắp trình bày bằng VBA dễ dàng. Nhưng với Access phải làm câu lệnh ADO thế nào?

Giả sử tôi có một Table NhanVien với 4 field: MaNV, TenNV, NoiLamViec, SoLuong

Tôi muốn đại loại như vầy:

SELECT MaNV, TenNV, Sum(SoLuong) AS TongSoLuong, [NoiLamViec] & " (" & [SoLuong] & ")" AS DienGiai
FROM NhanVien
GROUP BY MaNV, TenNV;


Ví dụ Nhân viên Y có mã XXX, làm việc tại 4 nơi (có 4 records cho mỗi nơi), tại A có số lượng là 4, B là 5, C là 6 và D là 7

Thì kết quả sẽ là:

MaNV: XXX
TenNV: YYY
TongSoLuong: 22
DienGiai: A (4), B (5), C (6), D (7)

Kết quả cột DienGiai thì phải làm thế nào? Xin được hướng dẫn.

Cảm ơn rất nhiều!
Không thể group được trong trường hợp này đâu anh.

SELECT NhanVien.MaNV, NhanVien.TenNV, NhanVien.SoLuong AS TongSoLuong, ([NoiLamViec]) & " (" & [TongSoLuong] & ")" AS DienGiai
FROM NhanVien;
Nếu muốn group thì tạo 1 cái Query nữa tham chiếu với query trên.
 
Nếu nối chuổi giống như anh thì nó ra kq là 70 dòng, sau khi group thì vẫn còn 70 dòng, chứng tỏ dữ liệu không có cái nào trùng.
Để đơn giản vấn đề, mình gửi lại file với 2 mã và 8 records. Nếu thực hiện xong thủ tục, kết quả mong muốn sẽ là:
MaNV ....|TenNV .....................|.TongSoLuong | DienGiai
HTN001 ..| Hoàng Trọng Nghĩa 01 | ........ 35 .......| Vị trí 1 (10), Vị trí 2 (12), Vị trí 3 (13)
HTN002 ..| Hoàng Trọng Nghĩa 02 | ........ 30 .......| Vị trí 1 (2), Vị trí 2 (4), Vị trí 3 (6), Vị trí 4 (8), Vị trí 5 (10)
 

File đính kèm

Lần chỉnh sửa cuối:
Để đơn giản vấn đề, mình gửi lại file với 2 mã và 8 records. Nếu thực hiện xong thủ tục, kết quả mong muốn sẽ là:
MaNV ....|TenNV .....................|.TongSoLuong | DienGiai
HTN001 ..| Hoàng Trọng Nghĩa 01 | ........ 35 .......| Vị trí 1 (10), Vị trí 2 (12), Vị trí 3 (13)
HTN002 ..| Hoàng Trọng Nghĩa 02 | ........ 30 .......| Vị trí 1 (2), Vị trí 2 (4), Vị trí 3 (6), Vị trí 4 (8), Vị trí 5 (10)
Nếu Nghĩa là trên ex và dùng ADO thì sẽ làm thế nào.
A chỉ có thể lấy data = ADO sau đó xử lý arr thì có thể ra được.
Còn câu SQL mà có kq vậy thì thua.
Chờ Bác Duyệt, bác Mỹ và HL làm rồi học hỏi.
 
Để đơn giản vấn đề, mình gửi lại file với 2 mã và 8 records. Nếu thực hiện xong thủ tục, kết quả mong muốn sẽ là:
MaNV ....|TenNV .....................|.TongSoLuong | DienGiai
HTN001 ..| Hoàng Trọng Nghĩa 01 | ........ 35 .......| Vị trí 1 (10), Vị trí 2 (12), Vị trí 3 (13)
HTN002 ..| Hoàng Trọng Nghĩa 02 | ........ 30 .......| Vị trí 1 (2), Vị trí 2 (4), Vị trí 3 (6), Vị trí 4 (8), Vị trí 5 (10)

Sao anh không làm kết quả như hình bên dưới cho dể.

13.jpg
 
Nếu Nghĩa là trên ex và dùng ADO thì sẽ làm thế nào.
A chỉ có thể lấy data = ADO sau đó xử lý arr thì có thể ra được.
Còn câu SQL mà có kq vậy thì thua.
Chờ Bác Duyệt, bác Mỹ và HL làm rồi học hỏi.

Cái này với Excel thì chỉ là như vầy:

PHP:
Sub GroupSoLuong()
    Dim sArray, GroupArr, Tmp
    Dim h As Long, i As Long, r As Long
    Sheet1.Range("F2:I65536").Clear
    
    sArray = Range(Sheet1.[A2], Sheet1.[A65536].End(xlUp)).Resize(, 4).Value
    
    h = UBound(sArray, 1): r = 0
    
    ReDim GroupArr(1 To h, 1 To 4)
    With CreateObject("Scripting.Dictionary")
        For i = 1 To h
            Tmp = sArray(i, 1)
            If Not .Exists(Tmp) Then
                r = r + 1: .Add Tmp, r
                GroupArr(r, 1) = Tmp
                GroupArr(r, 2) = sArray(i, 2)
                GroupArr(r, 3) = sArray(i, 4)
                GroupArr(r, 4) = sArray(i, 3) & " (" & sArray(i, 4) & ")"
            Else
                GroupArr(.Item(Tmp), 3) = GroupArr(.Item(Tmp), 3) + sArray(i, 4)
                GroupArr(.Item(Tmp), 4) = GroupArr(.Item(Tmp), 4) & ", " & sArray(i, 3) & " (" & sArray(i, 4) & ")"
            End If
        Next
    End With
    Sheet1.Range("F2").Resize(r, 4).Value = GroupArr
End Sub
 

File đính kèm

Đây là bài toán nối chuỗi nhiều record vào 1 record. Dù làm trong access cũng phải viết code đọc từng record và nối lại.
 
Đây là bài toán nối chuỗi nhiều record vào 1 record. Dù làm trong access cũng phải viết code đọc từng record và nối lại.

Vì chỉ mới học Access một hoặc hai tháng nay, nên không biết ký rì về code của nó, vậy cho nên Sư phụ làm ơn hướng dẫn cho em bài này luôn đi ạ.

Xin cám ơn.
 
Vì chỉ mới học Access một hoặc hai tháng nay, nên không biết ký rì về code của nó, vậy cho nên Sư phụ làm ơn hướng dẫn cho em bài này luôn đi ạ.

Xin cám ơn.
Đã tìm được cách nối chuổi, nhưng cái khó ở chổ là cộng số lượng từng nơi làm việc vào chuổi.

14.jpg
 
Lần chỉnh sửa cuối:
Với bài toán dạng này, chúng ta có thể sử dụng một trong những tính năng ưu việt của Access là nhúng hàm người dùng vào câu lệnh truy vấn. Tuy nhiên, đổi lại, tốc độ sẽ rất kém.
Ta viết thêm một hàm

PHP:
Function FlattenQry(ID As String) As String
    Dim Sql As String
    Sql = "SELECT [NoiLamViec] & "" ("" & [SoLuong] & "")"" AS DienGiai FROM NhanVien WHERE MaNV='" & ID & "';"
    Dim Rcs As Object, cn As Connection
    Set Rcs = CurrentProject.AccessConnection.Execute(Sql)
    Sql = ""
    While Not Rcs.EOF
        Sql = Sql & ", " & Rcs.Fields(0)
        Rcs.MoveNext
    Wend
    FlattenQry = IIf(Sql = "", "", Mid(Sql, 3))
    Rcs.Close
End Function
Sau đó đưa vào Querry câu lệnh này


PHP:
SELECT NhanVien.MaNV, NhanVien.TenNV, FlattenQry([manv]) AS Expr1
FROM NhanVien
GROUP BY NhanVien.MaNV, NhanVien.TenNV, FlattenQry([manv]);
Thế là xong.
Các bác xem qua file đính kèm nhé.
Tuy nhiên, có điều tôi chưa rõ lắm đó là: có thể có trường hợp nhiều 1 nhân viên có cùng địa điểm nhưng số lượng khác nhau không? Nếu thế thì phải làm khác tí chút trong câu truy vấn đặt trong hàm.
 

File đính kèm

Lần chỉnh sửa cuối:
Với bài toán dạng này, chúng ta có thể sử dụng một trong những tính năng ưu việt của Access là nhúng hàm người dùng vào câu lệnh truy vấn. Tuy nhiên, đổi lại, tốc độ sẽ rất kém.
Ta viết thêm một hàm

PHP:
Function FlattenQry(ID As String) As String
    Dim Sql As String
    Sql = "SELECT [NoiLamViec] & "" ("" & [SoLuong] & "")"" AS DienGiai FROM NhanVien WHERE MaNV='" & ID & "';"
    Dim Rcs As Object, cn As Connection
    Set Rcs = CurrentProject.AccessConnection.Execute(Sql)
    Sql = ""
    While Not Rcs.EOF
        Sql = Sql & ", " & Rcs.Fields(0)
        Rcs.MoveNext
    Wend
    FlattenQry = IIf(Sql = "", "", Mid(Sql, 3))
    Rcs.Close
End Function
Sau đó đưa vào Querry câu lệnh này


PHP:
SELECT NhanVien.MaNV, NhanVien.TenNV, FlattenQry([manv]) AS Expr1
FROM NhanVien
GROUP BY NhanVien.MaNV, NhanVien.TenNV, FlattenQry([manv]);
Thế là xong.
Các bác xem qua file đính kèm nhé.
Tuy nhiên, có điều tôi chưa rõ lắm đó là: có thể có trường hợp nhiều 1 nhân viên có cùng địa điểm nhưng số lượng khác nhau không? Nếu thế thì phải làm khác tí chút trong câu truy vấn đặt trong hàm.
Chưa được đâu nha bạn, ví dụ bạn thêm nv mới thì nó sẽ ra kết quả không group lại.

15.jpg

Hai Lúa thử open recordset, gán vào mảng, rồi xử lý mảng kết hợp Dic xem. (xử lý mảng ra kết quả, sau đó update query kết quả)

Em sẽ viết 1 hàm để gom nhóm dữ liệu theo yêu cầu đề bài.
 
Lần chỉnh sửa cuối:
Thực ra em chưa rõ sự liên quan giữa nơi làm việc và nhân viên vì thế chưa đưa ra được kết quả đúng theo yêu cầu.
E thử mô tả lại thế này:
1 ông nhân viên, có thể làm nhiều nơi khác nhau, mỗi nơi có một vài sản phẩm nào đó. Có thể có trường hợp cùng một nơi có nhiều nhóm số lượng sản phẩm.
Yêu cầu đầu bài là nhóm lại tổng sản phẩm theo nơi làm việc của ông ta và đưa vào diễn giải.
Nếu vậy thì em xin mạn phép đưa câu trả lời như trong file đính kèm.
PHP:
Function FlattenQry(ID As String) As String
    Dim Sql As String
    
    Sql = "SELECT NoiLamViec, Sum(SoLuong) AS SumOfSoLuong " & _
        "FROM NhanVien WHERE MaNV='" & ID & "' GROUP BY NoiLamViec;"
    Dim Rcs As Object, cn As Connection
    Set Rcs = CurrentProject.AccessConnection.Execute(Sql)
    Sql = ""
    While Not Rcs.EOF
        Sql = Sql & ", " & Rcs.Fields(0) & " (" & Rcs.Fields(1) & ")"
        Rcs.MoveNext
    Wend
    FlattenQry = IIf(Sql = "", "", Mid(Sql, 3))
    Rcs.Close
End Function
pictures.jpg
 

File đính kèm

Lần chỉnh sửa cuối:
Trong module:

Mã:
Option Compare Database

Public Function ConcatenateStr(strField As String, strField1 As String, _
    strTable As String, Optional strWhere As String, _
    Optional strOrderBy As String, Optional strSeparator = ", ") As Variant


    Dim rs As DAO.Recordset
    Dim rsPlace As DAO.Recordset
    Dim strSql As String
    Dim strOut As String
    Dim lngLen As Long
    
    ConcatenateStr = Null
    
    strSql = "SELECT " & strField & ", sum(" & strField1 & ") FROM " & strTable
    If strWhere <> vbNullString Then
        strSql = strSql & " WHERE " & strWhere
    End If
    If strOrderBy <> vbNullString Then
        strSql = strSql & " GROUP BY " & strField & " ORDER BY " & strOrderBy
    End If
    Set rs = DBEngine(0)(0).OpenRecordset(strSql, dbOpenDynaset)
    
    Do While Not rs.EOF
        If Not IsNull(rs(0)) Then
          strOut = strOut & rs(0) & " (" & rs(1) & ")" & strSeparator
        End If
        rs.MoveNext
    Loop
    rs.Close
    
    lngLen = Len(strOut) - Len(strSeparator)
    If lngLen > 0 Then
        ConcatenateStr = Left(strOut, lngLen)
    End If


Exit_Handler:
    Set rsPlace = Nothing
    Set rs = Nothing
    Exit Function


End Function

Trong Query

SELECT sub.MaNV, sub.TenNV, sub.SumOfSoLuong AS Tong, ConcatenateStr("NoiLamViec","SoLuong","nhanvien","[MaNV] = '" & [sub].[MaNV] & "'","NoiLamViec") AS GhiChuFROM [SELECT
q.[MaNV],
q.TenNV,
Sum(q.[SoLuong]) AS SumOfSoLuong
FROM NhanVien AS q
GROUP BY
q.[MaNV],
q.TenNV]. AS sub
ORDER BY sub.MaNV, sub.TenNV;
 

File đính kèm

Trong module:

Mã:
Option Compare Database

Public Function ConcatenateStr(strField As String, strField1 As String, _
    strTable As String, Optional strWhere As String, _
    Optional strOrderBy As String, Optional strSeparator = ", ") As Variant
.............

End Function

Trong Query

Hàm này rất hay, mình cũng thử thêm một cột [Thang] trong CSDL, để lọc thêm theo điều kiện này thì mình phải bắt buộc phải thể hiện trên điều kiện trên cột này, đồng thời cũng phải thể hiện trong điều kiện trong hàm trên luôn.

SELECT MaNV, TenNV, Thang, Sum(SoLuong) AS TongSoLuong, ConcatenateStr("NoiLamViec","SoLuong","NhanVien","Thang='THÁNG 08/ 2012' And [MaNV] = '" & [MaNV] & "'","NoiLamViec") AS GhiChu
FROM NhanVien
WHERE Thang="THÁNG 08/ 2012"
GROUP BY MaNV, TenNV, Thang;

Như vậy lọc mới đúng ý đồ của mình.

Tuy nhiên, có một thắc mắc là mình muốn dùng ADO (câu lệnh từ VBA của Excel) để lọc qua Excel thì phải làm như thế nào với câu lệnh Select?

Mã:
Sub AccToEx()
    On Error Resume Next
    If AccConn = False Then
        MsgBox "Khong ket noi"
    Else
        
        Dim sSQL As String
        Dim adoCommand As Object, oRs As Object
        
        gcnObj.Open
        
[COLOR=#0000cd][B]        sSQL = "SELECT MaNV, TenNV, Sum(SoLuong), " _
             & "ConcatenateStr(NoiLamViec,SoLuong, " _
             & "NhanVien,Thang='THÁNG 08/ 2012' " _
             & "And [MaNV] = '" & [MaNV] & "',NoiLamViec) " _
             & "FROM NhanVien" _
             & "WHERE Thang = 'THÁNG 08/ 2012' " _
             & "GROUP BY MaNV;"[/B][/COLOR]

        Set adoCommand = CreateObject("ADODB.Command")
        
        With adoCommand
            .CommandType = 1
            .ActiveConnection = gcnObj
            .CommandText = sSQL
        End With
        
        Set oRs = CreateObject("ADODB.Recordset")
        oRs.Open adoCommand, , 3, 4
        
        If oRs.EOF Then
            MsgBox "Không có records nào!", vbOKOnly + vbInformation, "THÔNG BÁO"
        Else
            With Sheet1
                .Range("2:65536").ClearContents
                .Range("A2").CopyFromRecordset oRs
            End With
        End If
        
        Set adoCommand = Nothing
        Set oRs = Nothing
        
        If Not gcnObj Is Nothing Then
            If (gcnObj.State And adStateOpen) = adStateOpen Then
                gcnObj.Close
            End If
            Set gcnObj = Nothing
        End If
    End If
End Sub

Xin hướng dẫn giúp mình nhé!
 

File đính kèm

Hàm này rất hay, mình cũng thử thêm một cột [Thang] trong CSDL, để lọc thêm theo điều kiện này thì mình phải bắt buộc phải thể hiện trên điều kiện trên cột này, đồng thời cũng phải thể hiện trong điều kiện trong hàm trên luôn.

Xin hướng dẫn giúp mình nhé!
Sao kg dùng ADO lấy ra 1 rec và chuyển sang Arr đ6ẻ xử lý, lúc này MaNV đã được sort rồi, kg cân Dic nữa.
PHP:
sSQL = "SELECT MANV, TENNV, Thang, sum(SoLuong) as tongsoluong ,  NoiLamViec as ghichu" & Chr(10)
sSQL = sSQL & "FROM " & sTbl & Chr(10)
sSQL = sSQL & "WHERE Thang = 'THÁNG 08/ 2012'" & Chr(10)
sSQL = sSQL & "Group by MaNV, TENNV, Thang, NoiLamViec"
...
tmpArr = oRs.getrows
 

File đính kèm

Có cách nào mình rút gọn hơn nữa không anh Thunghi. Em nhìn vo thấy arr nhiều quá +-+-+-+
 
Có cách nào mình rút gọn hơn nữa không anh Thunghi. Em nhìn vo thấy arr nhiều quá +-+-+-+

Chắc có lẽ anh ThuNghi kỹ quá nên dùng nhiều vòng lặp như vậy, thật ra khi xử lý mảng theo bài của anh ThuNghi thì không cần phải xử lý đến 2 lần dòng đầu và những dòng sau đâu.
Mã:
Sub AccToEx_2()
    If AccConn = False Then
        MsgBox "Khong ket noi"
        GoTo ErrorHandle
    End If
    
    Dim sSQL As String
    Dim adoCommand As Object, oRs As Object

    gcnObj.Open
    
    sSQL = "SELECT MaNV, TenNV, Thang, SUM(SoLuong) As TongSoLuong, NoiLamViec As DienGiai " _
         & "FROM NhanVien WHERE Thang = 'THÁNG 07/ 2012' " _
         & "GROUP BY MaNV, TenNV, Thang, NoiLamViec;"
    
    Set adoCommand = CreateObject("ADODB.Command")
    
    With adoCommand
        .CommandType = 1
        .ActiveConnection = gcnObj
        .CommandText = sSQL
    End With
    
    Set oRs = CreateObject("ADODB.Recordset")
    oRs.Open adoCommand, , 3, 4
    
    If oRs.EOF Then
        MsgBox "Không có records nào!", vbOKOnly + vbInformation, "THÔNG BÁO"
        GoTo ErrHandle
    End If
    
    Dim AccessArr, AcToExArr, ExcelArr, ArrField()
    Dim c As Long, h As Long, i As Long, j As Long, n As Long, r As Long
    Dim tmp As String: tmp = ""
    
[COLOR=#008000]    ''*****Lay FiledsName -> ArrField:[/COLOR]

    n = oRs.Fields.Count
    ReDim ArrField(1 To n)
    For c = 1 To n
        ArrField(c) = oRs.Fields(c - 1).Name
    Next
   
 [COLOR=#008000]   ''*****Lay Array tu Access:[/COLOR]
    
    AccessArr = oRs.GetRows

    c = UBound(AccessArr, 1) + 1
    h = UBound(AccessArr, 2) + 1

    ReDim AcToExArr(1 To h, 1 To c)
    For i = 1 To h
        For j = 1 To c
            AcToExArr(i, j) = AccessArr(j - 1, i - 1)
        Next
    Next

    [COLOR=#008000]''****Xu ly cong group AcToExArr -> ExcelArr:[/COLOR]

[COLOR=#0000cd] [B]   ReDim ExcelArr(1 To h, 1 To c): r = 0
    For i = 1 To h
        If AcToExArr(i, 1) <> tmp Then
            r = r + 1
            For c = 1 To 4
                ExcelArr(r, c) = AcToExArr(i, c)
            Next
            ExcelArr(r, 5) = AcToExArr(i, 5) & " (" & AcToExArr(i, 4) & ")" [/B][/COLOR][COLOR=#008000][B]''DienGiai[/B][/COLOR][COLOR=#0000cd][B]
        Else
            ExcelArr(r, 4) = ExcelArr(r, 4) + AcToExArr(i, 4) [/B][/COLOR][COLOR=#008000][B]''SoLuong[/B][/COLOR][COLOR=#0000cd][B]
            ExcelArr(r, 5) = ExcelArr(r, 5) & "; " & AcToExArr(i, 5) & " (" & AcToExArr(i, 4) & ")" [/B][/COLOR][COLOR=#008000][B]''DienGiai[/B][/COLOR][COLOR=#0000cd][B]
        End If
        tmp = AcToExArr(i, 1)
    Next[/B]
[/COLOR]
    With Sheets("Report")
        .Cells.ClearContents
        .Range("A1").Resize(, 5) = ArrField
        .Range("A2").Resize(r, 5) = ExcelArr
    End With
    
    Erase AccessArr, AcToExArr, ExcelArr, ArrField()

ErrHandle:
    Set adoCommand = Nothing
    Set oRs = Nothing
    
ErrorHandle:
    If Not gcnObj Is Nothing Then
        If (gcnObj.State And adStateOpen) = adStateOpen Then
            gcnObj.Close
        End If
        Set gcnObj = Nothing
    End If
End Sub

Có lẽ do cơ chế Group của Access nó sort từ A-Z luôn nên mới có thể dùng được với xử lý mảng như vậy. Còn nếu mảng mà chưa sắp xếp thì phải dùng đến Dictionary thôi (tôi thiết nghĩ nên dùng thì tốt hơn):

Thay thủ tục màu xanh thành thủ tục dưới đây:

Mã:
    [COLOR=#008000]''****Xu ly cong group AcToExArr -> ExcelArr:[/COLOR]
    
    ReDim ExcelArr(1 To h, 1 To c): r = 0
    With CreateObject("Scripting.Dictionary")
        For i = 1 To h
            tmp = AcToExArr(i, 1)
            If Not .Exists(tmp) Then
                r = r + 1: .Add tmp, r
                For c = 1 To 4
                    ExcelArr(r, c) = AcToExArr(i, c)
                Next
                ExcelArr(r, 5) = AcToExArr(i, 5) & " (" & AcToExArr(i, 4) & ")" [COLOR=#008000]''DienGiai[/COLOR]
            Else
                ExcelArr(.Item(tmp), 4) = ExcelArr(.Item(tmp), 4) + AcToExArr(i, 4) [COLOR=#008000]''SoLuong[/COLOR]
                ExcelArr(.Item(tmp), 5) = ExcelArr(.Item(tmp), 5) & "; " & AcToExArr(i, 5) & " (" & AcToExArr(i, 4) & ")" [COLOR=#008000]''DienGiai[/COLOR]
            End If
        Next
    End With
 
Lần chỉnh sửa cuối:
Chắc có lẽ anh ThuNghi kỹ quá nên dùng nhiều vòng lặp như vậy, thật ra khi xử lý mảng theo bài của anh ThuNghi thì không cần phải xử lý đến 2 lần dòng đầu và những dòng sau đâu.

Lý do là tôi muốn đưa ra những tình huống
1/ Chuyển từ Rec sang TmpArr
2/ Chuyển TmpArr sang sArr (ngang sang dọc) cho dễ nhìn
3/ Xử lý sArr
3 công đoạn này thì có thể làm thẳng từ Rec sang kq luôn nhưng thấy thêm công đoạn kg ảnh hưởng lắm và nhất là dễ nhìn và xử lý theo hướng Arr.

Còn đã dùng ADO thì dùng thêm Dic thì hơi dư, phần sort thì chắc chắn sẽ sort theo cột 1, TH muốn sort thêm thì chỉ cần thêm "Order by ..." vào câu SQL là OK.
 
Lý do là tôi muốn đưa ra những tình huống
1/ Chuyển từ Rec sang TmpArr
2/ Chuyển TmpArr sang sArr (ngang sang dọc) cho dễ nhìn
3/ Xử lý sArr
3 công đoạn này thì có thể làm thẳng từ Rec sang kq luôn nhưng thấy thêm công đoạn kg ảnh hưởng lắm và nhất là dễ nhìn và xử lý theo hướng Arr.

Còn đã dùng ADO thì dùng thêm Dic thì hơi dư, phần sort thì chắc chắn sẽ sort theo cột 1, TH muốn sort thêm thì chỉ cần thêm "Order by ..." vào câu SQL là OK.



Anh ThuNghi nói đúng đó, mình chỉ cần xử lý thẳng luôn một lần cho gọn!

Thay vì xử lý nhiều lần:

PHP:
    AccessArr = oRs.GetRows

    c = UBound(AccessArr, 1) + 1
    h = UBound(AccessArr, 2) + 1

    ReDim AcToExArr(1 To h, 1 To c)
    For i = 1 To h
        For j = 1 To c
            AcToExArr(i, j) = AccessArr(j - 1, i - 1)
        Next
    Next

    ''****Xu ly cong group AcToExArr -> ExcelArr:

    ReDim ExcelArr(1 To h, 1 To c): r = 0
    For i = 1 To h
        If AcToExArr(i, 1) <> tmp Then
            r = r + 1
            For c = 1 To 4
                ExcelArr(r, c) = AcToExArr(i, c)
            Next
            ExcelArr(r, 5) = AcToExArr(i, 5) & " (" & AcToExArr(i, 4) & ")"      ''DienGiai
        Else
            ExcelArr(r, 4) = ExcelArr(r, 4) + AcToExArr(i, 4)          ''SoLuong
            ExcelArr(r, 5) = ExcelArr(r, 5) & "; " & AcToExArr(i, 5) & " (" & AcToExArr(i, 4) & ")"         ''DienGiai
        End If
        tmp = AcToExArr(i, 1)
    Next

Thì mình xử lý ngay sau khi mảng "mới ra lò" luôn:

PHP:
    AccessArr = oRs.GetRows

    c = UBound(AccessArr, 1) + 1
    h = UBound(AccessArr, 2) + 1

    ReDim ExcelArr(1 To h, 1 To c): r = 0
    For i = 1 To h
        If AccessArr(0, i - 1) <> tmp Then
            r = r + 1
            For j = 1 To 4
                ExcelArr(r, j) = AccessArr(j - 1, i - 1)
            Next
            ExcelArr(r, 5) = AccessArr(4, i - 1) & " (" & AccessArr(3, i - 1) & ")"            ''DienGiai
        Else
            ExcelArr(r, 4) = ExcelArr(r, 4) + AccessArr(3, i - 1)            ''SoLuong
            ExcelArr(r, 5) = ExcelArr(r, 5) & "; " & AccessArr(4, i - 1) & " (" & AccessArr(3, i - 1) & ")"         ''DienGiai
        End If
        tmp = AccessArr(0, i - 1)
    Next

Như vậy đỡ tốn một vài công đoạn nữa và đương nhiên thời gian có thể nhỉn hơn tí xíu.
 
Sẳn đề tài này cho mình hỏi là câu lệnh SQL với WHERE với điều điện trường đó = rổng thì phải đặt câu lệnh gì? (nghĩa là trường đó chưa nhập gì vào hết).
Xin cám ơn!
 
Điều kiện vậy thì là
Cám ơn anh! Nhưng sao ra, khi bỏ điều kiện đó thì nó ra (Câu lệnh không báo lỗi nhưng không xuất ra dử liệu)
Câu lệnh điều kiện đó như bên dưới anh xem giúp có sai gì k nhé. Cám ơn anh.

mySql = mySql & "WHERE (MK=" & Kh & ")And(TKC='1111')AND(MN='" & MNg & "')AND(MNKP=" & NgKP & ")And(NHT>=" & Date1 & ")and(NHT<=" & Date2 & ")and(TM>0) and (NTT IS NULL) order by TM;"
 
Cám ơn anh! Nhưng sao ra, khi bỏ điều kiện đó thì nó ra (Câu lệnh không báo lỗi nhưng không xuất ra dử liệu)
Câu lệnh điều kiện đó như bên dưới anh xem giúp có sai gì k nhé. Cám ơn anh.

mySql = mySql & "WHERE (MK=" & Kh & ")And(TKC='1111')AND(MN='" & MNg & "')AND(MNKP=" & NgKP & ")And(NHT>=" & Date1 & ")and(NHT<=" & Date2 & ")and(TM>0) and (NTT IS NULL) order by TM;"
Phải xem dữ liệu mới xác định cái trường nào là kiểu text trường nào là số, đặc biệt là ngày tháng mà có cách xử khác nhau.
 
Mình có một file dữ liệu là access, trong có 3 table: tblBan, tblHang, tblKho. Mình muốn hỏi mọi người câu SQL để có kết quả hiển thị như trong bảng "Ket qua" ở trong file gửi kèm. Viết bằng VBA để hiển thị bảng "Ket qua" trong excel nhé, rất mong đượcmọi người giúp đỡ!
 

File đính kèm

Mình có một file dữ liệu là access, trong có 3 table: tblBan, tblHang, tblKho. Mình muốn hỏi mọi người câu SQL để có kết quả hiển thị như trong bảng "Ket qua" ở trong file gửi kèm. Viết bằng VBA để hiển thị bảng "Ket qua" trong excel nhé, rất mong đượcmọi người giúp đỡ!

Bạn tạo CSDL Access 2003 và chuyển đổi file excel trên sang 2003 giúp nhé.
 
Gửi bạn. Nhờ bạn giúp nhé!
Đầu tiên bạn chỉnh kiểu dữ liệu của trường BMaHang của bảng tblBan về kiểu number cho giống với HMaHang của bảng tblHang, và chỉnh KMaKhoLuuTru của bảng tblKho về làm khóa chính.

Code trong Excel để lấy dữ liệu theo yêu cầu của bạn là:

Mã:
Option Explicit
Sub LayDL()
Dim cnn As New ADODB.Connection
Dim rst As New ADODB.Recordset
Dim lsSQL As String
With cnn
    .Provider = "Microsoft Jet 4.0 OLE DB Provider"
    .ConnectionString = "Data Source=" & ThisWorkbook.Path & "\data.mdb"
    .CursorLocation = adUseClient
    .Open

End With

    lsSQL = "SELECT tblBan.BNgay, tblBan.BMaHang, tblHang.HTenhang, tblBan.BMaKhoLuuTru, tblKho.KTenKhoLuuTru, tblBan.BSoLuongBan " & _
                    "FROM tblKho INNER JOIN (tblHang INNER JOIN tblBan ON tblHang.HMaHang = tblBan.BMaHang) ON tblKho.KMaKhoLuuTru = tblBan.BMaKhoLuuTru;"

    rst.Open lsSQL, cnn, 1, 3
    [b5:g6000].ClearContents
    [b5].CopyFromRecordset rst
    
rst.Close: Set rst = Nothing
cnn.Close: Set cnn = Nothing

End Sub

Bạn xem file đính kèm nhé

Lưu ý: Giải nén rồi mới chạy file Excel nhé.
 

File đính kèm

Lần chỉnh sửa cuối:
Phải xem dữ liệu mới xác định cái trường nào là kiểu text trường nào là số, đặc biệt là ngày tháng mà có cách xử khác nhau.
Cám ơn anh. Anh cho em hỏi có câu điều kiện nào đại diện cho tất cả các kiểu dử liệu của trường đó k? (có nghĩa là trường đó là rổng hoặc bất cứ kiểu dử liệu gì nó cũng cho ra hết)
 
Cám ơn anh. Anh cho em hỏi có câu điều kiện nào đại diện cho tất cả các kiểu dử liệu của trường đó k? (có nghĩa là trường đó là rổng hoặc bất cứ kiểu dử liệu gì nó cũng cho ra hết)

Thì không cần gắn điều kiện gì vào trường đó hết. Như vậy nó sẽ hiện hết dữ liệu.
 
Thì không cần gắn điều kiện gì vào trường đó hết. Như vậy nó sẽ hiện hết dữ liệu.
Tại vì có lúc có lúc không? áp dụng cho nhiều trường hợp, trường đó có thể có hoặc không có dử liệu. nên em mới cần điều kiện như vậy. Em muốn điều kiện lọc giống như lọc bằng Advalced Filter vậy đấy, bổ tróng thì lộc hết, có điều kiện thì lọc theo điều kiện. Cám ơn anh đã quan tâm.
 
Tại vì có lúc có lúc không? áp dụng cho nhiều trường hợp, trường đó có thể có hoặc không có dử liệu. nên em mới cần điều kiện như vậy. Em muốn điều kiện lọc giống như lọc bằng Advalced Filter vậy đấy, bổ tróng thì lộc hết, có điều kiện thì lọc theo điều kiện. Cám ơn anh đã quan tâm.

Muốn áp dụng theo ý muốn có lúc vầy lúc khác thì bạn phải tạo 1 biến hoặc cái gì đó làm điều kiện để lọc. Nói chung tùy biến mà áp dụng vào thực tế.
 
Đầu tiên bạn chỉnh kiểu dữ liệu của trường BMaHang của bảng tblBan về kiểu number cho giống với HMaHang của bảng tblHang, và chỉnh KMaKhoLuuTru của bảng tblKho về làm khóa chính.

Code trong Excel để lấy dữ liệu theo yêu cầu của bạn là:

Mã:
Option Explicit
Sub LayDL()
Dim cnn As New ADODB.Connection
Dim rst As New ADODB.Recordset
Dim lsSQL As String
With cnn
    .Provider = "Microsoft Jet 4.0 OLE DB Provider"
    .ConnectionString = "Data Source=" & ThisWorkbook.Path & "\data.mdb"
    .CursorLocation = adUseClient
    .Open

End With

    lsSQL = "SELECT tblBan.BNgay, tblBan.BMaHang, tblHang.HTenhang, tblBan.BMaKhoLuuTru, tblKho.KTenKhoLuuTru, tblBan.BSoLuongBan " & _
                    "FROM tblKho INNER JOIN (tblHang INNER JOIN tblBan ON tblHang.HMaHang = tblBan.BMaHang) ON tblKho.KMaKhoLuuTru = tblBan.BMaKhoLuuTru;"

    rst.Open lsSQL, cnn, 1, 3
    [b5:g6000].ClearContents
    [b5].CopyFromRecordset rst
    
rst.Close: Set rst = Nothing
cnn.Close: Set cnn = Nothing

End Sub

Bạn xem file đính kèm nhé

Lưu ý: Giải nén rồi mới chạy file Excel nhé.

Em cũng mới tọ mọ excel cũng đang cần nối Dữ liệu với bảng tính excel vì dữ liệu mà lưu nhiều trong excel thì máy chạy như rùa, nên em muốn tìm hiểu cách để nối, lấy dữ liệu từ access ra excel tính toán. Rất giống ví dụ trên, em đã tải về file ketnoi nhưng không thấy excel hoạt động (hoặc không biết cách làm nó hoạt động), em không biết đoạn code trên phải viết ở đâu. Em còn gà lắm, mong các bác chỉ bảo chi tiết hơn. Cảm ơn các bác.
 
Em cũng mới tọ mọ excel cũng đang cần nối Dữ liệu với bảng tính excel vì dữ liệu mà lưu nhiều trong excel thì máy chạy như rùa, nên em muốn tìm hiểu cách để nối, lấy dữ liệu từ access ra excel tính toán. Rất giống ví dụ trên, em đã tải về file ketnoi nhưng không thấy excel hoạt động (hoặc không biết cách làm nó hoạt động), em không biết đoạn code trên phải viết ở đâu. Em còn gà lắm, mong các bác chỉ bảo chi tiết hơn. Cảm ơn các bác.
Bạn xem các đoạn Phim là biết phải làm gì
ADO căn bản: Kết nối truy vấn CSDL từ file Excel đến file Access.
 
Cảm ơn bạn nhưng khi mình kích vào lấy dữ liệu, nó báo lỗi gì đó và không thực hiện. Mình muốn lấy một phần dữ liệu, ví dụ một tuần hay một tháng bán hàng trong cơ sở dữ liệu của một năm. Dữ liệu cần lấy có thể thay đổi là tháng 1 hay tháng 2 trong năm.
 
Cảm ơn bạn nhưng khi mình kích vào lấy dữ liệu, nó báo lỗi gì đó và không thực hiện. Mình muốn lấy một phần dữ liệu, ví dụ một tuần hay một tháng bán hàng trong cơ sở dữ liệu của một năm. Dữ liệu cần lấy có thể thay đổi là tháng 1 hay tháng 2 trong năm.

Bạn đưa dữ liệu mẫu và code mà bạn nói báo lỗi lên xem thử như thế nào nhé.
 
Đầu tiên bạn chỉnh kiểu dữ liệu của trường BMaHang của bảng tblBan về kiểu number cho giống với HMaHang của bảng tblHang, và chỉnh KMaKhoLuuTru của bảng tblKho về làm khóa chính.

Code trong Excel để lấy dữ liệu theo yêu cầu của bạn là:

Mã:
Option Explicit
Sub LayDL()
Dim cnn As New ADODB.Connection
Dim rst As New ADODB.Recordset
Dim lsSQL As String
With cnn
    .Provider = "Microsoft Jet 4.0 OLE DB Provider"
    .ConnectionString = "Data Source=" & ThisWorkbook.Path & "\data.mdb"
    .CursorLocation = adUseClient
    .Open

End With

    lsSQL = "SELECT tblBan.BNgay, tblBan.BMaHang, tblHang.HTenhang, tblBan.BMaKhoLuuTru, tblKho.KTenKhoLuuTru, tblBan.BSoLuongBan " & _
                    "FROM tblKho INNER JOIN (tblHang INNER JOIN tblBan ON tblHang.HMaHang = tblBan.BMaHang) ON tblKho.KMaKhoLuuTru = tblBan.BMaKhoLuuTru;"

    rst.Open lsSQL, cnn, 1, 3
    [b5:g6000].ClearContents
    [b5].CopyFromRecordset rst
    
rst.Close: Set rst = Nothing
cnn.Close: Set cnn = Nothing

End Sub

Bạn xem file đính kèm nhé

Lưu ý: Giải nén rồi mới chạy file Excel nhé.

Mình tải file này của bạn về giải nén rồi chạy excel như bạn nói nhưng không lấy được dữ liệu từ access. Bạn hướng dẫn giúp mình cách lấy dữ liệu và có thể chỉ lọc lấy dữ liệu từ ngày 21/9 đến ngày 23/9/2012 sang excel thôi không. mình có thể chọn ngày khác nữa chứ không cố định ngày đó
 
Mình tải file này của bạn về giải nén rồi chạy excel như bạn nói nhưng không lấy được dữ liệu từ access. Bạn hướng dẫn giúp mình cách lấy dữ liệu và có thể chỉ lọc lấy dữ liệu từ ngày 21/9 đến ngày 23/9/2012 sang excel thôi không. mình có thể chọn ngày khác nữa chứ không cố định ngày đó
Thì bạn thêm điều kiện vào là được, ví dụ Cell D2 là ngày bắt đầu, E2 là ngày kết thúc, code sẽ như sau:

Mã:
Option Explicit
Sub LayDL()
Dim cnn As New ADODB.Connection
Dim rst As New ADODB.Recordset
Dim lsSQL As String
With cnn
    .Provider = "Microsoft Jet 4.0 OLE DB Provider"
    .ConnectionString = "Data Source=" & ThisWorkbook.Path & "\data.mdb"
    .CursorLocation = adUseClient
    .Open

End With
    lsSQL = "SELECT tblBan.BNgay, tblBan.BMaHang, tblHang.HTenhang, tblBan.BMaKhoLuuTru, tblKho.KTenKhoLuuTru, tblBan.BSoLuongBan " & _
                    "FROM tblKho INNER JOIN (tblHang INNER JOIN tblBan ON tblHang.HMaHang = tblBan.BMaHang) " & _
                    "ON tblKho.KMaKhoLuuTru = tblBan.BMaKhoLuuTru " & _
                    "where  tblBan.BNgay  between #" & Format(DateSerial(Year([d2]), Month([d2]), Day([d2])), "mm/dd/yyyy") & _
                     "# AND #" & Format(DateSerial(Year([e2]), Month([e2]), Day([e2])), "mm/dd/yyyy") & "# "
    rst.Open lsSQL, cnn, 1, 3
    [b5:g6000].ClearContents
    [b5].CopyFromRecordset rst
    
rst.Close: Set rst = Nothing
cnn.Close: Set cnn = Nothing

End Sub

Giải nén và chạy file Excel nhé.
 

File đính kèm

Khi mình kích Lấy DL nó báo thế nầy, không biết làm thế nào để cho nó hoạt động nữa. Nhờ bạn chỉ giúp.
 

File đính kèm

Khi mình kích Lấy DL nó báo thế nầy, không biết làm thế nào để cho nó hoạt động nữa. Nhờ bạn chỉ giúp.

Sao bạn không gửi cái file bạn muốn truy vấn lên? gửi hình thì giải quyết được gì chứ! Bạn gửi lên đi cho dễ làm cho bạn!

Nhưng không biết bạn có vào Tool > Reference và check vào mục Microsoft ActiveX Data Object 2.6 chưa nhỉ?
 

File đính kèm

  • Picture1.jpg
    Picture1.jpg
    70.3 KB · Đọc: 101
Lần chỉnh sửa cuối:
File LayDL_Acc.rar của Hai Lúa đó bạn. Mình tải về chọn Lấy DL là bị như vậy. Mình kiểm tra hình như đã check ô đó rồi.
 
excel 2007 :http://www.giaiphapexcel.com/forum/s...-%C4%91%C3%A2u

excel 2003: Mở file excel lên -> Tools -> Macro -> Security -> Chọn mức low, đóng hết các file Excel, mở lại file lần nữa.

Hai Lúa bắt bài đúng rồi đấy, nãy nhìn không rõ nội dung trong thông báo, giờ nhìn kỹ lại thấy nó thuộc lỗi Macro Setting.

File LayDL_Acc.rar của Hai Lúa đó bạn. Mình tải về chọn Lấy DL là bị như vậy. Mình kiểm tra hình như đã check ô đó rồi.


Bạn xem bài trước của Hai Lúa nhé!
 
Sao bạn không gửi cái file bạn muốn truy vấn lên? gửi hình thì giải quyết được gì chứ! Bạn gửi lên đi cho dễ làm cho bạn!

Nhưng không biết bạn có vào Tool > Reference và check vào mục Microsoft ActiveX Data Object 2.6 chưa nhỉ?

Việc trực tiếp Reference như vậy sẽ dẫn đến: nếu phiên bản ở máy khách không có cũng sẽ bị báo lỗi. Vì đôi khi ở máy khách có nhiều phiên bản khác nhau, hoặc không có phiên bản như trong Reference.
Dĩ nhiên nó sẽ dễ dàng cho người lập trình.

Theo tôi nên áp dụng late binding như có lần tôi đã đề cập. Như vậy mình sẽ không cần chú ý đến việc check vào Reference.

Lê Văn Duyệt
 
Bạn Hai Lúa ơi, cho mình hỏi nốt một vấn đề nữa. Mình muốn nhập dữ liệu ở file excel Vi du như ở trên rồi có thể làm một nút ấn vào đó, dữ liệu chuyển từ file excel Vi du sang lưu ở file access tên data. Sau đó, toàn bộ dữ liệu đã chuyển trên file excel bị xóa hết, chuẩn bị cho việc nhập dữ liệu lần khác. Mình biết được chút ít excel mà access thì mình không nhớ gì. Mình cần một file excel để nhập, chuyển dữ liệu sang access lưu sau đó chuyển ra file excel khác để tính toán. Mà nghiên cứu access thì mình k có thời gian. Bạn giúp mình với nha. Thanks.
 
Bạn Hai Lúa ơi, cho mình hỏi nốt một vấn đề nữa. Mình muốn nhập dữ liệu ở file excel Vi du như ở trên rồi có thể làm một nút ấn vào đó, dữ liệu chuyển từ file excel Vi du sang lưu ở file access tên data. Sau đó, toàn bộ dữ liệu đã chuyển trên file excel bị xóa hết, chuẩn bị cho việc nhập dữ liệu lần khác. Mình biết được chút ít excel mà access thì mình không nhớ gì. Mình cần một file excel để nhập, chuyển dữ liệu sang access lưu sau đó chuyển ra file excel khác để tính toán. Mà nghiên cứu access thì mình k có thời gian. Bạn giúp mình với nha. Thanks.

Bạn dùng code sau:

Mã:
Sub ToAcc()
Dim cnn, rst As Object, lsSQL As String
Set cnn = CreateObject("ADODB.Connection")
Set rst = CreateObject("ADODB.Recordset")
With cnn
    .Provider = "Microsoft Jet 4.0 OLE DB Provider"
    .ConnectionString = "Data Source=" & ThisWorkbook.Path & "\data.mdb"
    .Open
End With
    lsSQL = " INSERT INTO tblBan SELECT * FROM  [EXCEL 8.0;Database=" & ThisWorkbook.FullName & ";HDR=Yes].[ToAcc$];"
    rst.Open lsSQL, cnn, 1, 3
    Sheets("ToAcc").[A2:D60000].ClearContents
Set rst = Nothing: cnn.Close: Set cnn = Nothing

End Sub

Giải nén và chạy file Excel nhé.
 

File đính kèm

Mình có bảng access ví dụ bên. Như bạn Hai lúa chỉ mình đã tạo được file excel nhập liệu, nhưng mình muốn thêm một cửa sổ báo lỗi, ví dụ chỉ được nhập 3 mặc hàng vào mỗi kho, nếu nhập hàng thứ 4 vào kho 1 thì sẽ hiện một cửa sổ báo “Kho 1 đã đầy” và không cho phép nhập hàng đó vào dữ liệu.---Nếu hàng đã bán trong cột ngayban quá 2 ngày, hoặc mình có thể thay đổi thời gian vượt quá--- thì không tính, xem như kho đã trống; Tạo một file excel nhập liệu khác điền vào cột ngày bán, cho dữ liệu nhập kho đã có sẵn trong dữ liệu, ví dụ kẹo bán vào ngày 16/11/2012, một macro khác để nhập bổ sung giá bán; Mình muốn xuất dữ liệu ra một file excel khác nhưng ngày tham chiếu từ ngày-> đến ngày sẽ tham chiếu cả ngày nhập lẫn ngày bán. Ví dụ mình nhập từ ngày 01/11/2012 đến ngày 10/11/2012 thì sẽ xuất được tất cả dữ liệu ngày nhập kho trong phạm vi ngày đó lẫn dữ liệu ngày bán cũng trong phạm vi đó và không lệ thuộc vào nhau, --ngày nhapkho là ngày 29/10/2012 nhưng ngày bán là ngày 05/11/2012, ngày nhapkho là ngày 05/11/2012 nhưng ngày bán là ngày 30/11/2012 cũng vẫn xuất ra trong file excle xuất---; à, bạn chỉ luôn giúp câu lệnh để thay vùng dữ liệu từ ngày, đến ngày bằng từ số đến số giúp mình nha. Mong bạn Hai lua pro giúp đỡ, cảm ơn bạn.
 

File đính kèm

Không còn ai quan tâm đề tài này nữa hay không có cách vậy mọi người. Giúp mình với, mình vừa học hỏi vừa mò mẫm, mình chưa được học lập trình nên không hiểu nhiều, chỉ bắt chước theo mà được việc thôi.
 
Mình có bảng access ví dụ bên. Như bạn Hai lúa chỉ mình đã tạo được file excel nhập liệu, nhưng mình muốn thêm một cửa sổ báo lỗi, ví dụ chỉ được nhập 3 mặc hàng vào mỗi kho, nếu nhập hàng thứ 4 vào kho 1 thì sẽ hiện một cửa sổ báo “Kho 1 đã đầy” và không cho phép nhập hàng đó vào dữ liệu.---Nếu hàng đã bán trong cột ngayban quá 2 ngày, hoặc mình có thể thay đổi thời gian vượt quá--- thì không tính, xem như kho đã trống; Tạo một file excel nhập liệu khác điền vào cột ngày bán, cho dữ liệu nhập kho đã có sẵn trong dữ liệu, ví dụ kẹo bán vào ngày 16/11/2012, một macro khác để nhập bổ sung giá bán; Mình muốn xuất dữ liệu ra một file excel khác nhưng ngày tham chiếu từ ngày-> đến ngày sẽ tham chiếu cả ngày nhập lẫn ngày bán. Ví dụ mình nhập từ ngày 01/11/2012 đến ngày 10/11/2012 thì sẽ xuất được tất cả dữ liệu ngày nhập kho trong phạm vi ngày đó lẫn dữ liệu ngày bán cũng trong phạm vi đó và không lệ thuộc vào nhau, --ngày nhapkho là ngày 29/10/2012 nhưng ngày bán là ngày 05/11/2012, ngày nhapkho là ngày 05/11/2012 nhưng ngày bán là ngày 30/11/2012 cũng vẫn xuất ra trong file excle xuất---; à, bạn chỉ luôn giúp câu lệnh để thay vùng dữ liệu từ ngày, đến ngày bằng từ số đến số giúp mình nha. Mong bạn Hai lua pro giúp đỡ, cảm ơn bạn.

Bảng dữ liệu kỳ vậy bạn, thường thì người ta tạo những bảng danh mục và những bảng phát sinh riêng biệt, sau đó tạo mối quan hệ các bảng với nhau mục đích làm cho csdl nhẹ nhàng, dể truy vấn. Nhìn vào bảng của bạn, đọc hướng dẫn xong rồi chẳng biết làm như thế nào để giúp được bạn.
 
Lần chỉnh sửa cuối:
Có lẽ những đề tài về ADO không ai quan tâm nhỉ.

Mình rất muốn quan tâm nhưng tại chưa biết gì về Access nên không hiểu, chưa có thời gian để nghiên cứu.

Mình xin hỏi sơ một số vấn đề rất "lúa" như sau:
Ví dụ mình đang sử dụng cơ sở dữ liệu trên một file Excel thì:

1. Làm sao để chuyển dữ liệu đó thành CSDL.mdb
2. Khi sử dụng dữ liệu nguồn trên Access, việc trích lọc, truy xuất để đưa vào tính toán trên Excel có dễ dàng như làm việc với data trên Excel không?
3. Ưu điểm khi chuyển khi chuyển dữ liệu sang Acces để làm việc.
4. Có sử dụng Macro trên file mdb không?
5. Theo mình biết thì còn có thể lưu data vào file DBF, vậy có thể dùng ADO không?

Mình tin rằng có nhiều người muốn nhưng cũng bỡ ngỡ giống mình. Tự học mà ... hi hi
Cảm ơn Hai Lúa Miền Tây!
 
Mình rất muốn quan tâm nhưng tại chưa biết gì về Access nên không hiểu, chưa có thời gian để nghiên cứu.

Mình xin hỏi sơ một số vấn đề rất "lúa" như sau:
Ví dụ mình đang sử dụng cơ sở dữ liệu trên một file Excel thì:

1. Làm sao để chuyển dữ liệu đó thành CSDL.mdb
2. Khi sử dụng dữ liệu nguồn trên Access, việc trích lọc, truy xuất để đưa vào tính toán trên Excel có dễ dàng như làm việc với data trên Excel không?
3. Ưu điểm khi chuyển khi chuyển dữ liệu sang Acces để làm việc.
4. Có sử dụng Macro trên file mdb không?
5. Theo mình biết thì còn có thể lưu data vào file DBF, vậy có thể dùng ADO không?

Mình tin rằng có nhiều người muốn nhưng cũng bỡ ngỡ giống mình. Tự học mà ... hi hi
Cảm ơn Hai Lúa Miền Tây!

1. Import = tay từ 1 file excel vào access hoặc có thể dùng code từ excel hoặc code ở access.
2. Dĩ nhiên việc trích xuất và truy vấn vào excel theo ý muốn của mình.
3. Có thể lưu dữ liệu nhiều, truy vấn dữ liệu cần sẽ nhẹ nhàng hơn.
4. Nếu đơn thuần Access chỉ là chứa dữ liệu thì không cần dùng VBA trên Access.
 
Xin cho hỏi, dùng ADO để xóa dữ liệu (clearcontents) của:

1) Một hoặc vài cột trong Excel

2) Một bảng hoặc nhiều bảng trong 1 sheet của Excel

3) Một sheet hoặc nhiều sheet trong Excel

Thì phải làm như thế nào?

Cám ơn rất nhiều!
 
Lần chỉnh sửa cuối:

Bài viết mới nhất

Back
Top Bottom