Chuyên đề giải đáp những thắc mắc về code VBA

Liên hệ QC

maytinhvp01

Thành viên thường trực
Tham gia
27/7/13
Bài viết
390
Được thích
179
Mình muốn nhờ giải thich câu lệnh " If Ran.Cells(d, c) > max Then max = Ran.Cells(d, c) "
trong ví du:
Public Function LonNhat(Ran As Range)
Dim max As Double, v As Integer, d As Integer, c As Integer
max = Ran.Cells(1, 1)
For d = 1 To Ran.Rows.Count
For c = 1 To Ran.Columns.Count
If Ran.Cells(d, c) > max Then max = Ran.Cells(d, c)
Next c
Next d
v = Tim(max, Ran)
LonNhat = max
End Function
-------------------------------------------------------
[INFO1]Thông báo:
Vì topic này:
http://www.giaiphapexcel.com/forum/...ải-thích-các-code-đề-nghị-các-bạn-gửi-vào-đây
đã quá dài nên BQT đóng lại.
Nay tôi mở topic mới với cùng chủ đề: GIẢI THÍCH NHỮNG THẮC MẮC VỀ CODE
Các bạn nếu có nhu cầu giải thích code, vui lòng post tại đây nhé
NDU96081631

[/INFO1]
 
Chỉnh sửa lần cuối bởi điều hành viên:
Lần chỉnh sửa cuối:
Upvote 0
Tại có duy nhất 1 control nên không xảy ra sự kiện :) (có đi đâu đâu mà buộc ở lại)
Vẽ thêm 1 control bất kỳ đi
Có vậy mà like xong đành đoạn gỡ ra
Chính xác cái Em cần ... Mà tiện cho Em hỏi chút mà cớ sao phải cho 2 control trở lên nó mới có tác dụng là sao ???!!!!!!!! :D:p
 
Upvote 0
Chính xác cái Em cần ... Mà tiện cho Em hỏi chút mà cớ sao phải cho 2 control trở lên nó mới có tác dụng là sao ???!!!!!!!! :D:p
Các sự kiện Before update, after update, enter, exit của 1 control (loại nhập liệu) chỉ xảy ra khi vào hoặc ra khỏi control. Phải có control thứ 2 mới có chuyện từ đâu vào hoặc ra rồi đi đâu chứ?
Thí dụ như bị nhốt trong nhà (chung quanh không có gì hết) thì làm gì có chuyện mở cửa đi chơi hay về mở cửa vào nhà
 
Upvote 0
Em xin chào các thầy cô, anh chị trên diễn đàn.
Có 1 thắc mắc này nhờ mọi người trả lời giúp được không ạ?

1. Hiện tại em đang muốn duyệt qua từng file được chọn ( Ví dụ kích vô nút nó sẽ hiện lên đường dẫn foder => chọn những file muốn chọn).

Sau đó nó sẽ mở từ file lên và đưa vùng dữ liệu (vùng này cũng được khai báo trước) trong 1 sheet chỉ định vào mảng.
Mỗi 1 file mở lên sẽ được tạo thành 1 mảng riêng biệt ( Chẳng hạn em chọn 3 file, thì nó sẽ tạo ra 3 mảng Arr trong Locals).

2. Nếu như làm được 1. Vùng dữ liệu và tên sheet lấy dữ liệu trong file con sẽ khai báo bằng biến trước được không ạ?

Do đây là cách em nghĩ. Không biết có khả thi không? Nên mạn phép nhờ thầy cô và mọi người chỉ giúp ạ.
Em xin cám ơn!
 
Upvote 0
Xin chào các bạn:
Hiện OT mong muốn sau khi chạy được dữ liệu sẽ xuất ra được kết quả là:
Mã:
INSERT INTO TABLE_NAME (Col1,Col2,Col3,Col4,Col5) VALUES
(Col1_data1,Col2_data1,Col3_data1,Col4_data1,Col5_data1),
(Col1_data2,Col2_data2,Col3_data2,Col4_data2,Col5_data2),
(Col1_data3,Col2_data3,Col3_data3,Col4_data3,Col5_data3),
(Col1_data4,Col2_data4,Col3_data4,Col4_data4,Col5_data4),
(Col1_data5,Col2_data5,Col3_data5,Col4_data5,Col5_data5)

