Tìm kiếm với dữ liệu gần đúng (1 người xem)

  • Thread starter Thread starter huy vu
  • Ngày gửi Ngày gửi
Liên hệ QC

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

huy vu

Thành viên hoạt động
Tham gia
29/2/12
Bài viết
164
Được thích
1
Căn cứ bài viết tại Topic: http://www.giaiphapexcel.com/forum/showthread.php?94900-Xử-lý-48-triệu-dòng-trong-SQL-Server
Dear các bác cao thủ,

Em hiện có bảng A gồm 48 triệu dòng dữ liệu có cột số máy của xe. Kèm đó em có bảng B gồm loại số máy và model xe. Em muốn cập nhật model vào bảng A thì làm như thế nào tốt nhất nhỉ? Em có database ở SQL Server và muốn dùng lệnh SQL để chạy tự động ạ

Bảng A và B em gửi kèm theo file dưới đây.

Em xin cảm ơn các bác trước ạ!

Chủ Topic có hỏi về SQL

E muốn chuyển hướng làm VBA nên đặt lại câu hỏi sang Box lập trình
Tôi cũng chỉ nghe láng máng SQL nên chưa biết j. Với dữ liệu hơn 40 triệu dòng khả dùng DIC cũng chạy được
E có học mót sử dụng DIC, tuy nhiên theo yêu cầu của bài toán, Nếu như loại số máy bên Bang A giống hệt như loại số máy bên Bang B thì e làm được. Nhưng loại số máy bên bảng A có bổ sung thêm các ký tự đằng sau nên chưa biết sử lý tình huống thế nào
Nhân tiện bài toán của chủ Topic, E pốt file hỏi các thành viên
Mong nhận được sự trợ giúp
Mã:
Sub LoaiXe()
    Application.ScreenUpdating = False
    Dim T As Double, Dic1 As Object
    Dim MyRng As Range
    Dim SoMay, SoKhung, MoDel, HangXe
    Dim Source, ThongTin, Itm
    Dim I As Long
    T = Timer
    With Sheet1
        SoMay = .Range(.[E2], .[E1048576].End(3)).Value
    End With
    With Sheet2
        Set MyRng = Range(.Range("A2"), .Range("A1048576").End(xlUp))
        Source = MyRng
        MoDel = MyRng.Offset(, 1)
        HangXe = MyRng.Offset(, 2)
    End With
    ReDim ThongTin(1 To UBound(SoMay), 1 To 2)
    Set Dic1 = CreateObject("Scripting.Dictionary")
        For I = 1 To UBound(Source)
            Itm = CStr(Source(I, 1))
            If Itm > "" And Not Dic1.exists(Itm) Then
                Dic1.Add Itm, I
            End If
        Next
    For I = 1 To UBound(SoMay)
        Itm = CStr(SoMay(I, 1))
        If Dic1.exists(Itm) Then
            ThongTin(I, 1) = MoDel(Dic1.Item(Itm), 1)
            ThongTin(I, 2) = HangXe(Dic1.Item(Itm), 1)
        End If
    Next
    Sheet1.Range("G2").Resize(UBound(SoMay), 2) = ThongTin
    MsgBox Timer - T, , "Thoi gian"
    Application.ScreenUpdating = True
End Sub

Mong các thành viên giúp đỡ
 

File đính kèm

40 triệu dòng lớn hơn giới hạn của excel thì dic không chạy nổi.
Nếu số dòng ít hơn, theo mình thấy bảng B các số máy là duy nhất, số máy bảng A mới lặp lại nên gán số máy ở bảng B vào dictionary có vẻ chưa hợp lý. Mình chỉ nghĩ ra cách dùng 2 vòng lặp lồng nhau: vòng for duyệt qua số máy bảng A và vòng Do Loop duyệt qua số máy bảng B để so sánh 2 số máy.
 
Upvote 0
40 triệu dòng lớn hơn giới hạn của excel thì dic không chạy nổi.
Nếu số dòng ít hơn, theo mình thấy bảng B các số máy là duy nhất, số máy bảng A mới lặp lại nên gán số máy ở bảng B vào dictionary có vẻ chưa hợp lý. Mình chỉ nghĩ ra cách dùng 2 vòng lặp lồng nhau: vòng for duyệt qua số máy bảng A và vòng Do Loop duyệt qua số máy bảng B để so sánh 2 số máy.
Giả sử dữ liệu trong giới hạn của excel..mong các thành viên hỗ trợ
 
Upvote 0
Bên bảng B chỉ là vài ký tự đầu của bên bảng A. Đâu có dùng Dictionary được. Có cách dùng ArrayCollection, nhưng rất rắc rối.
Cách dễ hơn hêt là sort bảng B (1), rồi dùng phép tìm nhị phân - binary sort (2).

