COIST的DISTINCT ID不在子查询中?

时间:2015-10-26 09:23:16

标签: mysql

好的,我试图计算一个月内购买东西的用户,但是在之前几个月的任何一天都没有买过东西(比如,确定有多少新用户是每个月都有),所以这就是我有点想做的事情,但它显然不起作用:

SELECT COUNT(DISTINCT user_id NOT IN (
    SELECT user_id
    FROM payment
    WHERE amount > 0
    AND MONTH(payment_date) < "10"
    GROUP BY user_id
) AS new_users_count
FROM payment
WHERE amount > 0
AND MONTH(payment_date) >= "10"

如果我使用&#34; DISTINCT&#34;它返回0计数。

如果我把它拿出来,它会返回所有新老用户。

另外,在COUNT()中使用子查询需要一段时间来处理。

任何方式都可以使用SUM(IF ...)来完成?还是其他更优化的方式?

我到处寻找一个想法/解决方案,只是无法弄清楚。

4 个答案:

答案 0 :(得分:0)

将标准放在WHERE子句中。使用curlcurl -v -X COPY http://localhost:8080/method

NOT EXISTS

以下是条件聚合的替代方法:

NOT IN

答案 1 :(得分:0)

使用NOT EXISTS验证前一个月内同一用户不存在付款。

SELECT COUNT(DISTINCT tm.USERID)
FROM payment tm
WHERE tm.amount > 0
AND MONTH(tm.payment_date) >= "10"
AND NOT EXISTS
  ( SELECT 'x' 
    FROM payment lm
    WHERE lm.amount > 0
    AND MONTH(lm.payment_date) < "10"
    AND lm.user_id = tm.user_id
  )

PS:请注意,此查询一旦成为2016年将不再有效!以下是对此的修复。它交叉加入计算以获得该月的第一天。该值(DATEPIVOT)用于在当天或之前获得付款。为了计算,我使用了answer by Aleroot

这种表示法的另一个优点是,MySQL应该能够更好地利用payment.payment_date上的任何索引,因此当您的数据变大时,此查询将受到性能下降的影响。

SELECT COUNT(DISTINCT tm.USERID)
FROM payment tm
CROSS JOIN 
    (SELECT 
       DATE_SUB(CURRENT_DATE, INTERVAL DAYOFMONTH(CURRENT_DATE)-1 DAY) as DATEPIVOT) d
WHERE tm.amount > 0
AND tm.payment_date >= d.DATEPIVOT
AND NOT EXISTS
  ( SELECT 'x' 
    FROM payment lm
    WHERE lm.amount > 0
    AND lm.payment_date < d.DATEPIVOT
    AND lm.user_id = tm.user_id
  )

答案 2 :(得分:0)

COUNT(DISTINCT user_id NOT IN (..something..)

被理解为

COUNT(DISTINCT (user_id NOT IN (..something..))

NOT IN是一个布尔运算符,返回true / false(= 1/0)

COUNT()中的条件没有意义 - 您可能希望在WHERE子句中执行此操作。或者您可以使用SUM()GROUP BY

但是根本不使用子查询通常会更好(MySQL 5.6+可以很好地处理子查询,但是你的是#34;依赖&#34;一个)。这样的事情应该有效:

SELECT COUNT(DISTINCT p1.user_id)
FROM payment p1
LEFT JOIN payment p2
  ON p1.user_id = p2.user_id
     AND p2.amount > 0
     AND MONTH(p2.payment_date) < 10
WHERE p1.amount > 0
  AND MONTH(p1.payment_date) >= 10
  AND p2.user_id IS NULL;

左连接将加入相同user_id的任何现有行,该用户在&#34;之前订购了某些内容&#34;所以您只需与p2.user_id IS NULL核实没有这样的&#34;之前的订单&#34;存在此user_id。然后计算结果 - 因为每个用户可以多次返回,具体取决于付款次数,DISTINCT负责处理。

一些注释

  • MONTH(datetime)返回号码,因此删除了10
  • 周围的引号
  • 您需要user_id上的索引才能使其在任何合理的时间内正常工作,最好是(user_id, amount, payment_date)上的综合索引将其转换为联接的索引扫描
  • 遗憾的是,MONTH(p1.payment_date) >= 10不是可转化的条件,而且它明年会发生变化,因此您应该在比较中使用完整日期,例如p1.payment_date >= '2015-10-01'p2也是如此})然后在(payment_date, user_id, amount)上添加一个索引,以便快速FROM部分(只有至少有#34;新&#34;付款的用户将被检查,没有活动的旧用户将不会一直都要重新检查。)

答案 3 :(得分:-1)

我不确定但为什么不在SELECT之后使用DISTINCT?

SELECT DISTINCT  COUNT(user_id NOT IN