Nhưng OT đã loay hoay suốt với đoạn code bên dưới , kết quả ra xuất ra không mong muốn, các dấu ngoặc "(" không xen kẽ sau các dấu "," như trên :
Mã:
INSERT INTO TABLE_NAME (Col1,Col2,Col3,Col4,Col5) VALUES
(((((Col1_data1,Col2_data1,Col3_data1,Col4_data1,Col5_data1),
Col1_data2,Col2_data2,Col3_data2,Col4_data2,Col5_data2),
Col1_data3,Col2_data3,Col3_data3,Col4_data3,Col5_data3),
Col1_data4,Col2_data4,Col3_data4,Col4_data4,Col5_data4),
Col1_data5,Col2_data5,Col3_data5,Col4_data5,Col5_data5)

Nhờ các bạn sửa giúp đoạn code trên cho OT với ạ.

Mã:
Option Explicit

Sub Test()

    Dim sh As Worksheet, arr As Variant, s As String
    Dim I As Long, J As Long, cName As String, iData As String
    Set sh = ThisWorkbook.Worksheets("DL")
    
    arr = sh.Range("D1").Resize(6, 5).Value2
    For J = 1 To UBound(arr, 2)
        If J = 1 Then
            cName = arr(1, J)
        Else
            cName = cName & "," & arr(1, J)
        End If
    Next J
          
    For I = 2 To UBound(arr, 1)
        For J = 1 To UBound(arr, 2)
            s = arr(I, J)
            If J = 1 And I = 2 Then
                iData = s
            Else
                iData = iData & "," & s
            End If
        Next J
        iData = "(" & iData & ")"
    Next I

    s = "INSERT INTO TABLE_NAME (" & cName & ") VALUES " & iData
    
    Debug.Print s
          
End Sub
 

File đính kèm

  • for.xlsm
    15.7 KB · Đọc: 4
Upvote 0
Xin chào các bạn:
Hiện OT mong muốn sau khi chạy được dữ liệu sẽ xuất ra được kết quả là:
Mã:
INSERT INTO TABLE_NAME (Col1,Col2,Col3,Col4,Col5) VALUES
(Col1_data1,Col2_data1,Col3_data1,Col4_data1,Col5_data1),
(Col1_data2,Col2_data2,Col3_data2,Col4_data2,Col5_data2),
(Col1_data3,Col2_data3,Col3_data3,Col4_data3,Col5_data3),
(Col1_data4,Col2_data4,Col3_data4,Col4_data4,Col5_data4),
(Col1_data5,Col2_data5,Col3_data5,Col4_data5,Col5_data5)

Nhưng OT đã loay hoay suốt với đoạn code bên dưới , kết quả ra xuất ra không mong muốn, các dấu ngoặc "(" không xen kẽ sau các dấu "," như trên :
Mã:
INSERT INTO TABLE_NAME (Col1,Col2,Col3,Col4,Col5) VALUES
(((((Col1_data1,Col2_data1,Col3_data1,Col4_data1,Col5_data1),
Col1_data2,Col2_data2,Col3_data2,Col4_data2,Col5_data2),
Col1_data3,Col2_data3,Col3_data3,Col4_data3,Col5_data3),
Col1_data4,Col2_data4,Col3_data4,Col4_data4,Col5_data4),
Col1_data5,Col2_data5,Col3_data5,Col4_data5,Col5_data5)

Nhờ các bạn sửa giúp đoạn code trên cho OT với ạ.

Mã:
Option Explicit

Sub Test()

    Dim sh As Worksheet, arr As Variant, s As String
    Dim I As Long, J As Long, cName As String, iData As String
    Set sh = ThisWorkbook.Worksheets("DL")
   
    arr = sh.Range("D1").Resize(6, 5).Value2
    For J = 1 To UBound(arr, 2)
        If J = 1 Then
            cName = arr(1, J)
        Else
            cName = cName & "," & arr(1, J)
        End If
    Next J
         
    For I = 2 To UBound(arr, 1)
        For J = 1 To UBound(arr, 2)
            s = arr(I, J)
            If J = 1 And I = 2 Then
                iData = s
            Else
                iData = iData & "," & s
            End If
        Next J
        iData = "(" & iData & ")"
    Next I

    s = "INSERT INTO TABLE_NAME (" & cName & ") VALUES " & iData
   
    Debug.Print s
         
End Sub
Cảm ơn mọi người OT đã xử lý được rồi ạ, mặc dù nó hơi dài ạ:
Mã:
...
    For I = 2 To UBound(arr, 1)
        For J = 1 To UBound(arr, 2)
            s = arr(I, J)
            If J = 1 And I = 2 Then
                iData = "(" & s
            ElseIf J = 1 Then
                iData = iData & ",(" & s
            Else
                iData = iData & "," & s
            End If
        Next J
        iData = iData & ")"
    Next I
    ...