(1) Bạn Siwtom có bài nói về các cách sort. Chịu khó tìm sẽ được.
(2) Cách tìm nhị phân rất căn bản. Bạn tự làm được mà.
 
Upvote 0
Bên bảng B chỉ là vài ký tự đầu của bên bảng A. Đâu có dùng Dictionary được. Có cách dùng ArrayCollection, nhưng rất rắc rối.
Cách dễ hơn hêt là sort bảng B (1), rồi dùng phép tìm nhị phân - binary sort (2).

(1) Bạn Siwtom có bài nói về các cách sort. Chịu khó tìm sẽ được.
(2) Cách tìm nhị phân rất căn bản. Bạn tự làm được mà.
dạ. e nghĩ có thể thêm ký tự đại diện * để thay thế cho các ký tự đằng sau như dùng hàm ngoài bảng tính
 
Upvote 0
dạ. e nghĩ có thể thêm ký tự đại diện * để thay thế cho các ký tự đằng sau như dùng hàm ngoài bảng tính
Trong khi chờ đợi giải pháp sao không thử code này
PHP:
Sub FindText()
Dim BangB(), I, Found, FoundFirst
With Sheet2
    BangB = .Range(.[A2], .[C65536].End(3)).Value
End With
For I = 1 To UBound(BangB)
    Set Found = Sheet1.[E:E].Find(BangB(I, 1), , , 2)
    If Not Found Is Nothing Then
        FoundFirst = Found.Address
        Do
        Set Found = Sheet1.[E:E].FindNext(Found)
            Found.Offset(, 2) = BangB(I, 2)
            Found.Offset(, 3) = BangB(I, 3)
        Loop Until Found.Address = FoundFirst
    End If
Next
End Sub
 
Upvote 0
Nếu dữ liệu nhiều mà dùng code bài số 7 chắc phải đi pha cafe uống quá
Thử thêm với code này
PHP:
Sub FindText()
Dim BangA(), BangB(), I, J, Found, FoundFirst
With Sheet1
    BangA = .Range(.[a2], .[A1000000].End(3)).Resize(, 8).Value
End With
With Sheet2
    BangB = .Range(.[a2], .[C1000000].End(3)).Value
End With
For I = 1 To UBound(BangA)
    For J = 1 To UBound(BangB)
        If BangA(I, 5) Like BangB(J, 1) & "*" Then
            BangA(I, 7) = BangB(J, 2)
            BangA(I, 8) = BangB(J, 3)
        End If
    Next
Next
Sheet1.[a2].Resize(I - 1, 8) = BangA
End Sub
 
Upvote 0
Nếu dữ liệu nhiều mà dùng code bài số 7 chắc phải đi pha cafe uống quá
Thử thêm với code này
PHP:
Sub FindText()
Dim BangA(), BangB(), I, J, Found, FoundFirst
With Sheet1
    BangA = .Range(.[a2], .[A1000000].End(3)).Resize(, 8).Value
End With
With Sheet2
    BangB = .Range(.[a2], .[C1000000].End(3)).Value
End With
For I = 1 To UBound(BangA)
    For J = 1 To UBound(BangB)
        If BangA(I, 5) Like BangB(J, 1) & "*" Then
            BangA(I, 7) = BangB(J, 2)
            BangA(I, 8) = BangB(J, 3)
        End If
    Next
Next
Sheet1.[a2].Resize(I - 1, 8) = BangA
End Sub
cả 2 cách của a QuangHai đều chạy tốt.cách 2 cho kết quả nhanh hơn nhiều ạh
e cảm ơn a. cơ mà cho e hỏi thêm có thể vận dụng dic cho bài toán này ko a? vì dữ liệu tương đối lớn
 
Upvote 0
cả 2 cách của a QuangHai đều chạy tốt.cách 2 cho kết quả nhanh hơn nhiều ạh
e cảm ơn a. cơ mà cho e hỏi thêm có thể vận dụng dic cho bài toán này ko a? vì dữ liệu tương đối lớn
Chắc là không thể dùng Dic được đâu, bài này Dic không phù hợp.
 
Upvote 0
Nếu bạn muốn thử với Dic thì bạn tham khảo Code sau:
Mã:
Sub LoaiXe()
    Dim BangA(), BangB()
    Dim Dic As Object
    Dim i As Long, L As Long, k As Long, Tmp As String
    With Sheet1
        BangA = .Range(.[a2], .[A1000000].End(3)).Resize(, 8).Value
    End With
    With Sheet2
        BangB = .Range(.[a2], .[C1000000].End(3)).Value
    End With
    Set Dic = CreateObject("Scripting.Dictionary")
    With Dic
        For i = 1 To UBound(BangB, 1)
            If Not .Exists(BangB(i, 1)) Then
                k = k + 1
                .Add BangB(i, 1), k
            End If
        Next
        For i = 1 To UBound(BangA, 1)
            For L = 1 To Len(BangA(i, 5))
                Tmp = Left(BangA(i, 5), L)
                If .Exists(Tmp) Then
                    BangA(i, 7) = BangB(.Item(Tmp), 2)
                    BangA(i, 8) = BangB(.Item(Tmp), 3)
                    Exit For
                End If
            Next
        Next
    End With
    Sheet1.[a2].Resize(i - 1, 8) = BangA
