В MS Access с использованием VBA: я хочу передавать записи с временной сложностью менее N^2

У меня есть одна таблица заказов с 5000 заказами. И у меня есть одна таблица клиентов с 5000 клиентами.

Некоторые заказы имеют пустые значения в поле «CustomerID», которые я хочу исправить с помощью алгоритма.

В настоящее время для каждого нулевого значения в поле «CustomersID» в таблице «Заказы» алгоритм рассматривает три поля из таблицы «Заказы» (1. имя, 2. страна, 3. кластер) и циклически перебирает таблицу клиентов, чтобы найти совпадение с идентичными полями в таблице «Заказы». таблица клиентов (1. имя, 2. страна, 3. кластер). Если есть совпадение, я добавляю «CustomerID» в таблицу заказов (заменяя нулевое значение в «CustomersID», в противном случае я сначала создаю новую запись о клиенте в таблице «Клиенты», а затем добавляю «CustomerID» в таблицу «Заказы»).

Проблема в медленном алгоритме. При циклическом просмотре всех полей с нулевыми значениями в таблице заказов (в худшем случае 5000) и попытке для каждого поля найти совпадение в таблице «Клиенты» (в худшем случае 5000, если совпадений нет), общая временная сложность становится квадратичной. Н^2.

Заранее спасибо! Прикреплен мой код. Первый метод открывает набор записей таблицы заказов (rss). Затем он просматривает набор записей заказов, чтобы найти нулевые значения. Второй метод открывает набор записей для таблицы «Клиенты» (первый). Затем он выполняет поиск совпадений в полях, общих из таблицы заказов (1. имя 2. страна 3. кластер).

Public Sub TransferNullValues() 'hard coded parameters are "Orders", "Customers"
    Set coll = New Collection
    coll.Add "CustomerID"
    coll.Add "End_customer"
    coll.Add "End_customer_country"
    coll.Add "Cluster"
    
    Dim sqlStr As String
    sqlStr = "SELECT " & buildSql(coll) & " FROM Orders where Orders.CustomerID is null;"
    coll.Remove (1) 'remove customer id
    
    Dim rss As DAO.Recordset
    Set rss = Basic.getRs(sqlStr)
    
    Do While Not rss.EOF
        Dim locals As Collection
        Set locals = New Collection
        
        Dim v As Variant
        For Each v In coll
            locals.Add (rss(v).value)
        Next
        
        Dim id As Integer
        id = getCustID(locals)
        
        rss.Edit
        rss("CustomerID").value = id
        rss.Update
            
        rss.MoveNext
    Loop
    
    rss.Close
    Set rss = Nothing
    
End Sub

Private Function getCustID(locals As Collection) As Integer
    Dim sqlStr As String
    sqlStr = "SELECT * FROM CUSTOMERS;"
    Dim rst As DAO.Recordset
    Set rst = Basic.getRs(sqlStr)
    Dim trgt As Collection
    
    
    Do While Not rst.EOF
        Set trgt = New Collection
        
        Dim v As Variant
        For Each v In coll
            trgt.Add (rst(v).value)
        Next
        
        Dim allExists As Boolean
        allExists = True
        
        For Each v In locals
            If Not Basic.Exists(trgt, v) Then
                allExists = False
                Exit For
            End If
        Next
        
        If allExists Then
            getCustID = rst("CustomerID").value
            'Debug.Print "customer exists in customers table"
            Exit Function
        End If
    
        rst.MoveNext
        
    Loop
    
    rst.AddNew
    Dim count As Integer
    count = 1
    For Each v In locals
        rst.Fields(count).value = v
        count = count + 1
    Next
    
    Dim id As Integer
    id = rst("CustomerID")
    
    rst.Update
        rst.Close
    Set rst = Nothing
    
    getCustID = id
End Function

Я думал о том, как уменьшить временную сложность, но не нашел решения.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
75
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете сделать это более эффективно с помощью запроса UPDATE:

UPDATE Orders
    INNER JOIN Customers ON
        (Nz(Orders.name)    = Nz(Customers.name)) AND
        (Nz(Orders.country) = Nz(Customers.country)) AND
        (Nz(Orders.cluster) = Nz(Customers.cluster))
SET Orders.CustomerId = Customers.CustomerId
WHERE Orders.CustomerId Is Null

JOIN будет более эффективным, чем O(n2). Я предполагаю, что это O(n·log(n)).

Как отметили комментаторы, вы должны использовать функцию Nz() для преобразования возможных значений Null в ненулевые значения (пустую строку или число 0 и т. д.), чтобы сравнения работали правильно.

Это гораздо лучший способ сделать это! Однако мне также нужно принять во внимание ноль. Так, например, строка в таблице «Заказы», ​​где «имя (= null), страна (= Китай), кластер (= null)», должна присоединиться к строке в таблице «Клиенты», где «country (= null), страна (= Китай), кластер (=нуль)"

Martin 05.06.2024 12:23

Поскольку вы не можете присоединиться к NULL, вы можете использовать NZ для замены NULL текстом замены в операторе соединения, например. г. NZ(Orders.cluster, «пустой») = NZ(Customers.cluster, «пусто»)

Zen 05.06.2024 14:56

Другие вопросы по теме