Nếu Bạn nào có cách làm khác cho OT tham khảo với ạ.
 
Upvote 0
Cảm ơn mọi người OT đã xử lý được rồi ạ, mặc dù nó hơi dài ạ:

Dùng câu lệnh "INSERT INTO..." nó còn liên quan đến kiểu dữ liệu được qui định của từng cột trong Table nữa nhé. Ví dụ: kiểu Text phải để trong dấu ngoặc đơn, kiểu số không cần, kiểu Date thì dấu #..# (cho table Access)... Chú ý vụ này.
 
Upvote 0
PHP:
Option Explicit

Sub Test()
    Const prefix = "INSERT INTO TABLE_NAME  ("
    Dim sh As Worksheet, arr As Variant, s As String
    Dim i As Long, ub As Long
    Set sh = ThisWorkbook.Worksheets("DL")
    Dim dong1 As String, res As Variant
    
    arr = sh.Range("D1").Resize(6, 5).Value2
    'dong 1
    dong1 = join_by_row(arr, 1) & ") VALUES "
    ub = UBound(arr, 1)
    ReDim res(2 To ub)
    'khuc duoi
    For i = 2 To UBound(arr, 1)
        res(i) = "(" & join_by_row(arr, i) & ")"
    Next i
    s = prefix & dong1 & Join(res, ",")
    MsgBox s
End Sub

Private Function join_by_row(ByVal data_ As Variant, ByVal irow_ As Long, _
                             Optional ByVal sdeli As String = ",")
    'noi cac phan tu cua data_ trong dong irow_, boi dau phay
    'data_: mang du lieu
    'irow_: dong can xet
    Dim ub As Long, i As Long, res As Variant
    ub = UBound(data_, 2)
    ReDim res(1 To ub)
    For i = 1 To ub
        res(i) = data_(irow_, i)
    Next i
    join_by_row = Join(res, sdeli)
    Erase res
End Function
 
Upvote 0
Dùng câu lệnh "INSERT INTO..." nó còn liên quan đến kiểu dữ liệu được qui định của từng cột trong Table nữa nhé. Ví dụ: kiểu Text phải để trong dấu ngoặc đơn, kiểu số không cần, kiểu Date thì dấu #..# (cho table Access)... Chú ý vụ này.
Xin chào anh ongke0711,
Cảm ơn Anh đã chỉ dẫn ạ ,
OT đã hiểu thêm được một chút về CSDL nghĩa là trước khi ghi dữ liệu vào thì cần phải kiểm tra data_type của từng trường sau đó sẽ gán giá trị tùy thuộc và từng kiểu trường đó ạ.

PHP:
Option Explicit

Sub Test()
    Const prefix = "INSERT INTO TABLE_NAME  ("
    Dim sh As Worksheet, arr As Variant, s As String
    Dim i As Long, ub As Long
    Set sh = ThisWorkbook.Worksheets("DL")
    Dim dong1 As String, res As Variant
   
    arr = sh.Range("D1").Resize(6, 5).Value2
    'dong 1
    dong1 = join_by_row(arr, 1) & ") VALUES "
    ub = UBound(arr, 1)
    ReDim res(2 To ub)
    'khuc duoi
    For i = 2 To UBound(arr, 1)
        res(i) = "(" & join_by_row(arr, i) & ")"
    Next i
    s = prefix & dong1 & Join(res, ",")
    MsgBox s
End Sub

Private Function join_by_row(ByVal data_ As Variant, ByVal irow_ As Long, _
                             Optional ByVal sdeli As String = ",")
    'noi cac phan tu cua data_ trong dong irow_, boi dau phay
    'data_: mang du lieu
    'irow_: dong can xet
    Dim ub As Long, i As Long, res As Variant
    ub = UBound(data_, 2)
    ReDim res(1 To ub)
    For i = 1 To ub
        res(i) = data_(irow_, i)
    Next i
    join_by_row = Join(res, sdeli)
    Erase res
End Function

Xin chào befaint,
Cảm ơn Bạn rất nhiều.
-------
Chúc mọi người vui khỏe.
OT
Bài đã được tự động gộp:

Dùng câu lệnh "INSERT INTO..." nó còn liên quan đến kiểu dữ liệu được qui định của từng cột trong Table nữa nhé. Ví dụ: kiểu Text phải để trong dấu ngoặc đơn, kiểu số không cần, kiểu Date thì dấu #..# (cho table Access)... Chú ý vụ này.

