LEFT JOIN в MS Access с несколькими критериями и без дубликатов - PullRequest
0 голосов
/ 11 января 2019

Могу ли я попросить вас помочь в решении приведенной ниже задачи, используя оператор левого соединения SQL в Microsoft Access? Спасибо!

Цель (см. Также таблицы ниже):

  1. Количество записей в таблице результатов (A + B) должно быть таким же, как и в таблице A
  2. Значение B1, сопоставленное из таблицы B в таблицу A, должно быть ближайшим значением, меньшим, чем значение A1 соответствующего идентификатора в таблице A
  3. Если все значения B1 для одного и того же идентификатора в таблице B больше, чем значениеA1 соответствующего идентификатора в таблице A, используйте самое низкое значение B1 в таблице B

Таблица A (Входные данные)

Id  ValueA1
A   10
B   20
C   30

Таблица B (Таблица конфигурации)

id  ValueB1
A   20
A   30
A   40
B   15
B   25
B   35
C   18
C   28
C   38

Таблица A + B (ожидаемый результат)

id  ValueA1 ValueB1
A   10      20
B   20      15
C   30      28

Ответы [ 2 ]

0 голосов
/ 11 января 2019

Вот рабочий пример в MS SQL Server:

Select 'A' as Id, 10 as ValueA1 into #A
Insert into #A (Id,ValueA1 ) VALUES ('B', 20), ('C', 30)

Select 'A' as Id, 20 as ValueB1 into #B
Insert into #B (Id,ValueB1 ) VALUES ('A', 30), ('A', 40)
Insert into #B (Id,ValueB1 ) VALUES ('B', 15), ('B', 25), ('B', 35)
Insert into #B (Id,ValueB1 ) VALUES ('C', 18), ('C', 28), ('C', 38)

SELECT #A.Id, #A.ValueA1, coalesce(Max(Minors.ValueB1), Min(Majors.ValueB1))
FROM #A 
      LEFT JOIN (
                  SELECT #A.Id, #A.ValueA1, Max(#B.ValueB1) ValueB1   
                    FROM #A LEFT JOIN #B ON #A.Id = #B.Id   
                   WHERE #B.ValueB1 < #A.ValueA1 GROUP BY #A.Id, #A.ValueA1
                 ) Minors ON Minors.Id = #A.Id
      LEFT JOIN (
                   SELECT #A.Id, #A.ValueA1, Min(#B.ValueB1) ValueB1  
                     FROM #A LEFT JOIN #B ON #A.Id = #B.Id   
                    WHERE #B.ValueB1 >= #A.ValueA1 GROUP BY #A.Id, #A.ValueA1
                 ) Majors ON Majors.Id = #A.Id
GROUP BY #A.Id, #A.ValueA1 

DROP TABLE #A
DROP TABLE #B

Я думаю, что с небольшими изменениями вы можете адаптировать это к MS Access, например, функция объединения, которая сохраняет первый ненулевой элемент, может быть заменена на NZ (field1, field2)

Вот версия, совместимая с Access:

SELECT TableA.Id, TableA.ValueA1, Nz(Max(Minors.ValueB1),Min(Majors.ValueB1)) 
AS ValueB1
FROM 
   (SELECT TableA.Id, TableA.ValueA1, Max(TableB.ValueB1) AS ValueB1
    FROM TableA LEFT JOIN TableB ON TableA.Id = TableB.Id
    WHERE TableB.ValueB1 < TableA.ValueA1
    GROUP BY TableA.Id, TableA.ValueA1
   ) AS Minors 
RIGHT JOIN 
   (
     (SELECT TableA.Id, TableA.ValueA1, Min(TableB.ValueB1) AS ValueB1
      FROM TableA LEFT JOIN TableB ON TableA.Id = TableB.Id
      WHERE TableB.ValueB1 >= TableA.ValueA1
      GROUP BY TableA.Id, TableA.ValueA1
     ) AS Majors 
     RIGHT JOIN TableA ON Majors.ValueA1 = TableA.ValueA1
   ) 
ON Minors.ValueA1 = TableA.ValueA1
GROUP BY TableA.Id, TableA.ValueA1;
0 голосов
/ 11 января 2019

Только SQL, не VBA решение, которое я сразу вижу, использует агрегатные функции домена.

SELECT TableA.ID, TableA.ValueA1, Nz(DMax("ValueB1","TableB","ID='" & [ID] & "' 
        AND ValueB1<" & [ValueA1]),DMin("ValueB1","TableB","ID='" & [ID] & "'")) AS ValueB1
        FROM TableA;

Если это работает медленно с очень большим набором данных, пользовательская функция VBA может быть лучше.

...