Nối dữ liệu có ID giống nhau thành 1 dòng (1 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

MinhKhai

Giải pháp Ếc-xào
Tham gia
16/4/08
Bài viết
941
Được thích
574
Chào các anh chị

Em có file dữ liệu như đính kèm. trong đó cột A là các ID được thể hiện thành nhiều dòng.
Nhờ các anh chị tạo cho đoạn code để gom các email tại cột B cùng ID vào 1 dòng

Xin chân thành cảm ơn !

1629490532422.png
 

File đính kèm

File đính kèm

Upvote 0
Chào các anh chị

Em có file dữ liệu như đính kèm. trong đó cột A là các ID được thể hiện thành nhiều dòng.
Nhờ các anh chị tạo cho đoạn code để gom các email tại cột B cùng ID vào 1 dòng

Xin chân thành cảm ơn !
Góp thêm một cách cho bạn.
hãy nhấn nút CHẠY CODE và xem kết quả trong các cột từ F2 đến H(n). nếu bạn muốn chỗ khác thì sửa dòng 2 dòng có .[F2].resize(.......) ở cuối Modul NOI_DIA_CHI nhé- Tôi tin là bạn làm được. Dữ liệu từ cột A đến cột E nếu muốn có thể xóa bỏ
 

File đính kèm

Upvote 0
Góp thêm một cách cho bạn.
hãy nhấn nút CHẠY CODE và xem kết quả trong các cột từ F2 đến H(n). nếu bạn muốn chỗ khác thì sửa dòng 2 dòng có .[F2].resize(.......) ở cuối Modul NOI_DIA_CHI nhé- Tôi tin là bạn làm được. Dữ liệu từ cột A đến cột E nếu muốn có thể xóa bỏ
Tôi thấy đoạn:
If KQ(j, 2) <> epmty Then KQ(j, 2) = KQ(j, 2) & "," & Arr(i, 2) Else KQ(j, 2) = Arr(i, 2)
phải đặt điều kiện Arr(i, 2) <> Epmty mới đúng chứ bạn tức là có email thì mới nối (tránh kết quả ra toàn dấu phẩy). Và theo tôi nếu không thỏa điều kiện thì không làm gì cả nên đâu cần Else KQ(j, 2) = Arr(i, 2)
 
Upvote 0
Tôi thấy đoạn:
If KQ(j, 2) <> epmty Then KQ(j, 2) = KQ(j, 2) & "," & Arr(i, 2) Else KQ(j, 2) = Arr(i, 2)
phải đặt điều kiện Arr(i, 2) <> Epmty mới đúng chứ bạn tức là có email thì mới nối (tránh kết quả ra toàn dấu phẩy). Và theo tôi nếu không thỏa điều kiện thì không làm gì cả nên đâu cần Else KQ(j, 2) = Arr(i, 2)
Cảm ơn anh đã xem bài.
Tôi cũng đã thử rồi, nếu If Arr(i,2)<> empty then.... thì khi chay vẫn còn dấu "," do KQ(j,2)="", tiếp đến là dấu ", " , tiếp đến mới là Arr(i,2).
Và nếu vô hiệu Else KQ(j,2)=Arr(i,2) thì khi tìm thấy mã trùng sẽ KQ(j,2)= rỗng.!

Code tôi học mót còn có thiếu sót gì mong anh chị em xem qua chỉ giáo.
Trân trọng!
 
Upvote 0

File đính kèm

Upvote 0
Cảm ơn anh đã xem bài.
Tôi cũng đã thử rồi, nếu If Arr(i,2)<> empty then.... thì khi chay vẫn còn dấu "," do KQ(j,2)="", tiếp đến là dấu ", " , tiếp đến mới là Arr(i,2).
Và nếu vô hiệu Else KQ(j,2)=Arr(i,2) thì khi tìm thấy mã trùng sẽ KQ(j,2)= rỗng.!

Code tôi học mót còn có thiếu sót gì mong anh chị em xem qua chỉ giáo.
Trân trọng!
Ngay sau vòng for thêm if arr(i,2)<>"" luôn để không phải vào xét key đã tồn tại hay chưa, vừa đỡ thời gian xét dic, vừa tránh những lỗi mà bạn nêu
 
Upvote 0
Cảm ơn anh đã xem bài.
Tôi cũng đã thử rồi, nếu If Arr(i,2)<> empty then.... thì khi chay vẫn còn dấu "," do KQ(j,2)="", tiếp đến là dấu ", " , tiếp đến mới là Arr(i,2).
Và nếu vô hiệu Else KQ(j,2)=Arr(i,2) thì khi tìm thấy mã trùng sẽ KQ(j,2)= rỗng.!

Code tôi học mót còn có thiếu sót gì mong anh chị em xem qua chỉ giáo.
Trân trọng!
Bạn là gì thì với trường hợp này cũng sẽ dư 1 dấu phẩy:
1629508538249.png
Với điều kiện của bạn thì kết quả sẽ là:
tram.ptn@asgl.vn,,HANG.BUIMINH@THAITAN.COM,OPS.IMPORT@ACSV.COM.VN

Vậy theo tôi nên dư dấu phẩy đàng sau thì hơn với điều kiện và cách nối: If Arr(i, 2) <> epmty Then KQ(j, 2) = KQ(j, 2) & Arr(i, 2) & ","
Nếu cần thiết thì xóa dấu phẩy sau khi chạy hết dữ liệu, còn như tôi nghĩ thì để nguyên cũng được.
 
Upvote 0
Cảm ơn bạn, mình sẽ mò mẫm thêm, món này mình còn đang bỡ ngỡ lắm.
Trong lúc bác add key tạo item của key đó là số thứ tự k rồi. Thì khi kiểm tra key đã tồn tại thì chỉ cần lôi cái item của key đó ra (tức là số thứ tự k) rồi gán giá trị vào md(k,cột) = mn(i,cột) thôi bác. Còn hiện tại bác làm là như kiểu đi chợ, chạy quanh một vòng coi mặt hàng có không, có thì ghi mặt hàng đó vào sổ rồi chạy về nhà lấy tiền. Lấy tiền xong lại chạy ra chợ để mua :D
Hài hước tí thôi không có ý gì nhé bác
 
Upvote 0
Trong lúc bác add key tạo item của key đó là số thứ tự k rồi. Thì khi kiểm tra key đã tồn tại thì chỉ cần lôi cái item của key đó ra (tức là số thứ tự k) rồi gán giá trị vào md(k,cột) = mn(i,cột) thôi bác. Còn hiện tại bác làm là như kiểu đi chợ, chạy quanh một vòng coi mặt hàng có không, có thì ghi mặt hàng đó vào sổ rồi chạy về nhà lấy tiền. Lấy tiền xong lại chạy ra chợ để mua :D
Hài hước tí thôi không có ý gì nhé bác
Cũng phải cải tiến cách đi chợ thôi, giờ Covid cấm đi nhiều lần rồi.
 
Upvote 0
Chào các anh chị

Em có file dữ liệu như đính kèm. trong đó cột A là các ID được thể hiện thành nhiều dòng.
Nhờ các anh chị tạo cho đoạn code để gom các email tại cột B cùng ID vào 1 dòng

Xin chân thành cảm ơn !

View attachment 264445
Tham khảo thêm 1 cách
Mã:
Option Explicit

Sub ghep()
Dim Nguon
Dim Tk
Dim h, m, s
Dim Kq
Dim i, j, k

With Sheet3
    Nguon = .Range("A2", .Range("C2").End(xlDown))
End With
ReDim Tk(24, 60, 60)
ReDim Kq(1 To UBound(Nguon), 1 To 3)
For i = 1 To UBound(Nguon)
    If Nguon(i, 2) <> "" Then
        h = Hour(Nguon(i, 3))
        m = Minute(Nguon(i, 3))
        s = Second(Nguon(i, 3))
        If Tk(h, m, s) = "" Then
            k = k + 1
            Tk(h, m, s) = k
            Kq(k, 1) = Nguon(i, 1)
            Kq(k, 3) = Nguon(i, 3)
            Kq(k, 2) = Nguon(i, 2)
        Else
            j = Tk(h, m, s)
            Kq(j, 2) = Kq(j, 2) & ", " & Nguon(i, 2)
        End If
    End If
Next i
Sheet3.Range("E2").Resize(k, 3) = Kq
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Ngay sau vòng for thêm if arr(i,2)<>"" luôn để không phải vào xét key đã tồn tại hay chưa, vừa đỡ thời gian xét dic, vừa tránh những lỗi mà bạn nêu
Cảm ơn bạn đã xem bài và chỉ giáo. Đúng là thêm điều kiện Arr(i,2)<> empty vào ngay sau vòng for i thì tránh được hết những lỗi thừa dấu ", ".
và code được sửa lại như sau:
Mã:
Sub NOI()
Dim Arr(), KQ(), DK, dic As Object
Dim i As Long, j As Long, t&, d&
With Sheets("Data")
d = .Cells(Rows.Count, 1).End(xlUp).Row
Arr = .Range("A2:C" & d).Value
ReDim KQ(1 To UBound(Arr), 1 To 4)
  Set dic = CreateObject("Scripting.Dictionary")

For i = 1 To UBound(Arr)
If Arr(i, 2) <> Empty Then
     DK = Arr(i, 1)
    If Not dic.Exists(DK) Then
          t = t + 1: dic.Add DK, t
        KQ(t, 1) = t: KQ(t, 2) = DK: KQ(t, 3) = Arr(i, 2): KQ(t, 4) = Arr(i, 3)
    Else
        j = dic.Item(DK)
        KQ(j, 3) = KQ(j, 3) & ", " & Arr(i, 2)
    End If
End If
Next i
If t Then
    .[F2].Resize(UBound(Arr), 4).ClearContents
    .[F2].Resize(t, 4) = KQ
End If
End With
Set dic = Nothing
End Sub
Bài đã được tự động gộp:

Bạn là gì thì với trường hợp này cũng sẽ dư 1 dấu phẩy:
View attachment 264453
Với điều kiện của bạn thì kết quả sẽ là:
tram.ptn@asgl.vn,,HANG.BUIMINH@THAITAN.COM,OPS.IMPORT@ACSV.COM.VN

Vậy theo tôi nên dư dấu phẩy đàng sau thì hơn với điều kiện và cách nối: If Arr(i, 2) <> epmty Then KQ(j, 2) = KQ(j, 2) & Arr(i, 2) & ","
Nếu cần thiết thì xóa dấu phẩy sau khi chạy hết dữ liệu, còn như tôi nghĩ thì để nguyên cũng được.
Trường hợp bạn nếu đúng là tôi chủ quan không tính đến.
Tôi đã sửa lại theo góp ý của bạn @Nhattanktnn thêm If arr(i,2)<> empty then ... vào ngay sau vòng lặp For là giải quyết được các lỗi thừa dấu " ," rồi, nó cũng tiết kiệm được thời gian kiểm tra dic(DK) đã tồn tại hay chưa==> tốc độ được cải thiện.
Một lần nữa trân trọng cảm ơn các bạn đã góp ý.
 
Lần chỉnh sửa cuối:
Upvote 0
Cảm ơn bạn đã xem bài và chỉ giáo. Đúng là thêm điều kiện Arr(i,2)<> empty vào ngay sau vòng for i thì tránh được hết những lỗi thừa dấu ", ".
và code được sửa lại như sau:
Mã:
Sub NOI()
Dim Arr(), KQ(), DK, dic As Object
Dim i As Long, j As Long, t&, d&
With Sheets("Data")
d = .Cells(Rows.Count, 1).End(xlUp).Row
Arr = .Range("A2:C" & d).Value
ReDim KQ(1 To UBound(Arr), 1 To 4)
  Set dic = CreateObject("Scripting.Dictionary")

For i = 1 To UBound(Arr)
If Arr(i, 2) <> Empty Then
     DK = Arr(i, 1)
    If Not dic.Exists(DK) Then
          t = t + 1: dic.Add DK, t
        KQ(t, 1) = t: KQ(t, 2) = DK: KQ(t, 3) = Arr(i, 2): KQ(t, 4) = Arr(i, 3)
    Else
        j = dic.Item(DK)
        KQ(j, 3) = KQ(j, 3) & ", " & Arr(i, 2)
    End If
End If
Next i
If t Then
    .[F2].Resize(UBound(Arr), 4).ClearContents
    .[F2].Resize(t, 4) = KQ
End If
End With
Set dic = Nothing
End Sub
Bài đã được tự động gộp:


Trường hợp bạn nếu đúng là tôi chủ quan không tính đến.
Tôi đã sửa lại theo góp ý của bạn @Nhattanktnn thêm If arr(i,2)<> empty then ... vào ngay sau vòng lặp For là giải quyết được các lỗi thừa dấu " ," rồi, nó cũng tiết kiệm được thời gian kiểm tra dic(DK) đã tồn tại hay chưa==> tốc độ được cải thiện.
Một lần nữa trân trọng cảm ơn các bạn đã góp ý.
Đặt điều kiện ở đó (và như code của bạn) là không được đâu bạn ơi. Với trường hợp thế này:
1629512192266.png
thì ID của hai dòng đầu sẽ bị bỏ qua, mà lẽ ra phải có kết quả và Email = Empty kia chứ
 
Upvote 0
Đặt điều kiện ở đó (và như code của bạn) là không được đâu bạn ơi. Với trường hợp thế này:

thì ID của hai dòng đầu sẽ bị bỏ qua, mà lẽ ra phải có kết quả và Email = Empty kia chứ
Sao không chờ phản hồi của người hỏi (OP) ? Biết đâu người ta bỏ qua khi email có giá trị là rỗng?

.
 
Upvote 0
Sao không chờ phản hồi của người hỏi (OP) ? Biết đâu người ta bỏ qua khi email có giá trị là rỗng?

.
Tất nhiên nếu người dùng không cần thì ta không bàn đến nhưng ở đây đang nói đến chuyện lường hết các trường hợp có thể xảy ra khi lập trình thôi.

@HUONGHCKT
Theo tôi thì chỗ Else của bài #4 viết lại thế này là ổn
Rich (BB code):
        j = dic.Item(DK)
        If Arr(i, 2) <> epmty Then
            If KQ(j, 2) = Empty Then
                KQ(j, 2) = Arr(i, 2)
            Else
                KQ(j, 2) = KQ(j, 2) & "," & Arr(i, 2)
            End If
        End If
Dài ra tí nhưng dễ hiểu và có kết quả đúng
 
Upvote 0
Chào các anh chị
Trước hết xin được cảm ơn các anh chị đã giúp đỡ. Tất cả các hỗ trợ của anh chị phía trên đều đã đáp ứng yêu cầu của mình. Code không chỉ chạy đúng yêu cầu mà còn chạy rất mượt dù mình đã thử tăng dữ liệu gấp vài lần như thế.
File ban đầu của bạn @HUONGHCKT đúng là có thừa dấu phân cách nhưng sau đó vấn đề này đã được xử lý. Khi dữ liệu không có email để ghép, phần kết quả không list ra. Cách này cũng là mong muốn của mình. Giúp đỡ của bác @Hoàng Tuấn 868 thì khi vùng dữ liệu gốc bị trống dòng nào đó, kết quả vẫn ra dòng 1 trống. Cách này cũng hữu ích khi mình cần rà roát dữ liệu.
Code của bạn @CHAOQUAY mình thử thì ra kết quả có 1 dòng. Có lẽ mình làm sai gì đó.
Có 1 tình huống nhỏ là nếu cột ID bị tác động, kiểu dữ liệu đang là text chuyển sang là number lúc này code nhận thành 2 ID khác nhau. Các anh chị có thể bẫy lỗi phần này được không ?
Cảm ơn bạn @Maika8008 @Nhattanktnn@Phuocam nhiều nhé.
 
Upvote 0
Bài này hình như chỉ cần 1 dòng này là ra kết quả rồi:
Ghepmail2:=CONCATENATEX(SUMMARIZE('Table1', 'Table1'[ID],),[Email],", ")
Chủ thớt tham khảo nhé!
 
Upvote 0
Có 1 tình huống nhỏ là nếu cột ID bị tác động, kiểu dữ liệu đang là text chuyển sang là number lúc này code nhận thành 2 ID khác nhau. Các anh chị có thể bẫy lỗi phần này được không ?
Thử thay:

DK = Arr(i, 1)

bằng:

DK = CStr(Arr(i, 1))

.
 
Upvote 0
Có 1 tình huống nhỏ là nếu cột ID bị tác động, kiểu dữ liệu đang là text chuyển sang là number lúc này code nhận thành 2 ID khác nhau. Các anh chị có thể bẫy lỗi phần này được không ?
Mình thấy bạn cũng học code lâu rồi, có tìm hiểu về ADO, SQL rất nhiều mình nghĩ mấy cái này đâu khó gì với bạn đâu
Lỗi phần này thì mình sẽ chuyển nó về cùng dạng text, muốn làm điều đó thì theo code bạn @HUONGHCKT phần DK=Arr(i, 1) bạn sửa thành DK = CStr(Arr(i, 1))
Sửa: Nãy không thấy trả lời của bác @Phuocam :D
 
Upvote 0
1 máy quét 1 thời điểm chỉ có 1 ID => bài này có thể thống kê theo cột Time, => cùng 1 ID, dù là text hay number cũng ra kết quả như nhau
 
Upvote 0
Mình thấy bạn cũng học code lâu rồi, có tìm hiểu về ADO, SQL rất nhiều mình nghĩ mấy cái này đâu khó gì với bạn đâu
Lỗi phần này thì mình sẽ chuyển nó về cùng dạng text, muốn làm điều đó thì theo code bạn @HUONGHCKT phần DK=Arr(i, 1) bạn sửa thành DK = CStr(Arr(i, 1))
Sửa: Nãy không thấy trả lời của bác @Phuocam :D
Mình dùng Excel nhưng chỉ dùng ở mức cơ bản thôi. Công việc hàng ngày cũng ít dùng Excel mà toàn thao tác trên phần mềm. Trước mình có hỏi về ADO, SQL là do các phần mềm đều dùng SQL Server database. Lấy được dữ liệu trực tiếp từ SQL Server ra Excel nên cảm thấy hứng thú và tự hào lắm. Hiện tại Excel phiên bản mới (Office 2019, Offce365) hỗ trợ lấy dữ liệu từ các nguồn database khá dễ dàng nên cũng lơ là ADO hơn.
Đoạn code các bạn trên giúp mình thực sự chưa hiểu hết nên là hỏi thật
Còn về vấn đề mà bạn @Phuocam nêu mình cũng nêu ở phần trả lời trước: Code của Hoàng Tuấn 868 đã xử lý theo tình huống giữ lại ID khi trường email rỗng, còn của HUONGHCKT thì loại bỏ. Mình có cả 2 tình huống này rồi nên không hỏi thêm nữa. Như bạn Maika8008 đã nói user đưa ra vấn đề nhưng chưa chắc chọn được hoặc lường hết các tình huống, các anh chị có kinh nghiệm cứ trao đổi để "vét cạn" các tình huống giúp.
Bài đã được tự động gộp:

1 máy quét 1 thời điểm chỉ có 1 ID => bài này có thể thống kê theo cột Time, => cùng 1 ID, dù là text hay number cũng ra kết quả như nhau
Ý bác là lấy trường thời gian thay cho trường ID để pass qua vấn đề text hay number phải không ?
Bài đã được tự động gộp:

Sub NOI()
Dim Arr(), KQ(), DK, dic As Object
Dim i As Long, j As Long, t&, d&
Nhờ bạn giải thích giúp cách khai báo t&, d&. Mình chưa thấy cách khai báo thế này bao giờ
Ngoài ra việc khai báo dạng Dim Arr(), KQ(), DK, dic As Object thì Arr(), KQ(), DK, dic đều là Object à, thay vì: Dim Arr() As Object, KQ() As Object, DK As Object, dic As Object
 
Lần chỉnh sửa cuối:
Upvote 0
Code của Hoàng Tuấn 868 đã xử lý theo tình huống giữ lại ID khi trường email rỗng,
- Mình lấy cả trường hợp ID không có Email để có thể kiểm tra vì một lý do nào đấy (có thể do lỗi, có thể do sót) còn có hướng khắc phục.
- Nếu bỏ đi hết những trường hợp không có Email mà bỏ luôn ID thì cứ tưởng đủ hết rồi không kiểm tra lại thì có khi thiếu mà không biết. Tất nhiên mỗi bạn một ý tưởng khác nhau, khi kết hợp lại thì dù sao cũng phần nào ổn hơn chút chút.
Thân.
 
Upvote 0
Nhờ bạn giải thích giúp cách khai báo t&, d&. Mình chưa thấy cách khai báo thế này bao giờ
Ngoài ra việc khai báo dạng Dim Arr(), KQ(), DK, dic As Object thì Arr(), KQ(), DK, dic đều là Object à, thay vì: Dim Arr() As Object, KQ() As Object, DK As Object, dic As Object
Mình hiểu là t&,d& là kiểu varian, Còn Dim KQ(), Arr() là khai báo mảng chưa biết rõ kích thước, DK để trống thì được coi là mặc định Varian.
Không biết là hiểu có đúng không? Kiến thức VBA của mình chỉ là i, t thôi, toàn là học mót và chắp vá trên diễn đàn này và một số trang khác.
Bạn muốn tìm hiểu kỹ hãy đăng 1 topic hỏi các anh chị em có kiến thức sâu rộng về VBA nói riêng và EX nói chung. Chắc là các anh ấy sẽ giải đáp thôi mà.
Chúc vui, khỏe, và an toàn trong đại dịch.
Thân.
 
Upvote 0
Nhờ bạn giải thích giúp cách khai báo t&, d&. Mình chưa thấy cách khai báo thế này bao giờ
Ngoài ra việc khai báo dạng Dim Arr(), KQ(), DK, dic As Object thì Arr(), KQ(), DK, dic đều là Object à, thay vì: Dim Arr() As Object, KQ() As Object, DK As Object, dic As Object
t& là khai báo tắt của t As Long. Danh sách các kiểu biến có thể khai báo tắt như sau:
String $
Integer %
Long &
Single !
Double #
Currency @

Nếu khai báo 1 biến mà không chỉ định kiểu thì vba xem đó là kiểu Variant.

Nếu là mảng thì có thể khai báo có cặp ngoặc hoặc để trống (tức Variant) vì mảng cũng là kiểu Variant.

Nếu 1 biến arr được khai báo là Variant thì có thể tạm dùng vào việc khác nhưng đã khai báo arr() thì chỉ có thể là mảng thôi. Khai báo arr() As Object là không đúng, vba sẽ báo lỗi.

Variant khác với Object (đối tượng): như shape, range, dic, fso... Nếu khai báo dic as Variant mà Set dic là scripting.dictionary thì sẽ bị lỗi.
 
Upvote 0
Bài đã được tự động gộp:


Ý bác là lấy trường thời gian thay cho trường ID để pass qua vấn đề text hay number phải không ?
Với dữ liệu trong file bài 1: 1 thời điểm chỉ có 1 ID => thống kê theo cột "ID" hay "Time"cái nào cũng ra kết quả như nhau cả thôi.
 
Upvote 0
Thử code này anh @MinhKhai
Mã:
Sub GPE_hehehe()
Dim i&, k&, Data(), KetQua(), Dic As Object
On Error Resume Next
Data = Range(Sheets("Data").[A1], Sheets("Data").[A100000].End(3)).Resize(, 4)
ReDim KetQua(1 To UBound(Data), 1 To 3)
Set Dic = CreateObject("Scripting.Dictionary")

For i = 1 To UBound(Data)
    If Data(i, 2) <> Empty Then
        If Not Dic.exists(CStr(Data(i, 1))) Then
            k = k + 1
            Dic(CStr(Data(i, 1))) = k
            KetQua(k, 1) = Data(i, 1)
            KetQua(k, 2) = Data(i, 2)
            KetQua(k, 3) = Data(i, 3)
        Else
            KetQua(Dic.Item(CStr(Data(i, 1))), 2) = KetQua(Dic.Item(CStr(Data(i, 1))), 2) & "," & Data(i, 2)
        End If
    End If
Next
Sheets("KetQua").[A1].Resize(i - 1, 3) = KetQua
Sheets("KetQua").Activate
End Sub
Click RUN => kết quả bên Sheet KetQua

Em có góp ý thêm chút, khi email đi nhiều người e thấy ngăn cách các mail với nhau kiểu như này "; " chứ không phải dấu ","
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0

Bài viết mới nhất

Back
Top Bottom