【问题标题】:MYSQL: SELECT sum of field values while also SELECTing unique values?MYSQL:选择字段值的总和同时还选择唯一值?
【发布时间】:2013-06-10 16:59:37
【问题描述】:

我想计算每件商品的购买次数,同时根据查看内容的人,显示用户是否购买了内容。因为项目和购买的数量可能会变得很大,所以我不愿意投入更多的 JOINs 来实现这一点,因为那样看起来效果不佳。

基本上,我希望在以下查询中的某处有一个did_i_buy 字段,而不添加另一个JOIN。这可能吗?假设user_name=tom:

SELECT Items.item_id, item_name, COUNT(purchase_status='bought') as number_bought 
FROM Purchases
JOIN Items ON Purchases.item_id=Items.item_id
GROUP BY Items.item_id

这是我的数据库结构:

Table Items
item_id item_name
1           item_1
2           item_2
3           item_3

Table Purchases
item_id  purchase_status    user_name
1           bought          joe
2           bought          joe
1           bought          tom
1           bought          bill

tom 的期望结果

item_id item_name number_bought did_i_buy
1        item_1         3        yes
2        item_2         1        no

【问题讨论】:

  • 为什么不将“times_purchased”反规范化并为用户的购买状态做一次连接?
  • @landons,谢谢,我对 MYSQL 不是很有经验,因此我不确定你的意思。你能用一些代码解释一下吗?
  • 你不需要从 MySql 获取 did_i_buy。这是对资源的浪费。只需检查您的 PHP(或其他语言)代码中的 count > 0。

标签: mysql sql join


【解决方案1】:

如果我理解正确,did_i_buy 栏的意思是“汤姆买了吗”。你可以这样做:

SELECT
  Items.item_id,
  item_name,
  COUNT(CASE WHEN purchase_status='bought' THEN 1 END) as number_bought,
  MAX(CASE WHEN purchase_status='bought' AND user_name='Tom' THEN 'yes' ELSE 'no' END) AS did_i_buy
FROM Purchases
JOIN Items ON Purchases.item_id=Items.item_id
GROUP BY Items.item_id

或者(一个 CASE 声明,见下面的 cmets)

SELECT
  Items.item_id,
  item_name,
  COUNT(purchase_status='bought') as number_bought,
  MAX(CASE WHEN user_name='Tom' THEN 'yes' ELSE 'no' END) AS did_i_buy
FROM Purchases
JOIN Items ON Purchases.item_id=Items.item_id
WHERE purchase_status='bought'
GROUP BY Items.item_id

还有一个调整:因为WHERE 子句,COUNT 只会看到purchase_status='bought' 所在的行,所以检查状态的表达式可以省略(唯一的变化是在第 4 行):

SELECT
  Items.item_id,
  item_name,
  COUNT(*) as number_bought,
  MAX(CASE WHEN user_name='Tom' THEN 'yes' ELSE 'no' END) AS did_i_buy
FROM Purchases
JOIN Items ON Purchases.item_id=Items.item_id
WHERE purchase_status='bought'
GROUP BY Items.item_id

【讨论】:

  • 如果您使用 JOIN,您将更改 number_bought 计数,因为它将被过滤到仅与连接匹配的行。所以这是正常的做法。
  • 这是一个很难回答的问题,但在这种情况下,我认为最好避免使用 JOIN,因为 did_i_buy 是 number_bought 的子集,因此您已经必须扫描所有行purchase_status='bought'。您可能可以通过添加 WHERE purchase_status='bought' 来加快速度,因为您不会针对非“购买”行执行两个 CASE 命令。
  • 感谢@EdGibbs,我将您推定的更好的代码添加到您的答案中。这看起来对吗?如果是这样,我会接受你的回答。
  • 谢谢蒂姆。您不需要COUNT(purchase_status='bought') as number_bought 中的表达式,因为WHERE 已经删除了purchase_status <> 'bought' 所在的行。因此,您只需使用COUNT(*) 即可保存计算。我会更新的。
  • 好的,现在更新,感谢您的反馈和编辑 :) BTW - 好问题!
【解决方案2】:

你必须(我认为)使用子查询。每个对计数的请求都是一个单独的查询,因此没有办法对此进行优化(除非将其全部压缩到一个带有子查询的查询中)。商品中的横向数据与购买中的纵向数据之间没有特殊关系。

这是一个为用户计算交易的示例查询:

SELECT user_id,(SELECT count(*) FROM transactions WHERE buyer_id=u.user_id) as count FROM users as u

我将此查询与其他 JOIN 类型的类似查询进行了比较。结果:这个是 0.0005,而 Ed Gibbs 是 0.0018。但是,如果需要对 number_bought (ORDER BY count DESC) 进行排序,则后者的查询速度要快得多。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-22
    • 1970-01-01
    • 1970-01-01
    • 2015-01-14
    • 2013-10-31
    • 2012-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多