wtsrvd11
Thành viên mới
- Tham gia
- 17/7/19
- Bài viết
- 5
- Được thích
- 2
Sao mình xem như mô tả thì nó đâu có như vầy đâu bạn: "Nếu 1 cell trong cột đó thay đổi thì thì cell cùng hàng ở cột khác cộng giá trị ở cột vừa thay đổi". Mình thấy đâu có cùng hàng đâu.Nếu 1 cell trong cột đó thay đổi thì thì cell cùng hàng ở cột khác cộng giá trị ở cột vừa thay đổi như mô tả.
Không ạ. nếu ô ở cột mốc thay đổi thì giá trị trước khi thay đổi được cập nhật vào dòng cuối cùng của cột "Mốc cũ".Sao mình xem như mô tả thì nó đâu có như vầy đâu bạn: "Nếu 1 cell trong cột đó thay đổi thì thì cell cùng hàng ở cột khác cộng giá trị ở cột vừa thay đổi". Mình thấy đâu có cùng hàng đâu.
Có phải bạn muốn ô giá trị ngày tháng bên cột "Mốc" thay đổi thì giá trị thay đổi đó được cập nhật vào dòng cuối cùng của cột "Mốc cũ" hay không?
Bạn up file đó lên đi để mọi người xem giúp cho nhé !
Thân.
1. Bài của bạn mình thấy nó hơi "có vấn đề" ở dữ liệu cột C á (Mốc). Vì khi nhập liệu mới nó ghi đè lên luôn dữ liệu cũ, nghĩa là mất luôn "tính lịch sử", hi. Bạn có nghĩ đến trường hợp bạn lỡ tay nhập vào ô đó 1 ngày tháng sai (nhập 1 ngày trong quá khứ hoặc nhập 1 ngày nào đó sai với hạn định kỳ,...), bạn Enter xong bạn phải nhập lại không? Lúc đó theo yêu cầu của bạn thì bên cột B- cột Mốc cũ- sẽ xử lý như thế nào với dữ liệu bạn đã nhập sai??Không ạ. nếu ô ở cột mốc thay đổi thì giá trị trước khi thay đổi được cập nhật vào dòng cuối cùng của cột "Mốc cũ".
Cột mốc cũ có thể chỉnh sửa được mà. Tạm thời mình chỉ có giải pháp ghi text vào ô mốc cũ thôi. Bảng tính có nhiều con quá chia ra nữa thì có rất nhiều hàng. nếu bạn có giải pháp hay có thể tư vấn giúp ạ.1. Bài của bạn mình thấy nó hơi "có vấn đề" ở dữ liệu cột C á (Mốc). Vì khi nhập liệu mới nó ghi đè lên luôn dữ liệu cũ, nghĩa là mất luôn "tính lịch sử", hi. Bạn có nghĩ đến trường hợp bạn lỡ tay nhập vào ô đó 1 ngày tháng sai (nhập 1 ngày trong quá khứ hoặc nhập 1 ngày nào đó sai với hạn định kỳ,...), bạn Enter xong bạn phải nhập lại không? Lúc đó theo yêu cầu của bạn thì bên cột B- cột Mốc cũ- sẽ xử lý như thế nào với dữ liệu bạn đã nhập sai??
2. Ở cột B dữ liệu bạn nhập hơn chục ngày tháng nhưng nằm trong 1 ô thì nó cũng có vấn đề á. Vì 1 ô này nó sẽ ở dạng text, bạn sẽ rất khó tính toán với từng mốc thời gian trong đó (ví dụ: bạn sẽ không tính được khoảng thời gian giữa 2 mốc với nhau, nhỉ?!). Và, bây giờ xử lý theo yêu cầu của bạn thì phải "đối xử" với cái cột B đó như là text.
View attachment 240869
Bạn giải đáp ý 1 của mình đi rồi tính tiếp !
Cột mốc cũ có thể chỉnh sửa được mà => này là bạn chỉnh sửa bằng tay. Vậy thì sao có thể can thiệp bằng công thức để xử lý yêu cầu "nếu ô ở cột mốc thay đổi thì giá trị trước khi thay đổi được cập nhật vào dòng cuối cùng của cột Mốc cũ" được?! 1 trong 2 thôi, nhập tay sẽ không xài công thức, xài công thức thì không nhập tay.Cột mốc cũ có thể chỉnh sửa được mà. Tạm thời mình chỉ có giải pháp ghi text vào ô mốc cũ thôi. Bảng tính có nhiều con quá chia ra nữa thì có rất nhiều hàng. nếu bạn có giải pháp hay có thể tư vấn giúp ạ.
Đúng là chia ra thì dễ tính toán hơn. Mình sẽ tham khảo ý kiến của bạn.Cột mốc cũ có thể chỉnh sửa được mà => này là bạn chỉnh sửa bằng tay. Vậy thì sao có thể can thiệp bằng công thức để xử lý yêu cầu "nếu ô ở cột mốc thay đổi thì giá trị trước khi thay đổi được cập nhật vào dòng cuối cùng của cột Mốc cũ" được?! 1 trong 2 thôi, nhập tay sẽ không xài công thức, xài công thức thì không nhập tay.
Bài của bạn mình đang suy nghĩ để giải quyết nhưng chưa ra, nó trên tầm của mình, híc, sorry bạn. Bạn chờ các anh chị khác vào giúp nhé !
ps: dữ liệu nhiều hàng thì không thành vấn đề nếu làm như vậy sẽ chuẩn hóa được dữ liệu. Bạn sẽ xử lý chúng dễ dàng hơn. Bạn hiểu ý mình chứ. Bạn xử lý, tính toán ngày tháng thì dữ liệu bạn xử lý nó ở dạng Date sẽ dễ dàng hơn nhiều so với dạng Text đúng không?!
Option Explicit
#If VBA7 Then
Private Declare PtrSafe Function SetTimer Lib "USER32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr, ByVal uElapse As LongPtr, ByVal lpTimerFunc As LongPtr) As Long
Private Declare PtrSafe Function KillTimer Lib "USER32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr) As Long
#Else
Private Declare Function SetTimer Lib "user32" (ByVal HWnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Private Declare Function KillTimer Lib "user32" (ByVal HWnd As Long, ByVal nIDEvent As Long) As Long
#End If
'///////////////////////////////////////////////////////
#If Win64 Then
Private gTimerID As LongPtr
#Else
Private gTimerID As Long
#End If
'///////////////////////////////////////////////////////
Private CompareDateAgrs(), CompareDateIndex As Integer
Function S_CompareDate(Compare As Variant, _
ByVal WithCell As Excel.Range, _
Optional ByVal AutoFitRow As Boolean = False) As String
On Error Resume Next
KillTimer 0&, gTimerID: gTimerID = 0
'-----------------------------------------------
S_CompareDate = VBA.Replace(VBA.Mid(Application.Caller.Formula, 2), "S_CompareDate", "S_CompareDate", , , 1)
'-----------------------------------------------
Dim UB As Integer, i As Integer, f As Integer, K As Integer, Fit, Arg
Set WithCell = WithCell.Parent.Range(WithCell.Address)
'-----------------------------------------------
UB = UBound(CompareDateAgrs, 2): K = UB
If K > 0 Then GoSub CheckIn
If f = 0 Then K = K + 1:
ReDim Preserve CompareDateAgrs(1 To 2, 1 To K)
CompareDateAgrs(1, K) = Compare
Set CompareDateAgrs(2, K) = WithCell
CompareDateAgrs(3, K) = AutoFitRow
gTimerID = SetTimer(0&, 0&, 0, AddressOf S_CompareDate_callback)
Exit Function
CheckIn:
i = VBA.IIf(CompareDateIndex > 0 And CompareDateIndex <= K, CompareDateIndex, 1)
For f = i To K
If CompareDateAgrs(2, f).Worksheet Is WithCell.Worksheet Then
If CompareDateAgrs(2, f).Address = WithCell.Address Then Return
End If
Next
f = 0
Return
End Function
'///////////////////////////////////////////////////////
Private Sub S_CompareDate_callback()
On Error Resume Next
Static EarliestTime As Date, Procedure As String
Procedure = "'" & ThisWorkbook.Name & "'!S_CompareDate_callback"
Call KillTimer(0&, gTimerID): gTimerID = 0
Call Application.OnTime(EarliestTime, Procedure, , False)
'----------------------------------
Dim UB As Integer
UB = UBound(CompareDateAgrs, 2)
If UB > 0 Then
CompareDateIndex = CompareDateIndex + 1
Dim a As Variant, b As String, SP() As String, i As Integer
a = CompareDateAgrs(1, CompareDateIndex)
If Not IsDate(a) Or a = "" Then Exit Sub
a = Format(a, "dd/mm/yyyy")
Debug.Print CDate(a)
b = CompareDateAgrs(2, CompareDateIndex).Value
SP = Split(b, Chr(10))
For i = LBound(SP) To UBound(SP)
If IsDate(SP(i)) Then
If CDate(SP(i)) = CDate(a) Then : GoTo N
If CDate(SP(i)) > CDate(a) Then
SP(i) = CStr(a) & Chr(10) & SP(i): GoTo N
End If
End If
Next
SP(UBound(SP)) = SP(UBound(SP)) & Chr(10) & CStr(a)
N: b = Join(SP, Chr(10))
CompareDateAgrs(2, CompareDateIndex).Value = b
If CompareDateAgrs(3, CompareDateIndex) Then
CompareDateAgrs(2, CompareDateIndex).WrapText = True
CompareDateAgrs(2, CompareDateIndex).EntireRow.AutoFit
End If
If CompareDateIndex >= UB Then
Erase CompareDateAgrs: CompareDateIndex = 0
Else
EarliestTime = VBA.Now()
Call Application.OnTime(EarliestTime, Procedure)
End If
End If
End Sub
Cảm ơn bạn. code chạy ok. code phức tạp quá k biết gì để hỏi luônBạn copy code dưới đây để thử:
Viết công thức ở cột I hoặc một ô bất kì:
=S_CompareDate(C2,B2,True)
Và Fil xuống.
Giá trị True/False là Tự động giãn dòng
-------------------------------
JavaScript:Option Explicit #If VBA7 Then Private Declare PtrSafe Function SetTimer Lib "USER32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr, ByVal uElapse As LongPtr, ByVal lpTimerFunc As LongPtr) As Long Private Declare PtrSafe Function KillTimer Lib "USER32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr) As Long #Else Private Declare Function SetTimer Lib "user32" (ByVal HWnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long Private Declare Function KillTimer Lib "user32" (ByVal HWnd As Long, ByVal nIDEvent As Long) As Long #End If '/////////////////////////////////////////////////////// #If Win64 Then Private gTimerID As LongPtr #Else Private gTimerID As Long #End If '/////////////////////////////////////////////////////// Private CompareDateAgrs(), CompareDateIndex As Integer Function S_CompareDate(Compare As Variant, _ ByVal WithCell As Excel.Range, _ Optional ByVal AutoFitRow As Boolean = False) As String On Error Resume Next KillTimer 0&, gTimerID: gTimerID = 0 '----------------------------------------------- S_CompareDate = VBA.Replace(VBA.Mid(Application.Caller.Formula, 2), "S_CompareDate", "S_CompareDate", , , 1) '----------------------------------------------- Dim UB As Integer, i As Integer, f As Integer, K As Integer, Fit, Arg Set WithCell = WithCell.Parent.Range(WithCell.Address) '----------------------------------------------- UB = UBound(CompareDateAgrs, 2): K = UB If K > 0 Then GoSub CheckIn If f = 0 Then K = K + 1: ReDim Preserve CompareDateAgrs(1 To 2, 1 To K) CompareDateAgrs(1, K) = Compare Set CompareDateAgrs(2, K) = WithCell CompareDateAgrs(3, K) = AutoFitRow gTimerID = SetTimer(0&, 0&, 0, AddressOf S_CompareDate_callback) Exit Function CheckIn: i = VBA.IIf(CompareDateIndex > 0 And CompareDateIndex <= K, CompareDateIndex, 1) For f = i To K If CompareDateAgrs(2, f).Worksheet Is WithCell.Worksheet Then If CompareDateAgrs(2, f).Address = WithCell.Address Then Return End If Next f = 0 Return End Function '/////////////////////////////////////////////////////// Private Sub S_CompareDate_callback() On Error Resume Next Static EarliestTime As Date, Procedure As String Procedure = "'" & ThisWorkbook.Name & "'!S_CompareDate_callback" Call KillTimer(0&, gTimerID): gTimerID = 0 Call Application.OnTime(EarliestTime, Procedure, , False) '---------------------------------- Dim UB As Integer UB = UBound(CompareDateAgrs, 2) If UB > 0 Then CompareDateIndex = CompareDateIndex + 1 Dim a As Variant, b As String, SP() As String, i As Integer a = CompareDateAgrs(1, CompareDateIndex) If Not IsDate(a) Or a = "" Then Exit Sub a = Format(a, "dd/mm/yyyy") Debug.Print CDate(a) b = CompareDateAgrs(2, CompareDateIndex).Value SP = Split(b, Chr(10)) For i = LBound(SP) To UBound(SP) If IsDate(SP(i)) Then If CDate(SP(i)) = CDate(a) Then : GoTo N If CDate(SP(i)) > CDate(a) Then SP(i) = CStr(a) & Chr(10) & SP(i): GoTo N End If End If Next SP(UBound(SP)) = SP(UBound(SP)) & Chr(10) & CStr(a) N: b = Join(SP, Chr(10)) CompareDateAgrs(2, CompareDateIndex).Value = b If CompareDateAgrs(3, CompareDateIndex) Then CompareDateAgrs(2, CompareDateIndex).WrapText = True CompareDateAgrs(2, CompareDateIndex).EntireRow.AutoFit End If If CompareDateIndex >= UB Then Erase CompareDateAgrs: CompareDateIndex = 0 Else EarliestTime = VBA.Now() Call Application.OnTime(EarliestTime, Procedure) End If End If End Sub
Vì bạn không biết VBA nên không hiểu cơ chế của code trên.Cảm ơn bạn. code chạy ok. code phức tạp quá k biết gì để hỏi luôn
Nhìn code khủng quá, bạn làm nghề lập trình hảBạn copy code dưới đây để thử:
Viết công thức ở cột I hoặc một ô bất kì:
=S_CompareDate(C2,B2,True)
Và Fil xuống.
Giá trị True/False là Tự động giãn dòng
-------------------------------
JavaScript:Option Explicit #If VBA7 Then Private Declare PtrSafe Function SetTimer Lib "USER32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr, ByVal uElapse As LongPtr, ByVal lpTimerFunc As LongPtr) As Long Private Declare PtrSafe Function KillTimer Lib "USER32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr) As Long #Else Private Declare Function SetTimer Lib "user32" (ByVal HWnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long Private Declare Function KillTimer Lib "user32" (ByVal HWnd As Long, ByVal nIDEvent As Long) As Long #End If '/////////////////////////////////////////////////////// #If Win64 Then Private gTimerID As LongPtr #Else Private gTimerID As Long #End If '/////////////////////////////////////////////////////// Private CompareDateAgrs(), CompareDateIndex As Integer Function S_CompareDate(Compare As Variant, _ ByVal WithCell As Excel.Range, _ Optional ByVal AutoFitRow As Boolean = False) As String On Error Resume Next KillTimer 0&, gTimerID: gTimerID = 0 '----------------------------------------------- S_CompareDate = VBA.Replace(VBA.Mid(Application.Caller.Formula, 2), "S_CompareDate", "S_CompareDate", , , 1) '----------------------------------------------- Dim UB As Integer, i As Integer, f As Integer, K As Integer, Fit, Arg Set WithCell = WithCell.Parent.Range(WithCell.Address) '----------------------------------------------- UB = UBound(CompareDateAgrs, 2): K = UB If K > 0 Then GoSub CheckIn If f = 0 Then K = K + 1: ReDim Preserve CompareDateAgrs(1 To 2, 1 To K) CompareDateAgrs(1, K) = Compare Set CompareDateAgrs(2, K) = WithCell CompareDateAgrs(3, K) = AutoFitRow gTimerID = SetTimer(0&, 0&, 0, AddressOf S_CompareDate_callback) Exit Function CheckIn: i = VBA.IIf(CompareDateIndex > 0 And CompareDateIndex <= K, CompareDateIndex, 1) For f = i To K If CompareDateAgrs(2, f).Worksheet Is WithCell.Worksheet Then If CompareDateAgrs(2, f).Address = WithCell.Address Then Return End If Next f = 0 Return End Function '/////////////////////////////////////////////////////// Private Sub S_CompareDate_callback() On Error Resume Next Static EarliestTime As Date, Procedure As String Procedure = "'" & ThisWorkbook.Name & "'!S_CompareDate_callback" Call KillTimer(0&, gTimerID): gTimerID = 0 Call Application.OnTime(EarliestTime, Procedure, , False) '---------------------------------- Dim UB As Integer UB = UBound(CompareDateAgrs, 2) If UB > 0 Then CompareDateIndex = CompareDateIndex + 1 Dim a As Variant, b As String, SP() As String, i As Integer a = CompareDateAgrs(1, CompareDateIndex) If Not IsDate(a) Or a = "" Then Exit Sub a = Format(a, "dd/mm/yyyy") Debug.Print CDate(a) b = CompareDateAgrs(2, CompareDateIndex).Value SP = Split(b, Chr(10)) For i = LBound(SP) To UBound(SP) If IsDate(SP(i)) Then If CDate(SP(i)) = CDate(a) Then : GoTo N If CDate(SP(i)) > CDate(a) Then SP(i) = CStr(a) & Chr(10) & SP(i): GoTo N End If End If Next SP(UBound(SP)) = SP(UBound(SP)) & Chr(10) & CStr(a) N: b = Join(SP, Chr(10)) CompareDateAgrs(2, CompareDateIndex).Value = b If CompareDateAgrs(3, CompareDateIndex) Then CompareDateAgrs(2, CompareDateIndex).WrapText = True CompareDateAgrs(2, CompareDateIndex).EntireRow.AutoFit End If If CompareDateIndex >= UB Then Erase CompareDateAgrs: CompareDateIndex = 0 Else EarliestTime = VBA.Now() Call Application.OnTime(EarliestTime, Procedure) End If End If End Sub