End Sub
 
Upvote 0
Nếu bạn muốn thử với Dic thì bạn tham khảo Code sau:
Mã:
Sub LoaiXe()
    Dim BangA(), BangB()
    Dim Dic As Object
    Dim i As Long, L As Long, k As Long, Tmp As String
    With Sheet1
        BangA = .Range(.[a2], .[A1000000].End(3)).Resize(, 8).Value
    End With
    With Sheet2
        BangB = .Range(.[a2], .[C1000000].End(3)).Value
    End With
    Set Dic = CreateObject("Scripting.Dictionary")
    With Dic
        For i = 1 To UBound(BangB, 1)
            If Not .Exists(BangB(i, 1)) Then
                k = k + 1
                .Add BangB(i, 1), k
            End If
        Next
        For i = 1 To UBound(BangA, 1)
            For L = 1 To Len(BangA(i, 5))
                Tmp = Left(BangA(i, 5), L)
                If .Exists(Tmp) Then
                    BangA(i, 7) = BangB(.Item(Tmp), 2)
                    BangA(i, 8) = BangB(.Item(Tmp), 3)
                    Exit For
                End If
            Next
        Next
    End With
    Sheet1.[a2].Resize(i - 1, 8) = BangA
End Sub
Không có dữ liệu lớn để thử nhưng cảm giác vẫn cho thấy là nếu dùng Dic sẽ cho tốc độ chậm hơn 2 mảng lồng, thêm nữa thấy nó rắc rối quá
 
Upvote 0
Không có dữ liệu lớn để thử nhưng cảm giác vẫn cho thấy là nếu dùng Dic sẽ cho tốc độ chậm hơn 2 mảng lồng, thêm nữa thấy nó rắc rối quá
Chiẻ là tham khảo thôi mà anh. Nhưng mà em nghĩ tốc độ cũng không đến nỗi nào bởi nó chỉ duyệt qua số phần tử trong 1 chuỗi rồi đối chiếu với Dic nếu thỏa thì thoát ngay.

2 mảng lồng mà cũng dùng Exit For thì tốc độ sẽ nhanh hơn nhiều anh nhỉ?
 
Upvote 0
Chiẻ là tham khảo thôi mà anh. Nhưng mà em nghĩ tốc độ cũng không đến nỗi nào bởi nó chỉ duyệt qua số phần tử trong 1 chuỗi rồi đối chiếu với Dic nếu thỏa thì thoát ngay.

2 mảng lồng mà cũng dùng Exit For thì tốc độ sẽ nhanh hơn nhiều anh nhỉ?
Sao dám Exit for, nếu sort bảng A trước thì mới có thể dùng Exit for
 
Upvote 0
Cái này chưa chắc bởi nếu mã xe giống nhau phần đầu mà sai phần sau thì toi.

Ví dụ:

LC3C - Airblade - Honda
LC3C1 - Lead - Honda
Nếu mã xe có dạng như ví dụ thì có thể sort bảng B theo thứ tự giảm dần rồi dùng vòng lặp. Khi đó mã LC3C1 sẽ xuất hiện trước LC3C, có thể exit for ở LC3C1.
 
Upvote 0
Nếu mã xe có dạng như ví dụ thì có thể sort bảng B theo thứ tự giảm dần rồi dùng vòng lặp. Khi đó mã LC3C1 sẽ xuất hiện trước LC3C, có thể exit for ở LC3C1.
Chuẩn rồi ạ, đó là hướng code áp dụng bài #11 + nhận xét #13 + đề cập tại #14

(Đây có phải anh Hậu mà dhn46 gặp tại sinh nhật lần 8 không ta?)
 
Upvote 0
Vâng, ấy là đoán vậy thôi anh chứ dữ liệu thất mình có biết mặt mũi nó như thế nào đâu. Cứ để chủ Topic thử sai thì lại hỏi --=0.
Dạ.. topic này e mượn tình huống từ 1 topic khác đã nêu ở #1 để làm bài học cho mình. Thực tế chưa gặp trường hợp này bao giờ và cũng ko biết dữ liệu thật mặt mũi thế nào ạh, hì
E cảm ơn mng nhiều
 
Upvote 0
Tôi đã đoán là bạn muốn học cho nên tôi mới bảo bạn chịu khó đi tìm 2 trong những thuật toán căn bản của lập trình: sort và tìm nhị phân.
 
Upvote 0

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

Back
Top Bottom