MYSQL сопоставить несколько строк в одной таблице с несколькими идентификаторами - PullRequest
0 голосов
/ 19 января 2019

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

product_ids в моем заказе: 10,20,30,40,50

SELECT * 
  FROM vendors 
 WHERE product_id IN (10,20,30,40,50)

дает мне всех поставщиков, у которых есть хотя бы 1 из продуктов

vendor_id | product_id 
1234          10
1234          20
1234          30
1234          40
1235          10
1235          40
1236          20
1236          30
1236          40
1237          50
9876          10
9876          20
9876          30
9876          40
9877          10
9877          40
9877          50
9878          10
9878          20
9878          30
9878          50

После нескольких сумасшедших подзапросов (слишком длинных, чтобы публиковать здесь) я могу добраться до таблицы, в которой показано, чего не хватает каждому поставщику, и моя мысль состоит в том, чтобы затем присоединиться к этой таблице на основе этих недостающих элементов и затем показать продавцам, которые иметь изысканный список.

результат должен выглядеть следующим образом (разделены запятыми или нет, значения не имеют, просто легче читать)

vender_1 | product_id   |   missing_product_id   | vendor_2
1234       10,20,30,40          50                 9876,9878
1235        10,40            20,30,50              9878
1236        20,30,40           10,50               9877
1237        50              10,20,30,40            1234

или

vender_1 | product_id   |   missing_product_id   | vendor_2
1234           10          
1234           20              
1234           30           
1234           40                                 
1234                              50                 9876
1234                              50                 9878

и т.д ...

1 Ответ

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

Вы хотите group by и having:

SELECT v.vendor_id
FROM vendors v  -- Shouldn't this be called vendorProducts ?
WHERE v.product_id IN (10, 20, 30, 40, 50) 
GROUP BY v.vendor_id
HAVING COUNT(DISTINCT v.product_id) = 5;

Для нескольких поставщиков вы можете расширить вышеуказанную логику. Идея состоит в том, чтобы объединить таблицу, чтобы получить список пар поставщиков и всех продуктов, которые они вместе имеют. Затем выполните ту же логику, что и выше:

SELECT v.vendor_id1, v.vendor_id2
FROM (SELECT DISTINCT v1.vendor_id as vendor_id1, v2.vendor_id as vendor_id2,
             (CASE WHEN n.n = 1 THEN v1.product_id ELSE v2.product_id END) as product_id
      FROM vendors v1 JOIN
           vendors v2
           ON v1.product_id <> v2.product_id AND
              v1.vendor_id < v2.vendor_id CROSS JOIN
           (SELECT 1 as n UNION ALL SELECT 2) n
      UNION ALL
      -- Then include the singletons, just in case
      SELECT v.vendor_id, NULL, v.product_id
      FROM vendors v
     ) v
WHERE v.product_id IN (10, 20, 30, 40, 50) 
GROUP BY v.vendor_id1, v.vendor_id2
HAVING COUNT(DISTINCT v.product_id) = 5;

На самом деле вы можете выполнить фильтрацию товара в подзапросе, чтобы сделать запрос более эффективным. Что касается того, чтобы сделать это более общим, «5» - это количество предметов. Я не знаю, как создается окончательный запрос.

РЕДАКТИРОВАТЬ II:

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

select v1.*, v2.*
from (select vendor_id,
             max(product_id = 1) as p1,
             max(product_id = 2) as p2,
             max(product_id = 3) as p3,
             max(product_id = 4) as p4,
             max(product_id = 5) as p5,
      from vendors
      where product_id in (1, 2, 3, 4, 5)
      group by vendor_id
     ) v1 join
     (select vendor_id,
             max(product_id = 1) as p1,
             max(product_id = 2) as p2,
             max(product_id = 3) as p3,
             max(product_id = 4) as p4,
             max(product_id = 5) as p5,
      from vendors
      where product_id in (1, 2, 3, 4, 5)
      group by vendor_id
     ) v2
     on (v1.p1 + v2.p1) > 0 and
        (v1.p2 + v2.p2) > 0 and
        (v1.p3 + v2.p3) > 0 and
        (v1.p4 + v2.p4) > 0 and
        (v1.p5 + v2.p5) > 0;

Примечание. Если все продукты принадлежат одному поставщику, он будет отображаться в паре со всеми другими поставщиками.

...