Hoàng Nhật Phương
Thành viên gắn bó



- Tham gia
- 5/11/15
- Bài viết
- 1,895
- Được thích
- 1,219
File đính kèm
Lần chỉnh sửa cuối:
Con chào Bác SA,Bước 1 là 'lọc' (AdvancedFilter), nếu bạn đồng ý ta tiếp phần 'tách'
Khoảng bao nhiêu dòng mà nhiều bạn OverTime ?
Sub LocToanBo()
' Keyboard Shortcut: Ctrl+Shift+L
Dim Rws As Long ' + '
Rws = Sheets("DuLieu").[B2].CurrentRegion.Rows.Count ' + '
Sheets("DuLieu").Range("A1:F" & Rws).AdvancedFilter Action:=xlFilterCopy, _
CriteriaRange:=Range("G1:I2"), CopyToRange:=Range("A4:E4"), Unique:=True
End Sub
Bác ơi, còn trường hợp tách MaID nữa Bác xem giúp con ạ. T_TCho hỏi thêm là lọc duy nhất (theo ca) rồi mới tách (theo cột MaiD) hay tách trước rồi lọc duy nhất?
Nếu lọc duy nhất trước thì chỉ sửa lại tí thôi:
Mã:Sub LocToanBo() ' Keyboard Shortcut: Ctrl+Shift+L Dim Rws As Long ' + ' Rws = Sheets("DuLieu").[B2].CurrentRegion.Rows.Count ' + ' Sheets("DuLieu").Range("A1:F" & Rws).AdvancedFilter Action:=xlFilterCopy, _ CriteriaRange:=Range("G1:I2"), CopyToRange:=Range("A4:E4"), Unique:=True End Sub
Sub TachMaID()
Dim Rws As Long, J As Integer, W As Long, Col As Byte, VTr As Byte
Dim Arr(): Const FC As String = "/"
Dim MaID As String
With Sheets("KQ")
Rws = .[A5].CurrentRegion.Rows.Count: Arr() = .[A5].Resize(Rws, 4).Value
ReDim dArr(1 To 9 * Rws, 1 To 4) As String
End With
For J = 1 To UBound(Arr())
MaID = Arr(J, 1): If MaID = "" Then Exit For
VTr = InStr(MaID, FC)
If VTr Then
MaID = MaID & FC
Do
W = W + 1: dArr(W, 1) = Left(MaID, VTr - 1)
For Col = 2 To 4
dArr(W, Col) = Arr(J, Col)
Next Col
MaID = Mid(MaID, VTr + 1, Len(MaID)): VTr = InStr(MaID, FC)
If VTr < 1 Then Exit Do
Loop
Else
W = W + 1:
For Col = 1 To 4
dArr(W, Col) = Arr(J, Col)
Next Col
End If
Next J
MsgBox W
End Sub
Chào Bạn,
Cảm ơn Bạn đã quan tâm,thực sự OT hay làm việc với bảng tính nhiều dữ liệu. Đối với dữ liệu thực trong file này nhiều khoảng 6 tháng và tất cả các khách hàng chắc tầm mấy chục ngàn dòng thôi ạ, vì dữ liệu lấy từ SQL vào nên cũng lấy theo từng thời điểm tùy thuộc nhu cầu người muốn lấy ạ.
Rất mong nhận được sự giúp đỡ của AnhCU
Bài đã được tự động gộp:
Xin lỗi mọi người, hỏi bài về khuya nên OT quên mất một điều kiện nữa là lọc duy nhất ạ.
Hiện đã bổ sung và gửi lại file ở bài 1.
Rất mong nhận được sự giúp đỡ của các Bạn.
Nếu sau khi lọc có kết quảLý ra chuyện này phải tự làm mới phải, may mà hôm nay mát trời:
lọc duy nhất 4 cột cho ra Sheet"KQ" như sauBiết đâu nà. . . !, phải chờ ý của chủ bài đăng thôi!
Xin chào Anh ongke0711,Em có dùng Power Query không? Anh thấy có tính năng tách Chuỗi (phân cách nhau bằng các ký hiệu) trong Cell thành từng dòng rất nhanh đó.
Lý ra chuyện này phải tự làm mới phải, may mà hôm nay mát trời:
PHP:Sub TachMaID() Dim Rws As Long, J As Integer, W As Long, Col As Byte, VTr As Byte Dim Arr(): Const FC As String = "/" Dim MaID As String With Sheets("KQ") Rws = .[A5].CurrentRegion.Rows.Count: Arr() = .[A5].Resize(Rws, 4).Value ReDim dArr(1 To 9 * Rws, 1 To 4) As String End With For J = 1 To UBound(Arr()) MaID = Arr(J, 1): If MaID = "" Then Exit For VTr = InStr(MaID, FC) If VTr Then MaID = MaID & FC Do W = W + 1: dArr(W, 1) = Left(MaID, VTr - 1) For Col = 2 To 4 dArr(W, Col) = Arr(J, Col) Next Col MaID = Mid(MaID, VTr + 1, Len(MaID)): VTr = InStr(MaID, FC) If VTr < 1 Then Exit Do Loop Else W = W + 1: For Col = 1 To 4 dArr(W, Col) = Arr(J, Col) Next Col End If Next J MsgBox W End Sub
Xin chào Bác Siwtomlọc duy nhất 4 cột cho ra Sheet"KQ" như sau
Sub FilterAndUnique()
Dim lastRow As Long, r As Long, ngay As Long, pos As Long, size As Long, currRow As Long
Dim MaID As String, s As String, ca As String, text As String, data(), dic As Object
With ThisWorkbook.Worksheets("DuLieu")
lastRow = .Cells(Rows.Count, "A").End(xlUp).Row
If lastRow < 2 Then Exit Sub
data = .Range("A2:F" & lastRow).Value
End With
text = String(25, "a")
With ThisWorkbook.Worksheets("KQ")
ngay = .Range("C1").Value
ca = LCase(.Range("C2").Value)
.Range("A5:D10000").ClearContents
End With
Set dic = CreateObject("Scripting.Dictionary")
currRow = 0
For r = 1 To UBound(data)
If (CDbl(data(r, 4)) >= ngay) And (CDbl(data(r, 4)) <= ngay + 1) Then
If ca = "all" Or ca = LCase(data(r, 5)) Then
s = data(r, 1)
pos = 1
size = Len(s)
Mid(text, 11, 5) = data(r, 2)
Mid(text, 16, 5) = data(r, 3)
Mid(text, 21, 5) = data(r, 6)
Do While pos < size
MaID = Mid(s, pos, 10)
Mid(text, 1, 10) = MaID
pos = pos + 11
If Not dic.exists(text) Then
currRow = currRow + 1
dic.Add text, ""
data(currRow, 1) = MaID
data(currRow, 2) = data(r, 2)
data(currRow, 3) = data(r, 3)
data(currRow, 4) = data(r, 6)
End If
Loop
End If
End If
Next r
ThisWorkbook.Worksheets("KQ").Range("A5").Resize(currRow, 4).Value = data
Set dic = Nothing
End Sub
Bạn thử test xem đúng ý không. Tôi làm với lọc duy nhất. Có đúng lọc duy nhất không hay liệt kê hết?
Code đòi hỏi MaID, MaSP, TenSP, MaKH đều có độ dài cố định. Dài bao nhiêu cũng được miễn là luôn như thế. Vd. MaID luôn có 12 ký tự, MaSP - luôn 7, TenSP - luôn 6, MaKH - luôn 8. Hiện thời chúng luôn có 10, 5, 5, 5 ký tự. Nếu khác thì sửa trong code.
Dấu phân cách các MaID có thể bất kỳ, thậm chí chỗ này là "/", chỗ khác là "," - dấu phẩy, chỗ khác nữa là ";" - dấu chấm phẩy, chỗ nọ lại là "*". Yêu cầu chỉ là không được có dấu cách trong chuỗi. Vd. ID00001729<dấu cách>/ID00001730 là không hợp lệ.
Tôi viết cho tập tin đính kèm của bạn. Vd. cho 3 ca thì bạn dùng "All".
Tôi viết xong chỉ test 1 lần. Thấy ra kết quả nhưng ngại dò xem kết quả đúng hay không. Vậy bạn tự kiểm tra. Thuật toán thì rõ ràng rồi. Chỉ sợ nhầm lẫn khi viết code thôi.
Nếu bạn có tầm trăm, vài trăm ngàn dòng dữ liệu thì báo cáo tốc độ nhé. Tôi hơi tò mò.
Mã:Sub FilterAndUnique() Dim lastRow As Long, r As Long, ngay As Long, pos As Long, size As Long, currRow As Long Dim MaID As String, s As String, ca As String, text As String, data(), dic As Object With ThisWorkbook.Worksheets("DuLieu") lastRow = .Cells(Rows.Count, "A").End(xlUp).Row If lastRow < 2 Then Exit Sub data = .Range("A2:F" & lastRow).Value End With text = String(25, "a") With ThisWorkbook.Worksheets("KQ") ngay = .Range("C1").Value ca = LCase(.Range("C2").Value) .Range("A5:D10000").ClearContents End With Set dic = CreateObject("Scripting.Dictionary") currRow = 0 For r = 1 To UBound(data) If (CDbl(data(r, 4)) >= ngay) And (CDbl(data(r, 4)) <= ngay + 1) Then If ca = "all" Or ca = LCase(data(r, 5)) Then s = data(r, 1) pos = 1 size = Len(s) Mid(text, 11, 5) = data(r, 2) Mid(text, 16, 5) = data(r, 3) Mid(text, 21, 5) = data(r, 6) Do While pos < size MaID = Mid(s, pos, 10) Mid(text, 1, 10) = MaID pos = pos + 11 If Not dic.exists(text) Then currRow = currRow + 1 dic.Add text, "" data(currRow, 1) = MaID data(currRow, 2) = data(r, 2) data(currRow, 3) = data(r, 3) data(currRow, 4) = data(r, 6) End If Loop End If End If Next r ThisWorkbook.Worksheets("KQ").Range("A5").Resize(currRow, 4).Value = data Set dic = Nothing End Sub
Thực ra code bài trước của tôi có lỗi mà bạn không phát hiện ra.tuy nhiên trường hợp ở đây là số lý tự (độ dài các ký tự ở trong cùng cột và ở giữa các cột trong thực tế sẽ không giống nhau ạ),sản phẩm này mã dài tên dài, sản phẩm khác tên dài mã ngắn v.v...
Sub FilterAndUnique()
Dim lastRow As Long, k As Long, r As Long, ngay As Long, pos As Long, size As Long, currRow As Long
Dim MaID As String, s As String, ca As String, text As String, data(), result(), dic As Object
With ThisWorkbook.Worksheets("DL")
lastRow = .Cells(Rows.Count, "A").End(xlUp).Row
If lastRow < 2 Then Exit Sub
data = .Range("A2:F" & lastRow).Value
End With
ReDim result(1 To 10000, 1 To 4)
With ThisWorkbook.Worksheets("KQ")
ngay = .Range("C1").Value
ca = LCase(.Range("C2").Value)
.Range("A5:D10000").ClearContents
End With
Set dic = CreateObject("Scripting.Dictionary")
currRow = 0
For r = 1 To UBound(data)
If (CDbl(data(r, 4)) >= ngay) And (CDbl(data(r, 4)) <= ngay + 1) Then
If ca = "all" Or ca = LCase(data(r, 5)) Then
s = data(r, 1) & "/"
pos = 1
size = Len(s)
text = String(58, Chr(0))
Mid(text, 17, Len(data(r, 2))) = data(r, 2)
Mid(text, 33, Len(data(r, 3))) = data(r, 3)
Mid(text, 49, Len(data(r, 6))) = data(r, 6)
Do While pos < size
k = InStr(pos, s, "/")
MaID = Mid(s, pos, k - pos)
Mid(text, 1, Len(MaID)) = MaID
pos = k + 1
If Not dic.exists(text) Then
currRow = currRow + 1
dic.Add text, ""
result(currRow, 1) = MaID
result(currRow, 2) = data(r, 2)
result(currRow, 3) = data(r, 3)
result(currRow, 4) = data(r, 6)
End If
Loop
End If
End If
Next r
If currRow Then ThisWorkbook.Worksheets("KQ").Range("A5").Resize(currRow, 4).Value = result
Set dic = Nothing
End Sub
Xin chào Bác SiwtomThực ra code bài trước của tôi có lỗi mà bạn không phát hiện ra.
Do tôi không nghĩ kỹ nên dùng 1 mảng data. Do code ghi kết quả vào mảng nguồn data nên có thể (không luôn luôn) ở vòng lặp nào đó dữ liệu đọc ra từ mảng nguồn data sẽ sai và dẫn tới lỗi.
Bây giờ tôi dùng thêm mảng kết quả.
Điều kiện: MaID, MaSP, TenSP có ít nhất là 1 ký tự, nhiều nhất là 15 ký tự, và MaKH có nhiều nhất là 10 ký tự. Tôi nghĩ là quá đủ. Nếu chưa đủ thì bạn hãy cho biết mỗi trường có thể có nhiều nhất là bao nhiêu ký tự. Cứ cho dư ra cũng được.
Hãy test kỹ.
Mã:Sub FilterAndUnique() Dim lastRow As Long, k As Long, r As Long, ngay As Long, pos As Long, size As Long, currRow As Long Dim MaID As String, s As String, ca As String, text As String, data(), result(), dic As Object With ThisWorkbook.Worksheets("DL") lastRow = .Cells(Rows.Count, "A").End(xlUp).Row If lastRow < 2 Then Exit Sub data = .Range("A2:F" & lastRow).Value End With ReDim result(1 To 10000, 1 To 4) With ThisWorkbook.Worksheets("KQ") ngay = .Range("C1").Value ca = LCase(.Range("C2").Value) .Range("A5:D10000").ClearContents End With Set dic = CreateObject("Scripting.Dictionary") currRow = 0 For r = 1 To UBound(data) If (CDbl(data(r, 4)) >= ngay) And (CDbl(data(r, 4)) <= ngay + 1) Then If ca = "all" Or ca = LCase(data(r, 5)) Then s = data(r, 1) & "/" pos = 1 size = Len(s) text = String(58, Chr(0)) Mid(text, 17, Len(data(r, 2))) = data(r, 2) Mid(text, 33, Len(data(r, 3))) = data(r, 3) Mid(text, 49, Len(data(r, 6))) = data(r, 6) Do While pos < size k = InStr(pos, s, "/") MaID = Mid(s, pos, k - pos) Mid(text, 1, Len(MaID)) = MaID pos = k + 1 If Not dic.exists(text) Then currRow = currRow + 1 dic.Add text, "" result(currRow, 1) = MaID result(currRow, 2) = data(r, 2) result(currRow, 3) = data(r, 3) result(currRow, 4) = data(r, 6) End If Loop End If End If Next r If currRow Then ThisWorkbook.Worksheets("KQ").Range("A5").Resize(currRow, 4).Value = result Set dic = Nothing End Sub
text = String(58, Chr(0))
Mid(text, 17, Len(data(r, 2))) = data(r, 2)
Mid(text, 33, Len(data(r, 3))) = data(r, 3)
Mid(text, 49, Len(data(r, 6))) = data(r, 6)
Xin chào Bác Siwtom
Cảm ơn Bác đã giúp đỡ con ạ, code chạy nhanh và kết quả OK so với dữ liệu con gửi lên ạ.Hiện đối với mã sản phẩm thì quy định tối thiểu là 18 ký tự và tối đa là 25.Còn tên sản phẩm thì không có quy định có lúc thì dưới 10 có tên thì dài nhưng không quá 35 ký tự nếu số ký tự bị vượt quá trong code quy định thì con cần phải sửa con số nào trong code vậy Bác, nhờ Bác chú thích giúp con các con số 58,17,33,49 trong các dòng code sau với ạ.
Xin chào Bác Siwtom
Cảm ơn Bác đã giúp đỡ con ạ, code chạy nhanh và kết quả OK so với dữ liệu con gửi lên ạ.Hiện đối với mã sản phẩm thì quy định tối thiểu là 18 ký tự và tối đa là 25.Còn tên sản phẩm thì không có quy định có lúc thì dưới 10 có tên thì dài nhưng không quá 35 ký tự nếu số ký tự bị vượt quá trong code quy định thì con cần phải sửa con số nào trong code vậy Bác, nhờ Bác chú thích giúp con các con số 58,17,33,49 trong các dòng code sau với ạ.
Chúc Bác nhiều sức khỏe.Mã:text = String(58, Chr(0)) Mid(text, 17, Len(data(r, 2))) = data(r, 2) Mid(text, 33, Len(data(r, 3))) = data(r, 3) Mid(text, 49, Len(data(r, 6))) = data(r, 6)
text = String("độ lớn", Chr(0))
Mid(text, max(MaID) + 2, Len(data(r, 2))) = data(r, 2)
Mid(text, max(MaID) + max(MaSP) + 3, Len(data(r, 3))) = data(r, 3)
Mid(text, max(MaID) + max(MaSP) + max(TenSP) + 4, Len(data(r, 6))) = data(r, 6)
Xin chào anh ongke0711,Em xem lại qui định tạo mã các trường làm khoá. Đúng ra là phải cố định số ký tự đó em, chỉ có trường tên, diễn giải là không cố định thôi.
@batman1: Em nghĩ không cần dùng tới trường TenSP đâu anh, MaSP là đủ đại diện rồi.
Cảm ơn Bác Siwtom nhiều ạ,Mã:text = String("độ lớn", Chr(0))
với "độ lớn" = max(MaID) + max(MaSP) + max(TenSP) + max(MaKH) + 3 (3 ký tự 0 phân cách 4 thành phần)
Với max(MaID) = max(MaSP) = max(TenSP) = 15 và max(MaKH) = 10 thì "độ lớn " = 58
text có dạng: = <MaID><một loạt ký tự 0 thứ nhất><ký tự 0 phân cách><MaSP><một loạt ký tự 0 thứ hai><ký tự 0 phân cách><TenSP><một loạt ký tự 0 thứ ba><ký tự 0 phân cách><MaKH><một loạt ký tự 0 thứ tư>
Trong đó:
<MaID><một loạt ký tự 0 thứ nhất> = max(MaID)
<MaSP><một loạt ký tự 0 thứ hai> = max(MaSP)
<TenSP><một loạt ký tự 0 thứ ba> = max(TenSP)
<MaKH><một loạt ký tự 0 thứ tư> = max(MaKH)
Mã:Mid(text, max(MaID) + 2, Len(data(r, 2))) = data(r, 2) Mid(text, max(MaID) + max(MaSP) + 3, Len(data(r, 3))) = data(r, 3) Mid(text, max(MaID) + max(MaSP) + max(TenSP) + 4, Len(data(r, 6))) = data(r, 6)