Bởi vì thực tế có một số trạm bị hỏng cảnh báo, không có trong hệ thống thì trong tháng bọn em sẽ phải nhập liệu bằng thủ công. Vì vậy nên cuối tháng em inport số liệu vào sẽ chọn từ ô tiếp theo của cột B tiếp theo vị trí đã nhập, nếu không sẽ mất dữ liệu cũ.Tôi thắc mắc: Đằng nào thì dữ liệu cũng sẽ được Import vào cột B, vậy tại sao bạn còn dùng cái Application.InputBox("Chon noi de dat", Type:=8) để làm gì?
Thì vầy thôi:
Mã:Public Sub Exporting() Dim sArr(), dArr(), vFile Dim wkb As Workbook, wks As Worksheet, rng As Range Dim sFile As String, tmp As String Dim i As Long vFile = Application.GetOpenFilename("Excel Files, *.xls*") If TypeName(vFile) = "String" Then sFile = CStr(vFile) Application.ScreenUpdating = False Set wkb = Workbooks.Open(sFile) Set wks = wkb.Worksheets("Sheet1") sArr = wks.Range("J14", wks.Range("E60000").End(xlUp)).Value wkb.Close False ReDim dArr(1 To UBound(sArr, 1), [COLOR=#0000cd]1 To 7[/COLOR]) For i = 1 To UBound(sArr, 1) tmp = Mid(sArr(i, 1), InStr(sArr(i, 1), ":") + 1) dArr(i, 1) = Left(tmp, Len(tmp) - 5) dArr(i, 2) = TimeValue(Right(sArr(i, 5), 8)) dArr(i, 3) = DateSerial(Mid(sArr(i, 5), 7, 4), Mid(sArr(i, 5), 4, 2), Left(sArr(i, 5), 2)) If sArr(i, 3) <> Empty Then dArr(i, 4) = TimeValue(Right(sArr(i, 6), 8)) dArr(i, 5) = DateSerial(Mid(sArr(i, 6), 7, 4), Mid(sArr(i, 6), 4, 2), Left(sArr(i, 6), 2)) End If [COLOR=#ff0000]dArr(i, 6) = dArr(i, 5) + dArr(i, 4) - dArr(i, 3) - dArr(i, 2) dArr(i, 7) = Hour(dArr(i, 6)) * 60 + Minute(dArr(i, 6))[/COLOR] Next i Application.ScreenUpdating = True On Error Resume Next Set rng = Application.InputBox("Chon noi de dat", Type:=8) On Error GoTo 0 If Not rng Is Nothing Then With rng.Resize(i - 1, 7) .Value = dArr .EntireColumn.AutoFit Union(.Offset(, 1).Resize(, 1), .Offset(, 3).Resize(, 1), .Offset(, 3).Resize(, 5)).NumberFormat = "hh:mm" Union(.Offset(, 2).Resize(, 1), .Offset(, 4).Resize(, 1)).NumberFormat = "dd/mm/yyyy" .Offset(, 6).Resize(, 1).NumberFormat = "General" End With End If End If End Sub
Vấn sai anh ạ. Ví dụ như trong hình em gửi, nếu em sửa lại file data để số giờ lớn hơn 24h thì nó sẽ ra kết quả sai.
.
dArr(i, 7) = Int(dArr(i, 6) * 1440)
Public Sub Exporting()
Dim sArr(), dArr(), vFile
Dim wkb As Workbook, wks As Worksheet, rng As Range
Dim sFile As String, tmp As String
Dim i As Long
vFile = Application.GetOpenFilename("Excel Files, *.xls*")
If TypeName(vFile) = "String" Then
sFile = CStr(vFile)
Application.ScreenUpdating = False
Set wkb = Workbooks.Open(sFile)
Set wks = wkb.Worksheets("Sheet1")
sArr = wks.Range("J14", wks.Range("E60000").End(xlUp)).Value
wkb.Close False
ReDim dArr(1 To UBound(sArr, 1), 1 To 7)
For i = 1 To UBound(sArr, 1)
tmp = Mid(sArr(i, 1), InStr(sArr(i, 1), ":") + 1)
dArr(i, 1) = Left(tmp, Len(tmp) - 5)
dArr(i, 2) = TimeValue(Right(sArr(i, 5), 8))
dArr(i, 3) = DateSerial(Mid(sArr(i, 5), 7, 4), Mid(sArr(i, 5), 4, 2), Left(sArr(i, 5), 2))
If sArr(i, 3) <> Empty Then
dArr(i, 4) = TimeValue(Right(sArr(i, 6), 8))
dArr(i, 5) = DateSerial(Mid(sArr(i, 6), 7, 4), Mid(sArr(i, 6), 4, 2), Left(sArr(i, 6), 2))
End If
dArr(i, 6) = dArr(i, 5) + dArr(i, 4) - dArr(i, 3) - dArr(i, 2)
[COLOR=#ff0000]dArr(i, 7) = Int(dArr(i, 6) * 1440)[/COLOR]
Next i
Application.ScreenUpdating = True
On Error Resume Next
Set rng = Application.InputBox("Chon noi de dat", Type:=8)
On Error GoTo 0
If Not rng Is Nothing Then
With rng.Resize(i - 1, 7)
.Value = dArr
.EntireColumn.AutoFit
Union(.Offset(, 1).Resize(, 1), .Offset(, 3).Resize(, 1)).NumberFormat = "hh:mm"
Union(.Offset(, 2).Resize(, 1), .Offset(, 4).Resize(, 1)).NumberFormat = "dd/mm/yyyy"
[COLOR=#ff0000].Offset(, 5).Resize(, 1).NumberFormat = "[hh]:mm"[/COLOR]
.Offset(, 6).Resize(, 1).NumberFormat = "General"
End With
End If
End If
End Sub
Chuẩn anh ạ. Nhưng anh có thể tách riêng cho em code cộng giờ (cột G) và phút (cột H) đó được ko ạ. Nếu để lồng trong code này luôn thì những dòng dữ liệu em nhập thủ công sẽ không ra được kết quả.Yên tâm là không có sai đâu. Bởi cột G đang Format theo kiểu "hh:mm" nên thấy vậy thôi, nếu bạn format nó thành "[h]:mm" thì sẽ thấy ngay số giờ vượt quá 24
Riêng cột H, ta sửa thành vầy là chắc ăn nhất:
Toàn bộ code có thể sửa thành vầy:Mã:dArr(i, 7) = Int(dArr(i, 6) * 1440)
Mã:Public Sub Exporting() Dim sArr(), dArr(), vFile Dim wkb As Workbook, wks As Worksheet, rng As Range Dim sFile As String, tmp As String Dim i As Long vFile = Application.GetOpenFilename("Excel Files, *.xls*") If TypeName(vFile) = "String" Then sFile = CStr(vFile) Application.ScreenUpdating = False Set wkb = Workbooks.Open(sFile) Set wks = wkb.Worksheets("Sheet1") sArr = wks.Range("J14", wks.Range("E60000").End(xlUp)).Value wkb.Close False ReDim dArr(1 To UBound(sArr, 1), 1 To 7) For i = 1 To UBound(sArr, 1) tmp = Mid(sArr(i, 1), InStr(sArr(i, 1), ":") + 1) dArr(i, 1) = Left(tmp, Len(tmp) - 5) dArr(i, 2) = TimeValue(Right(sArr(i, 5), 8)) dArr(i, 3) = DateSerial(Mid(sArr(i, 5), 7, 4), Mid(sArr(i, 5), 4, 2), Left(sArr(i, 5), 2)) If sArr(i, 3) <> Empty Then dArr(i, 4) = TimeValue(Right(sArr(i, 6), 8)) dArr(i, 5) = DateSerial(Mid(sArr(i, 6), 7, 4), Mid(sArr(i, 6), 4, 2), Left(sArr(i, 6), 2)) End If dArr(i, 6) = dArr(i, 5) + dArr(i, 4) - dArr(i, 3) - dArr(i, 2) [COLOR=#ff0000]dArr(i, 7) = Int(dArr(i, 6) * 1440)[/COLOR] Next i Application.ScreenUpdating = True On Error Resume Next Set rng = Application.InputBox("Chon noi de dat", Type:=8) On Error GoTo 0 If Not rng Is Nothing Then With rng.Resize(i - 1, 7) .Value = dArr .EntireColumn.AutoFit Union(.Offset(, 1).Resize(, 1), .Offset(, 3).Resize(, 1)).NumberFormat = "hh:mm" Union(.Offset(, 2).Resize(, 1), .Offset(, 4).Resize(, 1)).NumberFormat = "dd/mm/yyyy" [COLOR=#ff0000].Offset(, 5).Resize(, 1).NumberFormat = "[hh]:mm"[/COLOR] .Offset(, 6).Resize(, 1).NumberFormat = "General" End With End If End If End Sub
Chuẩn anh ạ. Nhưng anh có thể tách riêng cho em code cộng giờ (cột G) và phút (cột H) đó được ko ạ. Nếu để lồng trong code này luôn thì những dòng dữ liệu em nhập thủ công sẽ không ra được kết quả.
Nhưng như lúc nãy anh hỏi em vì sao luôn đặt dữ liệu ở cột B mà lại cần cái chọn nơi bắt đầu dán dữ liệu làm gì. Bởi dữ liệu import em làm vào cuối tháng, file data đó được Export từ phần mềm cảnh báo sự cố trạm của bọn em. Nhưng các ngày trong tháng em còn có một số dữ liệu phải nhập bằng thủ công do một số trạm không có cảnh báo nên bọn em không lấy data tự động được.Tách là tách sao? Không hiểu!
Sau khi Import dữ liệu vào các cột B đến cột F, giờ ta sẽ dựa vào dữ liệu ở 4 cột C, D, E và F để lấy ra giờ và phút cho G và H.. và code này ta viết riêng, đúng không?
Bạn tự suy nghĩ đi, có sẵn rồi còn gì
Nhưng như lúc nãy anh hỏi em vì sao luôn đặt dữ liệu ở cột B mà lại cần cái chọn nơi bắt đầu dán dữ liệu làm gì. Bởi dữ liệu import em làm vào cuối tháng, file data đó được Export từ phần mềm cảnh báo sự cố trạm của bọn em. Nhưng các ngày trong tháng em còn có một số dữ liệu phải nhập bằng thủ công do một số trạm không có cảnh báo nên bọn em không lấy data tự động được.
Vậy nên với code này chỉ có những dòng được import thì mới tính được giờ và phút còn những dòng dữ liệu nhập thủ công sẽ không có kết quả.
Public Sub Exporting()
Dim sArr(), dArr(), vFile
Dim wkb As Workbook, wks As Worksheet, rng As Range
Dim sFile As String, tmp As String
Dim I As Long
vFile = Application.GetOpenFilename("Excel Files, *.xls*")
If TypeName(vFile) = "String" Then
sFile = CStr(vFile)
Application.ScreenUpdating = False
Set wkb = Workbooks.Open(sFile)
Set wks = wkb.Worksheets("Sheet1")
sArr = wks.Range("J14", wks.Range("E60000").End(xlUp)).Value
wkb.Close False
ReDim dArr(1 To UBound(sArr, 1), 1 To 6)
For I = 1 To UBound(sArr, 1)
tmp = Mid(sArr(I, 1), InStr(sArr(I, 1), ":") + 1)
dArr(I, 1) = I
dArr(I, 2) = Left(tmp, Len(tmp) - 5)
dArr(I, 3) = TimeValue(Right(sArr(I, 5), 8))
dArr(I, 4) = DateSerial(Mid(sArr(I, 5), 7, 4), Mid(sArr(I, 5), 4, 2), Left(sArr(I, 5), 2))
If sArr(I, 3) <> Empty Then
dArr(I, 5) = TimeValue(Right(sArr(I, 6), 8))
dArr(I, 6) = DateSerial(Mid(sArr(I, 6), 7, 4), Mid(sArr(I, 6), 4, 2), Left(sArr(I, 6), 2))
End If
Next I
Application.ScreenUpdating = True
On Error Resume Next
Set rng = Application.InputBox("Chon noi de dat", Type:=8)
On Error GoTo 0
If Not rng Is Nothing Then
With rng.Resize(I - 1, 6)
.Value = dArr
.EntireColumn.AutoFit
Union(.Offset(, 2).Resize(, 1), .Offset(, 4).Resize(, 1)).NumberFormat = "hh:mm"
Union(.Offset(, 3).Resize(, 1), .Offset(, 5).Resize(, 1)).NumberFormat = "dd/mm/yyyy"
End With
End If
End If
End Sub
Public Sub GPE_()
Dim sArr(), dArr(), I As Long, J As Long
sArr = Range([C8], [C65536].End(xlUp)).Resize(, 4).Value
ReDim dArr(1 To UBound(sArr, 1), 1 To 2)
For I = 1 To UBound(sArr, 1)
dArr(I, 1) = sArr(I, 4) + sArr(I, 3) - sArr(I, 2) - sArr(I, 1)
dArr(I, 2) = Int(dArr(I, 1) * 1440)
Next I
Range("G8:H8").Resize(I - 1) = dArr
End Sub
Khi nào muốn có hoặc tính lại kết quả của cột G:H thì chạy Sub này (Gán vào cái nút nào đó)
Format trước cột G là [hh]:mm
PHP:Public Sub GPE_() Dim sArr(), dArr(), I As Long, J As Long sArr = Range([C8], [C65536].End(xlUp)).Resize(, 4).Value ReDim dArr(1 To UBound(sArr, 1), 1 To 2) For I = 1 To UBound(sArr, 1) dArr(I, 1) = sArr(I, 4) + sArr(I, 3) - sArr(I, 2) - sArr(I, 1) dArr(I, 2) = Int(dArr(I, 1) * 1440) Next I Range("G8:H8").Resize(I - 1) = dArr End Sub
Nhưng chuyển sang code của anh em không biết cách.If Not rng Is Nothing Then
With rng.Resize(i - 1, 7)
.Value = dArr
.EntireColumn.AutoFit
Union(.Offset(, 1).Resize(, 1), .Offset(, 3).Resize(, 1)).NumberFormat = "hh:mm"
Union(.Offset(, 2).Resize(, 1), .Offset(, 4).Resize(, 1)).NumberFormat = "dd/mm/yyyy"
.Offset(, 5).Resize(, 1).NumberFormat = "[hh]:mm"
.Offset(, 6).Resize(, 1).NumberFormat = "General"
End With
End If
Em đã làm được nhưng nếu như cột G8:H8 và format sai định dạng thì nó không ra kết quả đúng. Anh Ndu đã giải quyết giúp em bằng code
Nhưng chuyển sang code của anh em không biết cách.
Và em mong muốn gán code này vào một sự kiện của sheet như sheet_change chẳng hạn để nó tự chạy khi có sự thay đổi của các cột trước có được không?
Muốn mỗi lần chạy code là mỗi lần Format lại thì thêm vào code chỗ này:Format trước cột G là [hh]:mm
Range("G8:H8").Resize(I - 1) = dArr
Range("G8").Resize(I - 1).NumberFormat = "[hh]:mm"
Em làm thế này cho tất cả các thángMuốn đưa vào sự kiện nào thì tuỳ bạn thôi. Thử đi rồi biết.
Mỗi lần thay đổi cột trước? Như bạn nói không phải chỉ là chạy code IMPORT mà còn nhập thủ công, mỗi lần nhập vào một ô nào đó là code chạy 1 lần? Nhập 100 ô code chạy 100 lần???????
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim sArr(), dArr(), K As Long, J As Long
On Error Resume Next
If Left(UCase(Sh.Name), 5) = "THANG" Then
sArr = Range([C8], [C65536].End(xlUp)).Resize(, 4).Value
ReDim dArr(1 To UBound(sArr, 1), 1 To 2)
For K = 1 To UBound(sArr, 1)
dArr(K, 1) = sArr(K, 4) + sArr(K, 3) - sArr(K, 2) - sArr(K, 1)
dArr(K, 2) = Int(dArr(K, 1) * 1440)
Next K
Range("G8:H8").Resize(K - 1) = dArr
Range("G8").Resize(K - 1).NumberFormat = "[hh]:mm"
Range("H8").Resize(K - 1).NumberFormat = "General"
End If
End Sub
Em làm thế này cho tất cả các tháng
E thấy có ra đúng kết quả nhưng không biết có vấn đề gì không? nhờ anh tư vấn thêm
Nhờ anh kiểm tra giúp em. Với file em gửi kèm theo đây, Em có gán nó vào sự kiện Workbook_SheetChange kèm với code thay thế cho hàm Vlookup em lượm được của a Ndu và sửa lại thì khi em paste số liệu hoặc Import vào nó không tự tính được mà em phải tác động vào một trong các cột B,C,D,E,F thì code đó mới chạy trong khi Vlookup vẫn tốt, nhưng nếu em để nó đứng độc lập như code bài trên em đã sửa thì vẫn ok. Anh chỉ dùm em xem lý do vì sao và khắc phục thế nào ạ?Đã đọc hiểu code, đã vận dụng và sửa được code của người khác vào file thực của mình thì cứ thế mà "tiến tới".
Áp dụng vào chỗ nào thì thử hết vào các sự kiện, cái nào khoái thì xài.
Ai biết bạn muốn cái gì mà tư vấn.
Một kinh nghiệm khi hỏi bài là:Anh Ndu, anh Ba Tê hay anh nào đó chỉ dùm em với ạ. Nghiền ngẫm cả chiều vẫn ko hiểu tại sao???
Cảm ơn anh đã chỉ dẫn. Em sẽ rút kinh nghiệm cho những lần sau. Còn lần này chiếu cố giúp em đi ạ. Em thực sự muốn làm được nhưng cứ một mình mò mẫm khó quá, mà ở cái chỗ của em muốn học cũng ko có chỗ học. Tuổi đời thì cũng gần 4 chục rồi giờ mới bắt đầu đi mò cái này thấy não nó cứ chậm đi mấy nhịp.Một kinh nghiệm khi hỏi bài là:
- Nên dự trù tất cả các tình huống và đưa ra một yêu cầu với 1 file mẫu, sao cho người khác giúp rồi thì không còn "ý quên, cho hỏi thêm, ví dụ tôi muốn ..., giả sử tôi muốn thêm..., bớt..." làm cho code đã viết phải "phá sản" làm lại từ đầu. Người viết code thành "công cốc".
- Đừng lấy code của người này đưa lên hỏi trên GPE nhờ thêm, bớt, hỏi sao "nó không chạy khi áp dụng vào file thực của tôi"... vì có thể không ai muốn chỉnh sửa code của người khác (đọc code là biết của ai trên GPE rồi).
- Đừng nêu đích danh người này, người kia giúp mình, người khác dù biết cũng chẳng thèm giúp, vì không liên quan tới mình.
- ....................
Cảm ơn anh đã chỉ dẫn. Em sẽ rút kinh nghiệm cho những lần sau. Còn lần này chiếu cố giúp em đi ạ. Em thực sự muốn làm được nhưng cứ một mình mò mẫm khó quá, mà ở cái chỗ của em muốn học cũng ko có chỗ học. Tuổi đời thì cũng gần 4 chục rồi giờ mới bắt đầu đi mò cái này thấy não nó cứ chậm đi mấy nhịp.![]()
Xem cái file của anh mới ngấm câu này. Em cảm ơn anh.Như tôi đã viết ở bài trước, đừng quá tự động "làm phiền CPU". khi nào muốn thì bấm nút 1 phát thôi, mắc gì gán vào tự động mỗi lần "đụng đâu cũng chạy code".