Xin chào Anh ongke0711,
Nhờ anh chỉ dâ thêm có phải SQL chỉ cho phép "INSERT INTO ..." 1000 dòng 1 lúc được thôi phải không phải không ạ?
OT thử thì vượt quá hệ thống không cho phép báo lỗi, và xóa <=1000 thì OK ạ.
Cảm ơn Anh ạ.
 
Lần chỉnh sửa cuối:
Upvote 0
Nhờ anh chỉ dâ thêm có phải SQL chỉ cho phép "INSERT INTO ..." 1000 dòng 1 lúc được thôi phải không phải không ạ?
OT thử thì vượt quá hệ thống không cho phép báo lỗi, và xóa <=1000 thì OK ạ.

Theo code trên thì em đang dùng kiểu Insert mới có từ SQL Sv 2008 trở lên: dùng Table Value và cách này bị giới hạn 1.000 dòng là đúng rồi.
Anh chưa dùng cách này nhưng em biến tấu nó chút:

Mã:
INSERT INTO TABLE_NAME (Col1,Col2,Col3,Col4,Col5)
SELECT Col1_data1,Col2_data1,Col3_data1,Col4_data1,Col5_data1
UNION ALL SELECT Col1_data2,Col2_data2,Col3_data2,Col4_data2,Col5_data2
UNION ALL SELECT Col1_data3,Col2_data3,Col3_data3,Col4_data3,Col5_data3
...

Hoặc:

Mã:
INSERT INTO TABLE_NAME (Col1,Col2,Col3,Col4,Col5)
SELECT * FROM (VALUES
(Col1_data1,Col2_data1,Col3_data1,Col4_data1,Col5_data1),
(Col1_data2,Col2_data2,Col3_data2,Col4_data2,Col5_data2),
(Col1_data3,Col2_data3,Col3_data3,Col4_data3,Col5_data3),
(..),
...
) AS TEMP (Col1,Col2,Col3,Col4,Col5);
 
Upvote 0
Em mới vào nghề đang học cơ bản về VBA
Có đoạn video dạy trên mạng. Em gõ code theo để chạy thử.
Nhưng code báo lỗi khi khai báo function.
Nhờ mọi người chỉ dạy hộ em, code bị sai chỗ nào
 

File đính kèm

  • VD Function.xlsm
    13.7 KB · Đọc: 5
Upvote 0
Em mới vào nghề đang học cơ bản về VBA
Có đoạn video dạy trên mạng. Em gõ code theo để chạy thử.
Nhưng code báo lỗi khi khai báo function.
Nhờ mọi người chỉ dạy hộ em, code bị sai chỗ nào
Theo mình thấy code bạn bị sai cú pháp, bạn chỉnh thử ở đoạn này
Mã:
demchuoiso = "co " & k & " so va co " & l & " chuoi "
 

File đính kèm

  • Function Dem Chuoi 83698#2552.xlsm
    14.3 KB · Đọc: 3
Upvote 0
Mình mới học VBA. Các bạn giải thích giúp mình đoạn Code sau sai ở đâu ?
Mã:
Public sh As String
Sub bieuTK1()
ThisWorkbook.Worksheets.Add after:=Sheets(Sheets.Count)
 Sheets(Sheets.Count).Name = "B1"
 'ThisWorkbook.VBProject.VBComponents(ThisWorkbook.Worksheets("B1").CodeName).Name = "TK1"
Set sh1 = Sheets("B1").CodeName
sh1.Range("A2").Select
End Sub

Toàn báo lỗi ở đoạn này Set sh1 = Sheets("B1").CodeName mà mình khhông hiểu tại sao ?
 
Upvote 0
Mình mới học VBA. Các bạn giải thích giúp mình đoạn Code sau sai ở đâu ?
Mã:
Public sh As String
Sub bieuTK1()
ThisWorkbook.Worksheets.Add after:=Sheets(Sheets.Count)
Sheets(Sheets.Count).Name = "B1"
'ThisWorkbook.VBProject.VBComponents(ThisWorkbook.Worksheets("B1").CodeName).Name = "TK1"
Set sh1 = Sheets("B1").CodeName
sh1.Range("A2").Select
End Sub
Toàn báo lỗi ở đoạn này Set sh1 = Sheets("B1").CodeName mà mình khhông hiểu tại sao ?
Sh1 là tham biến & tệ là bạn chưa khai báo kiểu dữ liệu cho nó; Nhưng bạn buộc máy phải hiểu đó là biến đối tượng.
Vậy bạn xem vế thứ 2 của biểu thức 'gán' đó có kiểu dữ liệu là gì chưa?
 
