Как написать запрос SQL, чтобы проверить, является ли отношение «многие ко многим» в одной таблице подмножеством отношения «многие ко многим» в другой таблице? - PullRequest
3 голосов
/ 27 июля 2011

У меня есть несколько моделей следующим образом:

Product:
  id
  name
  price

Order:
  id
  user
  created

OrderProduct:
  order_id
  product_id

Promo:
  id
  discount

PromoProduct:
  promo_id
  product_id

Акция распространяется на заказ, если в заказе присутствуют все продукты в акции. Как написать SQL-запрос, чтобы узнать, какие рекламные акции применяются к заказу?

Ответы [ 5 ]

4 голосов
/ 27 июля 2011
SELECT  *
FROM    promo p
WHERE   id NOT IN
        (
        SELECT  pp.promo_id
        FROM    promoProduct pp
        WHERE   pp.product_id NOT IN
                (
                SELECT  product_id
                FROM    orderProduct op
                WHERE   op.order_id = $order
                )
        )

Обратите внимание, что это также вернет все рекламные акции с пустыми списками товаров («в этом ангаре нет самолета, на котором я не могу летать»). Если это проблема, вам нужно будет добавить дополнительную проверку на непустоту рекламных акций.

1 голос
/ 27 июля 2011

Используя подзапросы, вы можете делить и побеждать.

Создайте запрос, чтобы узнать, сколько товаров в каждой акции:

SELECT promo_id, COUNT(product_id) AS no_products
FROM PromoProduct
GROUP BY promo_id

Затем создайте еще один, чтобы узнать, сколько товаров для каждого заказа в акции:

SELECT OP.order_id, PP.promo_id, COUNT(OP.product_id) AS no_products
FROM OrderProduct OP
INNER JOIN PromoProduct PP ON OP.product_id = PP.product_id
GROUP BY OP.order_id, PP.promo_id

Тогда соедините их вместе:

SELECT OP.order_id, PP.promo_id
FROM OrderProduct OP
INNER JOIN PromoProduct PP ON OP.product_id = PP.product_id
INNER JOIN (SELECT promo_id, COUNT(product_id) AS no_products
FROM PromoProduct
GROUP BY promo_id) PC ON PP.promo_id = PC.promo_id AND COUNT(OP.product_id) = PC.no_products
GROUP BY OP.order_id, PP.promo_id

Это может потребовать небольшой доработки, но вы понимаете, в чем дело.

1 голос
/ 27 июля 2011

Это должно соответствовать вашему критерию, согласно которому все товары в акции должны быть частью заказа - из-за q1.ct = q2.ct. q1.ct дает вам количество продуктов на промо на заказ; q2.ct дает вам общее количество товаров на заказ.

Очевидно, что вы можете дополнительно присоединить это к таблицам Order и Promo, чтобы получить любую дополнительную информацию, которую вы хотите в своем наборе результатов.

SELECT q1.order_id, q1.promo_id FROM
( SELECT op.order_id, pp.promo_id, COUNT( op.product_id ) AS ct
FROM OrderProduct op INNER JOIN PromoProduct pp ON product_id
GROUP BY op.order_id, pp.promo_id ) q1

INNER JOIN

( SELECT pp.promo_id, COUNT( pp.product_id ) AS ct
FROM PromoProduct pp
GROUP BY pp.promo_id ) q2

ON q1.promo_id = q2.promo_id AND q1.ct = q2.ct
0 голосов
/ 27 июля 2011

Вы можете оставить присоединение продуктов данного промо к продуктам данного заказа, и если строка (-ы) какого-либо продукта заказа вернется в ноль, это будет означать, что заказ не соответствует требованиям этого промо, учитывая ваше определение того, что требуется для квалификации.для промо.

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

        select promoproducts.productid, orderproducts.productid
        from promoproducts
        left join orderproducts
        on promoproducts.productid = orderproducts.productid
        where promoid = 'x' and orderid = 'y'

РЕДАКТИРОВАТЬ2: игнорировать выше (см. Комментарий Quassnoi);Подход, который я предлагаю, должен быть выполнен как ЛЕВОЕ СОЕДИНЕНИЕ к встроенному представлению:

        select pp.productid as promoproduct, orderproduct
        from promoproducts pp
        left join 

          (
         select productid as orderproduct
           from orderproducts
           where orderid=1

         ) as op
         on pp.productid=op.orderproduct
          where promoid =1

РЕДАКТИРОВАТЬ3: вместо сравнения заказа с определенным промо (where promoid = x) его можно сравнить свсе текущие рекламные акции:

          ...  where promoid in (select promoid from promos where startdate ... expirydate ...) 
           -- find current promos

Реальное преимущество этого подхода с левым объединением состоит в том, что он показывает вам все рекламные акции, на которые распространяется заказ, а также все рекламные акции.он не соответствует критериям и какие продукты должны быть добавлены в заказ, чтобы получить право на промо .

0 голосов
/ 27 июля 2011
SELECT *
FROM 'order' o
INNER JOIN orderproduct op ON op.order_id = o.order_id
INNER JOIN PromoProduct p ON p.product_id = op.product_id
WHERE o.order_id = ?

Попробуйте это .. Хотя я думаю, вы должны переименовать таблицу заказов, так как это ключевое слово в MySQL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...