-
RE: Thông báo dữ liệu đã tồn tại
ongke0711 > 21-07-17, 09:23 PM
Bạn khai báo lại biến:
Dim NgayKhamTruoc As Variant -
RE: Thông báo dữ liệu đã tồn tại
thanhtruong > 21-07-17, 09:37 PM
-
RE: Thông báo dữ liệu đã tồn tại
ongke0711 > 21-07-17, 10:16 PM
Vấn đề thứ nhất nằm ở nút [Lưu] của bạn.
-----------------------------------------------------------
Private Sub Command7_Click()
'If IsNull(Me.gio.Value) And IsNull(Me.ngay.Value) Then
If Len(Trim(Me.gio.Value) & “”) = 0 And Len(Trim(Me.ngay.Value) & “”) = 0 Then
Me.gio = Time
Me.ngay = Date => Lệnh lưu record đâu?
Else
DoCmd.Save
Me.Refresh
End If
Me.phantramgiam = Me.txtphantram
End Sub
-----------------------------------------------------------
-> Dịch theo code của bạn:
Nếu textbox [Gio] và [Ngày] rỗng thì gán textbox giờ = Time và Ngày = Date. Xong.
Nếu 2 textbox trên không rỗng thì Lưu và Refresh.
-> Vậy khi bạn Thêm mới record và bấm nút [Lưu], nó mới chỉ làm cái công đoạn là gán ngày giờ cho 2 textbox đó là xong, có lưu vào table đâu mà Dlookup.
Vấn đề thứ 2 là khai báo biến: bạn khai báo biến masokham là String mà khi Dlookup không có trị nó sẽ trả về Null vậy nó sẽ báo lỗi "Invalid use of Null". Chỉ có biến Variant mới chấp nhận Null cho nó.
Có 2 cách giải quyết: một là khai báo lại kiểu Variant như post trước tôi vừa đề cập. Hai là dùng hàm Nz() để khử giá trị Null.
1. Khai báo biến Variant: nếu làm cách này vô tình code nút [Lưu] cũ của bạn vẫn chạy tốt vì record mới không lưu thì Dlookup không ra -> Null -> "Khám lần đầu". Thực tế giai đoạn này record chưa lưu xuống Table, nếu bạn có dùng các code khác ví dụ như đếm có báo nhiêu record thì nó sẽ đếm thiếu 1 dòng này. Vì bạn dùng Bound Form nên khi đóng form record cũng tự lưu nên bạn cứ nghĩ là nút Lưu hoạt động đúng (nếu dùng Unbound form thì sẽ khóc tiếng Miên). Do vậy bạn phải sửa nút Lưu lại cho đúng nghĩa Lưu.
2. Dùng Nz():
masokham = Nz(DLookup("id", "thongtin", "[hoten] = '" & Me.txthoten & "'"), ""). --> Nếu Dlookup trả về giá trị NULL thì sẽ chuyển thành chuỗi rỗng "". Và trị này tương thích với biến String masokham. -
RE: Thông báo dữ liệu đã tồn tại
thanhtruong > 22-07-17, 12:01 AM
Đã chỉnh lại chạy rất ok,
Link demo 2
Chạy một lát thì phát hiện lỗi, lỗi ở chổ số ID khám gần nhất, nếu ngày 15/7/2017 nhập tên A với mã ID là 53
đến ngày 21/7/2017 nhập lại tên A với mã ID là 57, thì báo "đã khám cách đây 6 ngày, mã ID là 53" thì đúng
Nhưng cũng ngày đó nhập thêm tên A với số ID 58 thì báo "đã khám cách đây 0 ngày, mã ID là 53" ??????
đúng ra số ID ở đây là 57 mới đúng chứ? -
RE: Thông báo dữ liệu đã tồn tại
ongke0711 > 22-07-17, 12:12 AM
Một góp ý khác cho bạn về việc tìm kiếm bệnh nhân có dữ liệu hay chưa.
Theo cách tôi làm thì sẽ thiết kế thêm một nút tìm kiếm trên form bên cạnh ô nhập [Họ Tên]. Sau khi nhập Tên -> bấm nút tìm kiếm -> sẽ hiện form Tìm kiếm liệt kê danh sách những người có trùng Tên vừa nhập. Trên form Tìm Kiếm này sẽ có nhưng textbox để nhập các điều kiện tìm kiếm như: Ngày sinh, số CMND, số BHYT v.v.. -> Nếu trùng Tên bạn sẽ nhập tiếp ngày sinh (hoặc trường khác) để lọc tiếp -> Nếu không có thì sẽ là “Nhập mới”, nếu có xuất hiện trong danh sách thì bạn chỉ cần click chọn (hoặc double-click) vào người này để tự động điền mã id bệnh nhân vào phiếu khám cho nhanh. -
RE: Thông báo dữ liệu đã tồn tại
ongke0711 > 22-07-17, 12:17 AM
(22-07-17, 12:01 AM)thanhtruong Đã viết: Đã chỉnh lại chạy rất ok,
Link demo 2
Chạy một lát thì phát hiện lỗi, lỗi ở chổ số ID khám gần nhất, nếu ngày 15/7/2017 nhập tên A với mã ID là 53
đến ngày 21/7/2017 nhập lại tên A với mã ID là 57, thì báo "đã khám cách đây 6 ngày, mã ID là 53" thì đúng
Nhưng cũng ngày đó nhập thêm tên A với số ID 58 thì báo "đã khám cách đây 0 ngày, mã ID là 53" ??????
đúng ra số ID ở đây là 57 mới đúng chứ?
Cái này là do bạn phân tích CSDL không kỹ dẫn đến việc thiết kế table không hợp lý nên mới phát sinh lỗi này.
Demo 2 cái table liên quan đến lưu thông tin bệnh nhân và phiếu khám để bạn tham khảo.
- Table tblThongTinBenhNhan: dùng để lưu thông tin bệnh nhân lần đầu tới đăng ký khám chữa bệnh.
- Table tblPhieuKham: lưu thông tin từng lần khám bệnh của từng bệnh nhân
Khi bệnh nhân tới khám sẽ đăng ký thông tin vào bảng ThongTinBenhNhan nếu khám lần đầu. Nếu là bệnh nhân cũ thì chỉ cần dò tìm Mã bệnh nhân [MaBN] này rồi nhập vào phiếu đăng ký khám rồi lấy số thứ tự thôi.
Đối với CSDL của bạn hiện tại, theo tôi nhìn nhận thì table thongtin của bạn làm 2 chức năng, vừa lưu thông tin bệnh nhân vừa lưu thông tin từng lần khám nên mới có việc lập lại tên bênh nhân.
Bạn nên tách ra thành 2 table như trên và tạo nút tìm kiếm. Khi form Tìm kiếm này lọc ra được tên bênh nhân đã có lưu, nó cũng sẽ hiển thị thông tin lần khám gần nhất trên form cho bạn xem luôn chứ không cần hiện Message box như cách đang làm.
Còn đối với cái lỗi Dlookup sai số id là do bạn không đưa vào đủ điều kiện cho nó.
--------------------------------------------------
NgayKhamTruoc = DMax("Ngay", "Thongtin", "[hoten] = '" & Me.txthoten & "'")
masokham = DLookup("id", "thongtin", "[hoten] = '" & Me.txthoten & "' AND [Ngay] =#" & NgayKhamTruoc & "#")
---------------------------------------------------
* Một vấn đề khác nữa là bạn ngâm cứu lại sự khác nhau của câu lệnh:
DoCmd.Save
vs
DoCmd.RunCommand acCmdSaveRecord
vs
DoCmd.DoMenuItem
Bạn đang dùng Docmd.Save nó không lưu record đâu. Bạn phải vô table kiểm tra lại xem code có ok không. -
RE: Thông báo dữ liệu đã tồn tại
thanhtruong > 27-07-17, 06:50 PM
(22-07-17, 12:17 AM)ongke0711 Đã viết: Còn đối với cái lỗi Dlookup sai số id là do bạn không đưa vào đủ điều kiện cho nó.
--------------------------------------------------
NgayKhamTruoc = DMax("Ngay", "Thongtin", "[hoten] = '" & Me.txthoten & "'")
masokham = DLookup("id", "thongtin", "[hoten] = '" & Me.txthoten & "' AND [Ngay] =#" & NgayKhamTruoc & "#")
---------------------------------------------------
Khi đưa công thức này vào thì ok, nhưng khi thêm bệnh mới toanh, chưa khám lần nào thì báo lỗi ngay lập tức.
vì sao? vì ngày = ngày khám trước, mà ngày khám trước chưa có thì báo lỗi.
vậy khắc phục sao đây? xin Anh cho ý kiến. Cảm ơn ạh -
RE: Thông báo dữ liệu đã tồn tại
ongke0711 > 28-07-17, 06:21 PM
(27-07-17, 06:50 PM)thanhtruong Đã viết:
(22-07-17, 12:17 AM)ongke0711 Đã viết: Còn đối với cái lỗi Dlookup sai số id là do bạn không đưa vào đủ điều kiện cho nó.
--------------------------------------------------
NgayKhamTruoc = DMax("Ngay", "Thongtin", "[hoten] = '" & Me.txthoten & "'")
masokham = DLookup("id", "thongtin", "[hoten] = '" & Me.txthoten & "' AND [Ngay] =#" & NgayKhamTruoc & "#")
---------------------------------------------------
Khi đưa công thức này vào thì ok, nhưng khi thêm bệnh mới toanh, chưa khám lần nào thì báo lỗi ngay lập tức.
vì sao? vì ngày = ngày khám trước, mà ngày khám trước chưa có thì báo lỗi.
vậy khắc phục sao đây? xin Anh cho ý kiến. Cảm ơn ạh
Tôi gợi ý cái code là như vậy, khi áp dụng bạn phải điều chỉnh theo cái luồng xử lý dữ liệu của bạn cho nó hợp lý, đó mới là bẫy lỗi cho Form.
Phân tích lại cái luồng xử lý nhập liệu của bạn.
- Khi bạn nhập bất kỳ [hoten] nào thì chương trình sẽ kiểm tra [hoten] này là mới hay cũ. Nếu cũ thì thông báo cái [id] và [ngaykham] gần nhất của [hoten] này, nếu mới thì không cần làm gì cả và thông báo “mới’.
- Vậy khi kiểm tra bạn chỉ cần Dlookup xem cái ID bệnh nhân này (bạn đang dùng trường [hoten]) đã có trong table hay chưa?
DLookup (“hoten”, “ThongTin”, [hoten] = ‘“ & Me.txthoten & “‘“)
Nhưng nếu dùng code trên sẽ dư thêm một dòng code DLookup nên tôi dùng Dmax() cho biến NgayKhamTruoc để có thể sử dụng sau này luôn.
NgayKhamTruoc = DMax("Ngay", "Thongtin", "[hoten] = '" & Me.txthoten & "'")
- Sau khi có biến “NgayKhamTruoc” sẽ xét nó có Null hay có dữ liệu. Nếu là Null thì nhảy ra, hiện thông báo “Bệnh nhân mới”. Nếu không Null, lúc đó mới chạy tới tìm cái biến “masokham” và đưa vào MsgBox. Còn làm theo kiểu bạn là chạy code xử lý 2 biến trước (NgayKhamTruoc và masokham) rồi mới dùng If…Then để kiểm tra Null thì chắc chắn sẽ báo lỗi ngay dòng code masokham đối với bệnh nhân mới rồi.
Mã PHP:NgayKhamTruoc = DMax("Ngay", "Thongtin", "[hoten] = '" & Me.txthoten & "'")
If Not IsNull(NgayKhamTruoc) Then
SoNgay = DateDiff("d", NgayKhamTruoc, Date)
masokham = Nz(DLookup("id", "thongtin", "[hoten] = '" & Me.txthoten & "' AND [Ngay] =#" & Format(NgayKhamTruoc, "mm/dd/yyyy") & "#"), "")
'MsgBox "Da kham cach day " & SoNgay & " ngay!", vbInformation, "Thông báo"'
MsgBoxUni TCVN3toUNICODE(" §· kh¸m c¸ch ®©y ") & SoNgay & " ngày !" & TCVN3toUNICODE(" S« ID BÖnh Nh©n tríc ®ã lµ: ") & masokham, vbInformation, "Thông báo"
Else
MsgBoxUni TCVN3toUNICODE("Kh¸m lÇn ®Çu")
End If
- Một cái lỗi thứ 2 sẽ phát sinh khi bạn bấm nút [Lưu kết hợp kiểm tra] nó sẽ hiện cái msgbox thông báo cái [id] bạn vừa mới tạo. Vì sao? Vì cái nút [Lưu kết hợp kiểm tra] bạn viết code Save dữ liệu trước rồi mới chạy tới code kiểm tra tồn tại hay không. Nó đã lưu xuống table rồi thì tất nhiên báo tồn tại với ID mới nhất rồi.
- Cái lỗi thứ 3 là khi bạn bấm nút [Lưu kết hợp kiểm tra], nó hiện msgbox hỏi "có lưu hay không?". Nếu bạn chọn "No" thì nó vẫn chạy đoạn code kiểm tra vì bạn không có lệnh nào để chương trình dừng không chạy những dòng code kế tiếp.
Xem lại đoạn code lỗi của bạn.
Mã PHP:If Me.Dirty Then
If MsgBox("ban co muon luu hay khong?", _
vbYesNo + vbQuestion, "Save Changes") = vbNo Then
Me.Undo
End If
End If
If Len(Trim(Me.gio.Value) & “”) = 0 And Len(Trim(Me.ngay.Value) & “”) = 0 Then
Me.gio = Time
Me.ngay = Date
DoCmd.Save
Else
DoCmd.Save
Me.Refresh
End If
Me.phantramgiam = Me.txtphantram
'Chay doan code kiem tra benh nhan moi/cu?'
--------------------------------------------------------------------------------------------------
Sửa lại:
- Vì có 2 nút lệnh cần tới việc "kiểm tra id bệnh nhân" nên tôi đưa nó vô 1 cái Sub rồi bạn chỉ cần gọi nó cho gọn, khỏi phải viết lặp lại đoạn code này nhiều lần. Lưu ý: tôi chỉ chạy cái biến NgayKhamTruoc xong tới code If...Then, chứ không chạy 2 cái biến trước:
NgayKhamTruoc = ...
masokham = ....
Mã PHP:Sub KiemTraBenhNhanMoi()
Dim NgayKhamTruoc As Variant, SoNgay As Integer
Dim masokham As String
NgayKhamTruoc = DMax("Ngay", "Thongtin", "[hoten] = '" & Me.txthoten & "'")
If Not IsNull(NgayKhamTruoc) Then
SoNgay = DateDiff("d", NgayKhamTruoc, Date)
masokham = Nz(DLookup("id", "thongtin", "[hoten] = '" & Me.txthoten & "' AND [Ngay] =#" & Format(NgayKhamTruoc, "mm/dd/yyyy") & "#"), "")
'MsgBox "Da kham cach day " & SoNgay & " ngay!", vbInformation, "Thông báo"'
MsgBoxUni TCVN3toUNICODE(" §· kh¸m c¸ch ®©y ") & SoNgay & " ngày !" & TCVN3toUNICODE(" S« ID BÖnh Nh©n tríc ®ã lµ: ") & masokham, vbInformation, "Thông báo"
Else
MsgBoxUni TCVN3toUNICODE("Kh¸m lÇn ®Çu")
End If
End Sub
- Gọi Sub KiemTraBenhNhanMoi trong nút [Lưu kết hợp kiểm tra]. Khi chọn "No" phải "Exit Sub".
Mã PHP:Private Sub cmdLuuKetHopKiemTra_Click()
If Me.Dirty Then
If MsgBox("ban co muon luu hay khong?", _
vbYesNo + vbQuestion, "Save Changes") = vbNo Then
Me.Undo
Exit Sub
End If
End If
KiemTraBenhNhanMoi
If Len(Trim(Me.gio.Value) & “”) = 0 And Len(Trim(Me.ngay.Value) & “”) = 0 Then
Me.gio = Time
Me.ngay = Date
DoCmd.RunCommand acCmdSaveRecord
Else
DoCmd.Save
DoCmd.RunCommand acCmdSaveRecord
Me.Refresh
End If
Me.phantramgiam = Me.txtphantram
End Sub
Mã PHP:Private Sub cmdKiemTra_Click()
KiemTraBenhNhanMoi
End Sub
----------------------------------------------------------------------
Nói thêm:
Tổ chức table thông tin của bạn như vậy là đã sai cơ bản rồi mà bạn vẫn áp dụng, không chịu sửa à?. Cứ bênh nhân cũ tới khám là phải nhập toàn bộ dữ liệu lại (địa chỉ, đien thoại .....) bạn không thấy bất hợp lý cho người sử dụng à? Chưa kể là CSDL của bạn phình ra vì các dữ liệu lặp lại vô ích này, sau này kéo theo một lô một lốc các lỗi, các code không cần thiết để xử lý các dữ liệu trùng lặp.
Đó là ý kiến cá nhân tôi, nếu bạn vẫn muốn dùng thì bạn cứ dùng thôi. -
RE: Thông báo dữ liệu đã tồn tại
thanhtruong > 29-07-17, 08:29 AM
Em chưa đọc bài trả lời, vì ngại sẽ bị la nhiều lắm.
Cách mà anh chia sẽ thật tuyệt
(22-07-17, 12:12 AM)ongke0711 Đã viết: Một góp ý khác cho bạn về việc tìm kiếm bệnh nhân có dữ liệu hay chưa.
Theo cách tôi làm thì sẽ thiết kế thêm một nút tìm kiếm trên form bên cạnh ô nhập [Họ Tên]. Sau khi nhập Tên -> bấm nút tìm kiếm -> sẽ hiện form Tìm kiếm liệt kê danh sách những người có trùng Tên vừa nhập. Trên form Tìm Kiếm này sẽ có nhưng textbox để nhập các điều kiện tìm kiếm như: Ngày sinh, số CMND, số BHYT v.v.. -> Nếu trùng Tên bạn sẽ nhập tiếp ngày sinh (hoặc trường khác) để lọc tiếp -> Nếu không có thì sẽ là “Nhập mới”, nếu có xuất hiện trong danh sách thì bạn chỉ cần click chọn (hoặc double-click) vào người này để tự động điền mã id bệnh nhân vào phiếu khám cho nhanh.
Nhưng em chỉ làm đến được bước tìm được bệnh liệt kê ở danh sách bên dưới, còn nạp lại dữ liệu đó cho một lượt khám mới thì không làm được.
Nến mới mò tiếp phương pháp cũ, trước mắt em sẽ đọc tiếp bài trên, rồi nghiên cứu cách này.
Xin cảm ơn Anh nhiều. -
RE: Thông báo dữ liệu đã tồn tại
ongke0711 > 29-07-17, 09:34 AM
(29-07-17, 08:29 AM)thanhtruong Đã viết: Nhưng em chỉ làm đến được bước tìm được bệnh liệt kê ở danh sách bên dưới, còn nạp lại dữ liệu đó cho một lượt khám mới thì không làm được.
Nến mới mò tiếp phương pháp cũ, trước mắt em sẽ đọc tiếp bài trên, rồi nghiên cứu cách này.
Xin cảm ơn Anh nhiều.
- Bước quan trọng không kém là bạn đã tìm ra và thống nhất cái cách Form nhập liệu nó hoạt động xử lý như thế nào (cái cách hợp lý nhất) rồi thì cứ theo đó tìm kiếm code cho nó. Đã có rất nhiều phần mềm QL phòng khám, bạn cứ download về chạy thử xem cái cách họ xử lý form có thuận tiện không, hợp lý không rồi chắt lọc ra cái cách xử lý riêng cho trường hợp của bạn. Lập trình không phải tự mình viết ra code hết mới là giỏi là còn phải biết cách tìm ra nguồn code có sẵn và áp dụng nó cho mình. Có nhưng nguồn code thông dụng mà các lập trình viên khác đã trải nghiệm và viết ra cái cách tối ưu rồi thì cứ lấy mà dùng thay vì làm cái công việc "Reinvent the wheel".
- Những vấn đề tôi đề cập với bạn ở trên làm sao cho thuận tiện đối với người dùng đó chính là UX (User Experience) - Trải nghiệm người dùng trong thiết kế Form. Nó khác với UI (User Interface) - Giao diện người dùng nhé bạn. Về UX, tức bạn thiết kế form sao cho người dùng cảm thấy thuận tiện nhất khi sử dụng, bỏ các thao tác dư thừa, mất thời gian, qua quá nhiều bước để có được thông tin hoặc hoàn tất công việc mà người dùng mong muốn.
Ví dụ đơn giản:
1. Khi họ gõ tên bênh nhân, chỉ cần bấm phím nóng F1 thì sẽ hiện cái form tìm kiếm thay vì click chọn vào cái nút tìm kiếm -> mất thời gian chuyển tay qua chuột.
2. Khi hiện form TK, nếu nó chỉ hiện lên một đống danh sách bệnh nhân mà chưa lọc trước ra cái tên bạn vừa gõ ở form trước thì nó lại không hay lắm -> hiện form lên và lọc danh sách trước luôn để họ tìm cho nhanh.
==> đó chính là có quan tâm đến trải nghiệm người dùng và thiết kế phù hợp cho như cầu này.
Nói chung đùng nên làm qua loa sau này khi bạn ứng dụng hoàn chỉnh rồi, quay lại sửa là mệt lắm. Hơn nữa nhiều khi làm biếng không muốn sửa luôn vì thấy một rừng code và form.
Còn việc gán dữ liệu thì bạn làm theo cách đơn giản là được rồi. Khi tìm kiếm xong, bạn chỉ cần gán [mã bệnh nhân] không thôi vào form phiếu khám là được rồi.
Vd: Forms!frmPhieuKham.txtMaBenhNhan = Forms!frmTimKiem.txtMaBenhNhan