[英]MySQL Query Customers Who Have Not Bought
Background:背景:
We are setting up a promotions system to give away free products to registered customers.我们正在建立一个促销系统,向注册客户赠送免费产品。 We're trying to design a database which is flexible enough to handle multiple products, and giveaways.我们正在尝试设计一个足够灵活的数据库来处理多种产品和赠品。 The requirements are that products may be given away on a drip basis on a first come basis to qualified customers.要求是产品可以按先到先到的方式分发给合格的客户。
Example:例子:
Apple wants to give away 1000 ipads in March.苹果希望在 3 月份赠送 1000 台 ipad。
They want to give away maximum of 1 per hour.他们希望每小时最多赠送 1 个。
They want to give it to customers who are in California or New York.他们想把它提供给在加利福尼亚或纽约的客户。
They want to limit how many free ipads a customer can get (limit 1 per 15 days).他们想限制客户可以获得的免费 ipad 数量(每 15 天限制 1 个)。
Data Structure:数据结构:
Products - 1 entry per unique product.产品- 每个独特产品 1 个条目。 eg Apple iPad例如苹果 iPad
ProductGiveAways产品赠品
Problem:问题:
With the above structure we are able to do a query against our customers table and find out which are qualified for the promotion.通过上述结构,我们可以对客户表进行查询,并找出哪些符合促销条件。
What I cannot figure out is the best way to:我无法弄清楚的是最好的方法是:
In other words:换句话说:
Say amazon.com wants to show me DVDs which I have not already bought.假设 amazon.com 想要向我展示我尚未购买的 DVD。 What is the proper way to query that?查询的正确方法是什么?
Is the right approach to first get a list of previously bought products and then Query with a NOT clause?首先获取以前购买的产品列表,然后使用 NOT 子句进行查询是正确的方法吗?
I'm assuming you'll have a table for what has been given away.我假设你会有一张桌子来存放已经赠送的东西。 In this table I would include a column for recipient id which can map back to the customer table.在此表中,我将包含一个收件人 ID 列,该列可以映射回客户表。 You can then create queries to find eligible recipients by searching for customers who have not met disqualifying conditions.然后,您可以通过搜索不符合取消资格条件的客户来创建查询以查找符合条件的收件人。
select customerid
from customer
where customerid not in (
select recipientid
from givenaway
where ..... and ....
)
Because there's not a definitive data structure defined, I'm going to use the following which you can tailor to whatever data structure you have designed yourself:因为没有定义明确的数据结构,我将使用以下内容,您可以根据自己设计的任何数据结构进行定制:
INTEGER
( IDENTITY
and PRIMARY KEY
) ProductId - INTEGER
( IDENTITY
和PRIMARY KEY
)VARCHAR
产品名称 - VARCHAR
INTEGER
( IDENTITY
and PRIMARY KEY
) StateId - INTEGER
( IDENTITY
和PRIMARY KEY
)VARCHAR
状态名称 - VARCHAR
INTEGER
( IDENTITY
and PRIMARY KEY
) CustomerId - INTEGER
( IDENTITY
和PRIMARY KEY
)INTEGER
( FOREIGN KEY
) StateId - INTEGER
(外FOREIGN KEY
)INTEGER
( IDENTITY
and PRIMARY KEY
) PromotionId - INTEGER
( IDENTITY
和PRIMARY KEY
)INTEGER
( FOREIGN KEY
) ProductId - INTEGER
(外FOREIGN KEY
)INTEGER
数量 - INTEGER
DATETIME
开始日期 - 日期DATETIME
DATETIME
结束日期 - 日期DATETIME
INTEGER
PurchaseLimitDays - INTEGER
INTEGER
( FOREIGN KEY
)促销INTEGER
- INTEGER
(外FOREIGN KEY
)INTEGER
( FOREIGN KEY
) StateId - INTEGER
(外FOREIGN KEY
)So in answer to your questions:所以回答你的问题:
Query customers in California or New York (is this a good use case for a join and another table?)查询加利福尼亚或纽约的客户(这是一个连接和另一个表的好用例吗?)
Personally I would join to a centralized state table ( PromotionState
) in my above example, I'm sure there's a better way but you could do a condition such as:就我个人而言,我会在上面的示例中加入集中状态表 ( PromotionState
),我确定有更好的方法,但您可以执行以下条件:
WHERE
(SELECT COUNT * FROM PromotionState x WHERE x.PromotionId = p.PromotionId) = 0
OR NOT(ps.PromotionId IS NULL)
Alternatively you could do a GROUP BY
and HAVING
, using all the other columns as the items to GROUP BY
and something like HAVING COUNT * = 0
OR HAVING SUM CASE WHEN (Conditions met) THEN 1 ELSE 0 END = 0
或者,您可以执行GROUP BY
和HAVING
,使用所有其他列作为GROUP BY
的项目,以及类似HAVING COUNT * = 0
或HAVING SUM CASE WHEN (Conditions met) THEN 1 ELSE 0 END = 0
When a customer logs in to see what free items are not available to him, how can I exclude the Apple iPad if the customer has already gotten this freebie?当客户登录查看哪些免费商品不提供给他时,如果客户已经获得此免费赠品,我如何排除 Apple iPad?
Say amazon.com wants to show me DVDs which I have not already bought.假设 amazon.com 想要向我展示我尚未购买的 DVD。 What is the proper way to query that?查询的正确方法是什么?
As I've said you could use GROUP BY
and HAVING
to determine whether an item has been previously "won" by either using COUNT
or SUM
正如我所说,您可以使用GROUP BY
和HAVING
来确定以前是否通过使用COUNT
或SUM
来“赢得”某个项目
Is the right approach to first get a list of previously bought products and then Query with a NOT clause?首先获取以前购买的产品列表,然后使用 NOT 子句进行查询是正确的方法吗?
There are probably better ways, sub queries can get very heavy and sluggish, I'd recommend trying some of the above techniques and then using a profiler to hopefully make it more efficient.可能有更好的方法,子查询可能会变得非常繁重和缓慢,我建议您尝试上述一些技术,然后使用分析器来提高效率。
First, when you set the CustomerState
to California,NewYork
you are violating the First Normal Form
of database design.首先,当您将CustomerState
设置为California,NewYork
您违反了数据库设计的First Normal Form
。
So let's reorganize your domain model.因此,让我们重新组织您的域模型。
State - 1 Entry per unique state ...状态- 每个独特状态 1 个条目......
Customer - 1 Entry per unique customer StateId: (California|NewYork|...) ...客户- 每个唯一客户 StateId 1 个条目:(加利福尼亚|纽约|...)...
Product - 1 Entry per unique product ...产品- 每个独特产品 1 个条目...
ProductGiveAways - Many entries per product ProductID Quantity StartDate End Date PurchaseLimitDays ... ProductGiveAways - 每个产品的多个条目 ProductID Quantity StartDate End Date PurchaseLimitDays ...
ProductGiveAways_State ProductGiveAwaysId StateId ... ProductGiveAways_State ProductGiveAwaysId STATEID ...
Customer_Product - 1 Entry per bought product by customer CustomerId ProductId PurchaseDate ... Customer_Product - 每个客户购买的产品有 1 个条目 CustomerId ProductId PurchaseDate ...
When you want to query custoners in California or New York, all you have to do now is :当您想查询加利福尼亚或纽约的客户时,您现在要做的就是:
// This is just an example, you have to change the 'California', 'New York' with their ids
SELECT * FROM Customer WHERE StateId IN ('California', 'New York')
When a customer logs in to see what free items are available to him :当客户登录以查看他可以使用哪些免费商品时:
// It's not an accurate sql, just an example
SELECT Product.*
FROM Product
JOIN ProductGiveAways ON ProductId
JOIN ProductGiveAways_State ON ProductGiveAwaysId
WHERE ProductId NOT IN (
SELECT ProductId FROM Customer_Product JOIN ProductGiveAways ON ProductId
WHERE CustomerId = /* the customer id */
AND ( TO_DAYS(now()) - TO_DAYS(PurchaseDate) ) < PurchaseLimitDays
)
AND StateId = /* customer StateId */
AND StartDate < now() < End Date // Elligible ProductGiveAways
For Laravel We Use Something Like this, i hope you can relate to this query or you can use online laravel query converter for using it in mysql ( orator )对于 Laravel 我们使用类似这样的东西,我希望您可以与此查询相关联,或者您可以使用在线 Laravel 查询转换器在 mysql ( orator ) 中使用它
$user_id = auth()->user()->id;
Product::where('status', 'active')
->whereNotIn('id', function($query) use ($user_id) {
$query->select('product_id')->from(new OrderProduct->getTable())
->where('user_id', $user_id)->where('status', 'delivered');
}); });
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.