Upvote 0
Sheets("B1").CodeName là 1 giá trị chuỗi (code name của 1 sheet). Set dùng để gán giá trị đối tượng cho 1 biến. Thế là lỗi Type MisMatch
 
Upvote 0
Mình phải sửa như nào, Sheet(“B1”).CodeName mình vẫn phải khai biến sao. Biến sh1 mình đã khai báo là Public as string không đúng sao bạn. Mình phải sửa thế nào mong các anh chị thầy cô diễn đàn sửa giúp
 
Upvote 0
Khai báo As String là kiểu chuỗi, không gán đối tượng worksheet được.
Khai báo worksheet thì được, nhưng không gán chuỗi vào được
Với code bài 1 thì chỉ cần bỏ .CodeName ra:

Mã:
Set sh1 = Sheets("B1")
 
Upvote 0
Set là lệnh gán địa chỉ của đối tượng cho một biến đối tượng.
(nếu bạn không hiểu câu trên thì nên chịu khó bỏ thời giờ học về biến, kiểu biến, đối tượng và lệnh let/set)

Trong code của bạn, cần sửa:
Set sh1 = Sheets("B1").CodeName
sh1.Range("A2").Select
thành:
sh1 = Sheets("B1").CodeName ' sh1 bây giờ là kiểu chuỗi chứ không phải kiểu đối tượng
For Each sh In Sheets
If sh.CodeName = sh1 Then sh.Range("A2").Select ' sh1 là khoá để lọc ra cái sheet có tên CodeName
Next Sh

Chú:
VBA có hai hạng biến (ở đây nói hạng chứ không phải loại): hạng đơn giản và hạng phức tạp.
Lệnh gán trong VBA chia ra thành Let cho hạng đơn giản và Set cho hạng phức tạp.
Về sau này, VBA tự đơn giản bằng cách hiểu ngầm "Let". Vì vậy, lệnh gán hạng đơn giản khogn cần phải có từ khoá Let
Let A = B bây giờ viết là A = B (giá trị của B được cóp qua A)
Tuy nhiên, lệnh gán hạng phức tạp vẫn không được đơn giản hoá. Vẫn phải dùng Set.
Lênh Set có nghĩa là cóp địa chỉ của đối tượng, không phải trị của đối tượng.
Set A = B có nghĩa là A và B sẽ cùng chỉ vào chung một đối tượng.
 
Lần chỉnh sửa cuối:
Upvote 0
Anh/chị có thể viết cho em 1 module insert thêm dòng từ sheet dữ liệu ban đầu sau khi chạy thì ra kết quả như sheet kết quả mong muốn của em không ạ. Em cảm ơn rất nhiều.
 

File đính kèm

  • sample.xlsx
    9.4 KB · Đọc: 6
Upvote 0
Mình có file code VBA như file đính kèm.
Mục đích file này, giúp công nhân giảm thiểu thời gian gõ bàn phím (ví dụ : trong file đã thiết lập nút bấm KEYSET, để công nhân nhập 53.8 vào excel, thay vì phải gõ 53.8, chỉ cần gõ 7 là tự động nhập 53.8 vào cell).

Tuy nhiên, mình đang mới học cơ bản về VBA. Mình vẫn chưa hiểu được thuật toán trong code. Nhờ các bác chỉ dạy giúp em các điểm dưới đây :
1. Sub TIMDEY() có tác dụng gì
2. Userform Macro1 (nút bấm START). Trong code UserForm1.Show, theo em hiểu khi ấn START, thì nó sẽ hiện userform1 lên thôi. Tại sao, ấn nút START này, nó lại liên kết chạy được cả code Sub WR(). Từ đó dẫn đến mình có thể thao tác gõ phím tắt thông qua Keyset
3. Code Sheet2.Cells(J, I).Value = KEYDAT(KEYINDX)
Em tìm trên mạng, hay thư viện đều không tìm thấy hướng dẫn về KEYDAT. Các bác chỉ em cách dùng KEYDAT, hoặc link có nói về nó. Trong code của file, cũng không thấy có code nào liên kết với keyset. Tại sao KEYSET lại hoạt động được.

Sorry bài viết em có gì khó hiểu mong các bác phản hồi.

Thanks
 

File đính kèm

  • VD Keydat.xlsm
    60.5 KB · Đọc: 5
Lần chỉnh sửa cuối:
Upvote 0
Web KT
Back
Top Bottom