MySQL: лучший способ поиска строк, где связанный список соответствует заданному списку - PullRequest
0 голосов
/ 21 октября 2019

Я построил оператор SQL, объясненный здесь:

У меня есть таблица Account, например:

|-- Account ---|
| ID | comment |
| 1  | blabla1 |
| 2  | blabla2 |
| 3  | blabla3 |

У меня есть таблица Customer, например:

|---- Customer ----|
|   ID   | comment | 
| 111111 | blabla1 |
| 222222 | blabla2 |
| 333333 | blabla3 |

У меня есть отношение Customer_To_Account, например:

|----- Customer_To_Account -----|
| ID | account_id | customer_id |
| 1  |     1      |   111111    |
| 2  |     1      |   222222    |
| 3  |     1      |   333333    |
| 4  |     2      |   111111    |
| 5  |     2      |   222222    |
| 6  |     3      |   111111    |

Я хочу найти все учетные записи, которые назначены клиентам в данном списке, например (111111, 222222). Возвращенные счета ДОЛЖНЫ содержать хотя бы одного из указанных клиентов, и они НЕ ДОЛЖНЫ содержать клиента, которого НЕ в данном списке.

Ожидаемый результат:

  • Для списка (111111) результатом должна быть только учетная запись 3, так как учетная запись 3 содержит клиента 111111 и НЕ содержит других клиентов. Например, счета 1 и 2 содержат клиентов 222222, которых нет в списке (111111) ->, следовательно, нет в результате.

  • Для списка (111111, 222222) результат должен бытьсчета 2 и 3, так как они содержат по крайней мере одного из указанных клиентов (111111, 222222), а НЕ содержат других клиентов. Учетная запись 1 содержит клиента 333333, которого нет в списке (111111, 222222) ->, поэтому нет в результате.

Мой запрос:

    SELECT * FROM Account WHERE ID IN (
        SELECT distinct account_id FROM Customer_To_Account 
        WHERE customer_id IN("111111", "222222")) -- all accounts, that have one of these customers assigned
      AND ID NOT IN (
        SELECT distinct account_id FROM Customer_To_Account 
        WHERE customer_id NOT IN("111111", "222222")) -- all accounts, that have other customers assigned than the given customers

Возвращает правильный результат, но не имеет очень плохой производительности запроса, так как выбирает все идентификаторы учетных записей, у которых есть хотя бы один клиент, которого нет в данном списке.

У кого-нибудь есть лучшая идея / запрос для такого варианта использования?

Большое спасибо!

heiwil

1 Ответ

2 голосов
/ 21 октября 2019

Как насчет использования агрегации?

select account_id
from customer_to_account ca
group by account_id
having sum( customer_id in ( . . . ) ) > 0 and  -- at least 1
       sum( customer_id not in ( . . . ) ) = 0  -- no others
...