[英]How do I write a SQL query to check if a many-to-many relationship on one table is a subset of a many-to-many relationship on another table?
I have some models as follows: 我有一些模型如下:
Product:
id
name
price
Order:
id
user
created
OrderProduct:
order_id
product_id
Promo:
id
discount
PromoProduct:
promo_id
product_id
A promotion applies to an order if all products in the promotion are present in the order. 如果促销中的所有产品都存在于订单中,则促销适用于订单。 How do I write a SQL query to find out what promotions apply to an order?
如何编写SQL查询以查找适用于订单的促销活动?
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
)
)
Note that this will also return all promotions with empty product lists ("there ain't no plane in this hangar that I can't fly"). 请注意,这也会返回所有带有空产品列表的促销活动(“这个机库中没有我无法飞行的飞机”)。 If that's a problem, you will need to throw in an additional check for non-emptiness of the promotions.
如果这是一个问题,您需要额外检查促销的非空虚。
This should fulfil your criterion that all the products in the promo need to be part of the order - because of the q1.ct = q2.ct
. 这应该符合您的标准,即促销中的所有产品都需要成为订单的一部分 - 因为
q1.ct = q2.ct
q1.ct
gives you a count of products per promo per order; q1.ct
为您提供每个订单每个促销的产品数量; q2.ct
gives you a total count of products per order. q2.ct
为您提供每个订单的产品总数。
Obviously you can further join this to the Order and Promo tables to get whatever additional information you want in your result set. 显然,您可以进一步将其加入订单和促销表,以获得您在结果集中所需的任何其他信息。
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
Using subqueries you can divide and conquer. 使用子查询可以分而治之。
Create a query to find how many products are in each promo: 创建一个查询以查找每个促销中有多少产品:
SELECT promo_id, COUNT(product_id) AS no_products
FROM PromoProduct
GROUP BY promo_id
Then create another to find how many products for each order are in a promo: 然后创建另一个以查找促销中每个订单的产品数量:
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
Then join them together: 然后加入他们:
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
That may need a little tweaking but you get the point. 这可能需要一些调整,但你明白了。
You could left join a given promo's products to a given order's products, and if any orderproducts row(s) came back null it would mean that the order did not qualify for that promo, given your definition of what it takes to qualify for a promo. 您可以将给定促销产品加入给定订单的产品,如果任何订单产品行返回null,则意味着该订单不符合该促销的条件,因为您定义了获得促销资格所需的条件。
EDIT: 编辑:
select promoproducts.productid, orderproducts.productid
from promoproducts
left join orderproducts
on promoproducts.productid = orderproducts.productid
where promoid = 'x' and orderid = 'y'
EDIT2: ignore above (see Quassnoi's comment); EDIT2:忽略上面(见Quassnoi的评论); the approach I'm suggesting needs to be done as a LEFT JOIN to an inline view:
我建议的方法需要作为内联视图的LEFT JOIN来完成:
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
EDIT3: instead of comparing the order to a specific promo ( where promoid = x
), it could be compared against all current promos: EDIT3:不是将订单与特定促销(
where promoid = x
)进行比较,而是将其与所有当前促销进行比较:
... where promoid in (select promoid from promos where startdate ... expirydate ...)
-- find current promos
The real-world advantage to this left-join approach is that it shows you all of the promos the order qualifies for as well as all of the promos it does not qualify for and which product(s) would have to be added to the order to qualify for a promo . 这种左连接方法的真实优势在于它向您显示订单所符合的所有促销,以及它不符合条件的所有促销以及必须将哪些产品添加到订单中有资格获得促销 。
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 = ?
Try that.. Though I think you should rename the order table, as it is a keyword in MySQL. 试试..虽然我认为你应该重命名订单表,因为它是MySQL中的关键字。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.