• Kỹ thuật không cho lưu dữ liệu (Undo) ở Subform dạng Datasheet
  • Kỹ thuật không cho lưu dữ liệu (Undo) ở Subform dạng Datasheet

    ongke0711 > 17-03-20, 02:02 PM

    Kỹ thuật huỷ lưu dữ liệu sau khi nhập liệu cho Form ở dạng Main - SubForm.
    -------------------------------------------------------------------------------------------------------------------------------  

    Có nhiều bạn khi thiết kế Form nhập liệu vướng phải vấn đề là:
    - Sau khi nhập liệu xong, sai, không muốn lưu thì làm sao? vì Access đã tự động lưu dữ liệu xuống Table khi bạn di chuyển con trỏ (nhảy) qua dòng khác.
    - Khi đã nhập liệu nhiều dòng trong SubForm (dạng Datasheet hoặc Continuous) rồi, giờ muốn huỷ tất cả các dòng vừa nhập  thì làm như thế nào?

    Ở bài này tôi sẽ nói về Form nhập liệu ở dạng Mainform-SubForm. Nếu Form dạng Single Form thì việc "Undo" dữ liệu vừa nhập đã có nhiều bài hướng dẫn rồi. Các bạn có thể tìm kiếm trên diễn đàn, xem thêm bài của bác XuanThanh.
    Link: https://thuthuataccess.com/forum/thread-5350.html

    Để bàn tới các thủ thuật Huỷ (Undo) lưu dữ liệu khi nhập liệu thì các bạn phải xét tới việc thiết kế Form theo kiểu nào, dạng Unbound Form hay Bound Form vì cách thức xử lý sẽ khác nhau. 
    - Bound Form là Form có gắn với Record Source (Table, Query) và các control (Textbox, combo...) cũng có Control Source là tên các Field tron Table, Query tương ứng.
    - Unbound Form: là Form không có có Record Source và các control trên Form cũng vậy - không có control source.

    1. Bound Form:
     Đây là điểm mạnh của Access. Nó hỗ trợ việc di chuyển tới lui các record, lưu , thêm, sửa xoá v.v.. rất nhanh, không tốn nhiều code để thực hiện các tác vụ trên như Unbound Form. Một điểm hay cũng là điểm bất tiện của nó là việc Lưu dữ liệu. Sau khi nhập liệu, chỉ cần di chuyển con trỏ chuột qua dòng khác là dữ liệu lưu ngay xuống Table, không cần phải code cho nút Lưu. Nhưng điểm bất tiện của tính năng này là: khi người dùng không muốn Lưu dữ liệu vừa thay đổi đó thì phải viết code để trả lại dữ liệu ban đầu. Vấn đề này sẽ phức tạp hơn nếu nhập liệu nhiều dòng trong liên tiếp như trong Form dạng Datasheet hoặc Continuous.  Khi đó ta không thể chạy code của sự kiên Form_ BeforeUpdate vì Access sẽ bật thông báo hỏi có muốn Lưu hay không mỗi khi qua dòng mới, nhập liệu 1 chục dòng , bấm nút trả lời 1 chục lần. Thường thì sau khi nhập 1 lúc nhiều dòng thì người dùng mới bấm Lưu, khi đó thì dữ liệu của Subform cũng đã lưu xuống table rồi, vậy hồi lại các dòng cũ như thế nào. Các giải pháp cho trường hợp này như sau: 
    - Dùng Table tạm làm RecordSource cho Subform, khi nào bấm nút Lưu sẽ chạy lệnh "INSERT INTO..." ghi dữ liệu xuống Table. Hoặc
    - Xoá các record vừa nhập dựa trên Khoá ngoại (Foreign Key) của dữ liệu vừa thêm vào. Thiết lập Relationship với tuỳ chọn "Cascade Delete Related Record" để khi xoá 1 dòng trong Table Cha thì nó tự động xoá luôn nhiều dòng liên quan trong Table Con thông qua khoá ngoại.
    - Dùng DAO Transaction như bài bạn maidinhdan vừa chia sẻ.

    2. Unbound Form:
    Dùng dạng này sẽ ít tốn code cho việc bẫy lỗi khi Lưu, Huỷ lưu dữ liệu. Nhưng phải tốn code để tải dữ liệu lên Form khi Form khởi chạy (Form_Load). Tôi thì thích kiểu nàyn
    Mặc dùng là Unbound Form nhưng khi thiết kế ở dạng có Subform đi kèm thì lại phải kết hợp vừa Unbound cho Main form và Bound cho Subform. Không có cách gì thiết kế nhập liệu nhiều dòng cho Subform ở dạng Unbound cả.
    Tuỳ sở thích lập trình mà dev chọn kiểu Unbound hay Bound. Tôi thì thích dùng cách Unbound phối hợp như trên hơn.

    Giới thiệu cơ bản với các bạn về các kiểu Form để hiểu tại sao phải có các kỹ thuật xử lý khác nhau khi muốn Huỷ lưu trên Form nhập liệu. Sau đây tôi sẽ lần lượt giới thiệu demo các cách xử lý theo từng kiểu Form.

    -----------------------------------------------------------------------------------------------------------------------------------------
    Phần 1:  Bound Form với thiết kế có Main - Subform

    - Không dùng Table tạm cho Subform.
    - Dùng kỹ thuật DAO Transaction (bạn maidinhdan vừa giới thiệu cho nó nóng sốt 014 ).

    Đây là demo nhập liệu Phiếu Nhập/ Xuất cho của một chương trình bán hàng đơn giản. Tôi thiết kế theo quan điểm cá nhân là:
    - Có 1 Form danh sách các phiếu nhâp/xuất để có cái nhìn tổng quát các PN/PX đã phát sinh. Đây cũng là Form tìm kiếm luôn.
    - Từ Form Danh sách sẽ Xem chi tiết hoặc Sửa các PN/ PX khi double-click vào nó. Có thể thêm mới phiếu từ Form này.
    - Các thức tôi code cho form này là:
       + Dùng Bound Form nhưng không gán sẳn Record Source cho Form mà chi khi Load lên mới gán bằng câu lệnh SQL.
       + Khai báo một Workspace. Khi nạp dữ liệu cho Form sẽ bắt đầu transaction: WS.BeginTrans. Khi lưu sẽ WS.CommitTrans. Khi Huỷ sẽ: WS.Rollback. Vì Workspace sẽ có tác động lên toàn bộ Recordset nào đã khai báo khi BeginTrans. 
    - Chú ý thứ tự code ở các events, nếu sai chút là báo lỗi tùm lùm 014 .


    Link demo: https://drive.google.com/open?id=1O0HjQ5...D1ezktg8R5


    [Hình: 49667897188_511586ff14_o.png]


    Code của frmNhap: 

    Mã PHP:
    Option Compare Database
    Option Explicit

    Dim arrArgs
    () As String

    Private Sub cmdClose_Click()
        Set WS Nothing    'Phai dóng WS, neu không Access không thoát hoan toàn.
        DoCmd.Close
    End Sub

    Private Sub cmdHuy_Click()
        WS.Rollback
        WS.BeginTrans
        Me.Refresh  '
    Tránh báo lõi #name khi click nhieu lan.
    End Sub

    Private Sub cmdLuu_Click()

        WS.CommitTrans
        SetFormState False
        Me
    .Recalc  'De AllowEdit có tác dung

        '
    Requery các form liên quan
        Select 
    Case arrArgs(2)
        Case "frmDSPhieuNhapXuat"
            Forms!frmDSPhieuNhapXuat!sfmDSPhieuNX.Requery
        
    Case Else
            'do nothing
        End Select


    End Sub

    Private Sub cmdThem_Click()

        '
    Xu ly WS de tranh loi khi them moi.
        If Me.cmdLuu.Enabled True Then
            
    If msgBoxUni("B" ChrW(7841) & "n có mu" ChrW(7889) & "n L" ChrW(432) & "u d" ChrW(7919) & " li" ChrW(7879) & "u hi" ChrW(7879) & "n t" ChrW(7841) & "i tr" ChrW(432) & ChrW(7899) & "c khi m" ChrW(7903) & " phi" ChrW(7871) & "u m" ChrW(7899) & "i?"vbQuestion vbYesNo"Thông báo") = vbYes Then
                WS
    .CommitTrans  'Phai ket thuc phiên Transaction cu, moi gan rs cho subF duoc.
            Else
                WS.Rollback
            End If
        End If

        arrArgs(0) = "Add"
        NapPhieuNhap
        
        SetFormState True

    End Sub

    Private Sub Form_Load()

        Set WS = DBEngine.Workspaces(0)

        If Len(Nz(Me.OpenArgs, "")) > 0 Then
            arrArgs = Split(Me.OpenArgs, "|")
        Else    '
    Mo tu Menu
            ReDim arrArgs
    (0 To 2) As String
            arrArgs
    (0) = "Add"
            arrArgs(1) = ""
            arrArgs(2) = ""
        End If

        NapPhieuNhap

    End Sub

    Sub NapPhieuNhap
    ()
        Dim db As DAO.Database
        
    'Dim rs As DAO.Recordset, rs2 As DAO.Recordset  '-->Khai báo toàn cuc
        Dim strSQL 
    As StringstrSQL2 As String

        Set db 
    CurrentDb
        Select 
    Case arrArgs(0)
        Case "Add"
            strSQL "SELECT * FROM tblNhapXuat WHERE 1=2"
            strSQL2 "SELECT 'Xóa' As Xoa,* FROM tblNhapXuat_CT WHERE 1=2"
        Case "Edit"
            strSQL "SELECT * FROM tblNhapXuat WHERE ID=" arrArgs(1)
            strSQL2 "SELECT 'Xóa' As Xoa, * FROM tblNhapXuat_CT WHERE IDPhieu=" arrArgs(1)
        End Select

        Set rs 
    Nothing    'Tránh lõi khi gán rs moi, khi chon dòng khác - Sua
        Set rs = db.OpenRecordset(strSQL, dbOpenDynaset)
        Set Me.Recordset = rs
        Set rs2 = Nothing
        Set rs2 = db.OpenRecordset(strSQL2, dbOpenDynaset)
        If rs2.BOF And rs2.EOF Then
            '
    Bãy lôi khi mo recordset thêm moiChua có du lieu de MoveLast.
        Else
            rs2.MoveLast  'Phai activate rs2 de lay toàn bo record gán vào SubF, neu không se treo ung dung.
        End If
        Set Me.sfmNhapXuatCT.Form.Recordset = rs2

        WS.BeginTrans

    End Sub

    Sub SetFormState(blnState As Boolean)
        Me.cmdClose.SetFocus
        Me.cmdLuu.Enabled = blnState
        Me.cmdHuy.Enabled = blnState
        Me.cmdThem.Enabled = blnState
        Me.AllowEdits = blnState
        Me.cmdThem.Enabled = Not blnState
        Me.sfmNhapXuatCT.Locked = Not blnState
    End Sub 


    ----------------------------------------------------------------------------------------------------------------------------
    Bài kế tiếp sẽ làm demo kỹ thuật khác cho UnBound Form với thiết kế có Main - Subform
  • RE: Kỹ thuật không cho lưu dữ liệu (Undo) ở Subform dạng Datasheet

    dotrung > 23-03-20, 06:37 PM

    Đang hóng kỹ thuật UnBound Form với thiết kế có Main - Subform của anh Ongke, đặc biệt trên class modules
  • RE: Kỹ thuật không cho lưu dữ liệu (Undo) ở Subform dạng Datasheet

    ongke0711 > 01-04-20, 01:35 AM

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

    Phần 2: Unbound Form với thiết kế kiểu Main - Subform


    - Dùng table tạm cho Subform. Như đã nói ở bài trước Subform dạng Datasheet hoặc Continuous phải ở dạng Bound Form mới hiển thị nhiều dòng được. 
    - Đây là kiểu kết hợp Unbound (MainF) với Bound Form (SubF).

    Cách thức xử lý của Form này:
    - Khi Form được mở lên để Sửa một phiếu Nhâp/ xuất nào đó sẽ dùng hàm để lọc, lấy ra record từ table chính rồi gán lên các Unbound textbox trên MainForm. Song song đó sẽ load bộ record cần sửa vào table tạm làm nguồn cho Subform.
    - Vì là Unbound Form và gắn với table tạm nên sau khi nhập liệu, nếu không muốn lưu thì chỉ cần đóng form là xong, không cần phải Undo dữ liệu đã nhập. Ngược lại thì muốn Lưu bạn phải dùng code để ghi toàn bộ dữ liệu trên Form vào các table chính.

    Trong file demo này tôi có kèm theo các kỹ thuật như:
    - Tham số OpenArgs: dùng để truyền các tham số từ Form trước qua Form sau theo yêu cầu.
    - Hàm kiểm tra các Textbox có rỗng hay không trước khi lưu dữ liệu. Hàm duyệt qua tất cả các control trên form để kiểm tra chứ không cần phải viết từng dòng code kiểm tra cho từng Textbox như: If IsNull(txtNgay) Then ....
    - Hàm tải record lên Unbound Form, cập nhật, thêm mới. Tận dụng thuộc tính Tag của Form property phục vụ cho code.
    - Các bẫy lỗi khi form không có dữ liệu, bẫy lỗi để form hoạt động trơn tru.

    Hình minh hoạ bẫy lỗi các Textbox buộc phải có dữ liệu, không được để trống.

    [Hình: 49720911836_5093b6a335_o.png]



    Đây là bộ code cho các hàm lấy dữ liệu, cập nhât, thêm mới dữ liệu cho Unbound Form. Copy vào Module.

    Mã PHP:
    Option Compare Database
    Option Explicit

    Function GetRecord(rs As DAO.Recordsetfrm As Form)
    On Error GoTo ErrHandler
        Dim fld 
    As Field
        Dim ctl 
    As control

        
    For Each fld In rs.Fields
            
    For Each ctl In frm.Controls
                
    If ctl.Name "txt" fld.Name Or ctl.Name "cbo" fld.Name Or ctl.Name "chk" fld.Name Or ctl.Name "fra" fld.Name Then
                    ctl 
    rs.Fields("" fld.Name "").Value
                
    ElseIf ctl.Name "img" fld.Name Then
                    
    If Not IsNull(rs.Fields("" fld.Name "").ValueThen
                        On Error Resume Next
                        ctl
    .Picture CStr(rs.Fields("" fld.Name "").Value)
                    End If
                End If
            Next
        Next

        
    'rs.Close  '-> Không closede tái su dung cho hàm Update/Add trong form
        
    'Set rs = Nothing'
        Exit Function

    Exit_ErrHandler:
        On Error Resume Next
        rs
    .Close
        Set rs 
    Nothing
        
    Exit Function

    ErrHandler:
        msgBoxUni "Mã l" ChrW(7895) & "i: " Err.Number vbCrLf _
                  
    "N" ChrW(7897) & "i dung l" ChrW(7895) & "i: " Err.DescriptionvbCritical"Get Record Error"
        Resume Exit_ErrHandler

    End 
    Function

    Function 
    AddRecord(rs As DAO.Recordsetfrm As Form)

        On Error GoTo ErrHandler
        Dim fld 
    As Field
        Dim ctl 
    As control

        rs
    .AddNew
        
    For Each fld In rs.Fields
            
    For Each ctl In frm.Controls
                
    If ctl.Name "txt" fld.Name Or ctl.Name "cbo" fld.Name Or ctl.Name "chk" fld.Name Then
                    rs
    .Fields("" fld.Name "").Value ctl
                End 
    If
            Next
        Next
        rs
    .Update

        
    'rs.Close
        '
    Set rs Nothing
        
    Exit Function

    Exit_ErrHandler:
        On Error Resume Next
        rs
    .Close
        Set rs 
    Nothing
        
    Exit Function

    ErrHandler:
        msgBoxUni "L" ChrW(432) & "u d" ChrW(7919) & " li" ChrW(7879) & "u th" ChrW(7845) & "t b" ChrW(7841) & "i." vbCrLf vbCrLf _
                  
    "Mã l" ChrW(7895) & "i: " Err.Number vbCrLf _
                  
    "N" ChrW(7897) & "i dung l" ChrW(7895) & "i: " Err.DescriptionvbCritical"Add Record Error"
        Resume Exit_ErrHandler

    End 
    Function

    Function 
    UpdateRecord(rs As DAO.Recordsetfrm As Form)
        On Error GoTo ErrHandler

        Dim fld 
    As Field
        Dim ctl 
    As control

        rs
    .Edit
        
    For Each fld In rs.Fields
            
    For Each ctl In frm.Controls
                
    If ctl.Tag Like "no" Then
                    
    'do nothing'
                Else
                    If ctl.Name "txt" fld.Name Or ctl.Name "cbo" fld.Name Or ctl.Name "chk" fld.Name Then
                        rs
    .Fields("" fld.Name "").Value ctl
                    End 
    If
                End If
            Next ctl
        Next fld
        rs
    .Update
        
    'fMsgBox getMes(26), vbInformation, getTit(1)'

        'rs.Close
        '
    Set rs Nothing
        
    Exit Function

    Exit_ErrHandler:
        On Error Resume Next
        rs
    .Close
        Set rs 
    Nothing
        
    Exit Function

    ErrHandler:
        msgBoxUni "L" ChrW(432) & "u d" ChrW(7919) & " li" ChrW(7879) & "u th" ChrW(7845) & "t b" ChrW(7841) & "i." vbCrLf vbCrLf _
                  
    "Mã l" ChrW(7895) & "i: " Err.Number vbCrLf _
                  
    "N" ChrW(7897) & "i dung l" ChrW(7895) & "i: " Err.DescriptionvbCritical"Update Record Error"

        Resume Exit_ErrHandler

    End 
    Function

    Public 
    Sub ClearRecord(frm As Form)
        Dim ctl As control
        
    For Each ctl In frm.Controls
            
    If ctl.Tag Like "no" Then
                
    'do nothing'
            Else
                Select Case ctl.ControlType
                
    Case acTextBoxacComboBox
                    ctl
    .Value ""
                Case acCheckBox
                    ctl
    .Value False
                
    Case acImage
                    ctl
    .Picture ""
                Case Else
                    'do nothing'
                End Select
            End 
    If
        Next
    End Sub 

    >> Để dùng các hàm này lấy dữ liệu lên Form thì các Control (Textbox, combo, checkbox...) phải tuân theo qui tắc đặt tên là: "txt" + tên Field dùng trong table. Tiền tố là 3 ký tự: "txt" - cho Textbox; "cbo" - cho ComboBox; "chk" - cho CheckBox...

    [Hình: 49720985936_d8372e000b_o.png]



    Sau đây là link file demo. Các bạn download về từ từ ngâm cứu.

    Link: https://drive.google.com/open?id=1wxpmOa...-oigvGFrLk

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

    Bài tiếp sẽ nói về cách: Dùng OpenArgs để truyền tham số từ Form này qua Form khác.
  • RE: Kỹ thuật không cho lưu dữ liệu (Undo) ở Subform dạng Datasheet

    dotrung > 01-04-20, 10:29 PM

    anh Bảo quả thật cao thủ, trước giờ em không biết phần nạp tham số unbound, cảm ơn anh Ongke0711 rất nhiều.
  • RE: Kỹ thuật không cho lưu dữ liệu (Undo) ở Subform dạng Datasheet

    huuduy.duy > 16-04-20, 04:10 PM

    (01-04-20, 01:35 AM)ongke0711 Đã viết: -----------------------------------------------------------------------------------------

    Phần 2: Unbound Form với thiết kế kiểu Main - Subform
    [Hình: 49720911836_5093b6a335_o.png]

    Do yêu cầu công việc phải chọn nhiều nhân viên từ Danh sách nhân viên chung, nên em thay Subform thành Listbox  để chọn nhân viên qua lại giữ 2 Listbox.

    Phần Form Phiếu Yêu cầu đào tạo: sẽ cập nhật thông tin như: 
    1/ Người yêu cầu, nội dung yêu cầu, Thời gian đào tạo, Nơi đào tạo, .. cập nhật vào bảng tblPhieuYeuCau
    2/ Mỗi phiếu Yêu cầu như vậy sẽ chọn ra danh sách nhân viên từ 1 danh sách nhân viên chung của Cty cần đào tạo theo nội dung đó và ghi bảng tblNhanVienDaDaoTao.

    Em lầm đến đoạn gọi Phiếu Yêu cầu lên để bổ sung thêm nhân viên cần đào tạo thì bị lỗi. Nhờ anh xem giúp
    Trân trọng cảm ơn
    Link
    ** Ngoài cách sử dụng Listbox, thì mình có thể sủ dụng Subform có checkbox để check những nhân viên cần chọn được không anh
    [img][Hình: 1.png]http://[/img]
  • RE: Kỹ thuật không cho lưu dữ liệu (Undo) ở Subform dạng Datasheet

    Xuân Thanh > 16-04-20, 10:15 PM

    1/ Gọi hết danh sách nhân viên đưa vào list bên phải
    2/ Cái list bên trái chỉ làm list tạm. Sau khi đưa hết danh sách đã chọn từ list bên phải qua thì mới cập nhật vào tblPhieuYeuCau
  • RE: Kỹ thuật không cho lưu dữ liệu (Undo) ở Subform dạng Datasheet

    huuduy.duy > 16-04-20, 11:27 PM

    (16-04-20, 10:15 PM)Xuân Thanh Đã viết: 1/ Gọi hết danh sách nhân viên đưa vào list bên phải
    2/ Cái list bên trái chỉ làm list tạm. Sau khi đưa hết danh sách đã chọn từ list bên phải qua thì mới cập nhật vào tblPhieuYeuCau
    Cái này được rồi anh.
    Chỉ còn 1 cái là gọi lại cái đã nhập để bổ sung thêm nhân viên từ bên phải vào bên trái ạ
  • RE: Kỹ thuật không cho lưu dữ liệu (Undo) ở Subform dạng Datasheet

    Xuân Thanh > 16-04-20, 11:30 PM

    (16-04-20, 11:27 PM)huuduy.duy Đã viết: Cái này được rồi anh.
    Chỉ còn 1 cái là gọi lại cái đã nhập để bổ sung thêm nhân viên từ bên phải vào bên trái ạ

    Thì lôi ngược cái table PYC đó ra dễ ẹc mà
  • RE: Kỹ thuật không cho lưu dữ liệu (Undo) ở Subform dạng Datasheet

    huuduy.duy > 16-04-20, 11:39 PM

    (16-04-20, 11:30 PM)Xuân Thanh Đã viết:
    (16-04-20, 11:27 PM)huuduy.duy Đã viết: Cái này được rồi anh.
    Chỉ còn 1 cái là gọi lại cái đã nhập để bổ sung thêm nhân viên từ bên phải vào bên trái ạ

    Thì lôi ngược cái table PYC đó ra dễ ẹc mà


    Dạ, đối với anh thì dễ, nhưng đối với em, em lôi nó ra được rồi, nhưng bổ sung thêm thì bị lỗi. Nhờ anh giúp  ạ
  • RE: Kỹ thuật không cho lưu dữ liệu (Undo) ở Subform dạng Datasheet

    ongke0711 > 17-04-20, 12:31 AM

    (16-04-20, 04:10 PM)huuduy.duy Đã viết: Do yêu cầu công việc phải chọn nhiều nhân viên từ Danh sách nhân viên chung, nên em thay Subform thành Listbox  để chọn nhân viên qua lại giữ 2 Listbox.

    Phần Form Phiếu Yêu cầu đào tạo: sẽ cập nhật thông tin như: 
    1/ Người yêu cầu, nội dung yêu cầu, Thời gian đào tạo, Nơi đào tạo, .. cập nhật vào bảng tblPhieuYeuCau
    2/ Mỗi phiếu Yêu cầu như vậy sẽ chọn ra danh sách nhân viên từ 1 danh sách nhân viên chung của Cty cần đào tạo theo nội dung đó và ghi bảng tblNhanVienDaDaoTao.

    Em lầm đến đoạn gọi Phiếu Yêu cầu lên để bổ sung thêm nhân viên cần đào tạo thì bị lỗi. Nhờ anh xem giúp
    Trân trọng cảm ơn
    Link
    ** Ngoài cách sử dụng Listbox, thì mình có thể sủ dụng Subform có checkbox để check những nhân viên cần chọn được không anh

    Cái Form đặc thù của em áp dụng cách làm như file demo của anh cũng không khác biệt gì nhiều ở qui trình xử lý, chỉ là khác nhau trong phần nạp dữ liệu thôi.

    Khi bấm nút [Sửa], sẽ nạp thông tin của PYC đó vào frmNhapPYC:
    - Nạp tblNhanVien vào tblNhanVienTemp.
    - Select query từ tblNhanVienDaDaoTao để lấy ra số nhân viên đã đăng ký theo số PYC đang gọi (fldFlag = True).
    - Dùng vòng lặp Recordset để cập nhật fldFlag=True của các nhân viên trong tblNhanVienTemp.
    - Xong.

    Ngoại trừ cách dùng vòng lặp Recordset, có thể dùng hàm gộp các MSNV thành chuỗi rồi dùng câu lệnh SQL "UPDATE ... SET...", có thể tốc độ xử lý sẽ nhanh hơn. Em tự test thử đi nhé.
    VD: UPDATE tblNhanVienTemp SET fldFlag = True WHERE MSNV IN ('S00234','S00695','S01234')

    Anh thấy em tận dụng thuộc tính Tag của control để lưu câu lệnh SQL cũng sáng tạo đó. Lưu ý là chỉ có thể lưu tối đa 2.048 ký tự (byte) thôi nhé. 

    Lưu ý: anh có ghi chú trong demo ở trên là phải chú ý đặt tên (name) của textbox trên Form phải trùng với tên Field trong Table cần lấy dữ liệu thì các hàm GetRecord(), UpdateRecord() mới chạy đúng. 

    Link file đã sửa: http://www.mediafire.com/file/khx6yy982u...accdb/file


    Còn về việc dùng SubForm có checkbox chọn nhân viên thì cũng gần tương tự cách xử lý trên. Chú ý là có thêm comboBox chọn Phòng ban để giới hạn việc phải kéo lên xuống danh sách nhân viên quá dài. (Giống như cái ListBox bên phải Form em đang làm).