Mysql局部变量没有更新

时间:2015-02-13 19:20:24

标签: mysql

我尝试使用局部变量来保存用户数的值,以便计算当前计数与之前的计数之间的比率。

我使用此查询:

SET @count = 0;

SELECT  DATE_FORMAT(ual.time, "%M, %Y") as monthName,

@count as beforeCount, 

count(DISTINCT ual.user_id)/@count as progress,

@count := count(DISTINCT ual.user_id) as afterCount

FROM user_activity_log ual

LEFT OUTER JOIN user u

ON u.gym = 22

LEFT OUTER JOIN (SELECT ualWeek.user_id FROM user_activity_log ualWeek 

GROUP BY FROM_DAYS(TO_DAYS(ualWeek.time) -MOD(TO_DAYS(ualWeek.time) -1, 7)), ualWeek.user_id 

HAVING count(ualWeek.user_id) > 1) weekUsers

ON u.id = weekUsers.user_id

LEFT OUTER JOIN (SELECT ualMonth.user_id FROM user_activity_log ualMonth 

GROUP BY DATE(DATE_FORMAT(ualMonth.time, "%Y-%m-01")), ualMonth.user_id 

HAVING count(ualMonth.user_id) > 5) monthUsers

ON u.id = monthUsers.user_id

WHERE

(ual.user_id = weekUsers.user_id OR ual.user_id = monthUsers.user_id) AND

((ual.time BETWEEN '2014-02-13' AND '2015-02-13') OR (('2014-02-13' IS NULL) OR ('2015-02-13' IS NULL)))

GROUP BY DATE(DATE_FORMAT(ual.time, "%Y-%m-01"))

我的问题是@count没有更新自己。 这是我的结果: enter image description here

如果我编辑我的查询并删除我的加入它的工作正常。 新查询:

SET @count = 0;

SELECT  DATE_FORMAT(ual.time, "%M, %Y") as monthName,

@count as beforeCount, 

count(DISTINCT ual.user_id)/@count as progress,

@count := count(DISTINCT ual.user_id) as afterCount

FROM user_activity_log ual

WHERE

((ual.time BETWEEN '2014-02-13' AND '2015-02-13') OR (('2014-02-13' IS NULL) OR ('2015-02-13' IS NULL)))

GROUP BY DATE(DATE_FORMAT(ual.time, "%Y-%m-01"))

enter image description here

  • 我的问题是为什么会发生这种情况,如何保持我的联接并仍然拥有@counter

1 个答案:

答案 0 :(得分:0)

用户定义变量的行为无法保证使用SELECT语句,就像你使用它一样。

MySQL 5.5参考手册

的“9.4用户定义变量”部分的摘录
  

对于其他语句,例如SELECT,您可能会得到您期望的结果,但这不能保证。在下面的语句中,您可能会认为MySQL将首先评估@a,然后再进行一次分配:

     

SELECT @a, @a:=@a+1, ...;

     

但是,涉及用户变量的表达式的评估顺序是未定义的。

参考:http://dev.mysql.com/doc/refman/5.5/en/user-variables.html


您可以尝试(无保证)使用parens中的连接包装SELECT,并将其用作另一个查询的内联视图。至少通过5.5版本,该查询的结果将实现为派生表,外部查询将针对该查询运行。

方法是将结果集准备到派生表中,然后运行使用用户定义变量的外部查询,以“保留”前一行的值。再一次,没有保证,但这可能适合你:

SELECT DATE_FORMAT(d.dt, '%M, %Y') AS monthName
     , d.cnt/@prev_count           AS progress
     , @prev_count := d.cnt        AS cnt
  FROM ( SELECT @prev_count := 0 ) i
  JOIN ( SELECT DATE(DATE_FORMAT(ual.time, '%Y-%m-01')) AS dt  
              , COUNT(DISTINCT ual.user_id)             AS cnt
           FROM user_activity_log ual
           LEFT 
           JOIN user u
             ON u.gym = 22
           LEFT 
           JOIN ( SELECT ualWeek.user_id 
                    FROM user_activity_log ualWeek 
                   GROUP
                      BY FROM_DAYS(TO_DAYS(ualWeek.time) -MOD(TO_DAYS(ualWeek.time) -1, 7))
                       , ualWeek.user_id 
                  HAVING COUNT(ualWeek.user_id) > 1
                ) weekUsers
             ON weekUsers.user_id = u.id
           LEFT 
           JOIN ( SELECT ualMonth.user_id
                    FROM user_activity_log ualMonth 
                   GROUP
                      BY DATE(DATE_FORMAT(ualMonth.time, '%Y-%m-01'))
                       , ualMonth.user_id
                  HAVING COUNT(ualMonth.user_id) > 5
                ) monthUsers
             ON monthUsers.user_id = u.id
          WHERE (ual.user_id = weekUsers.user_id OR ual.user_id = monthUsers.user_id)
            AND ((ual.time BETWEEN '2014-02-13' AND '2015-02-13') OR (('2014-02-13' IS NULL) OR ('2015-02-13' IS NULL)))
          GROUP BY DATE(DATE_FORMAT(ual.time, '%Y-%m-01'))
          ORDER BY DATE(DATE_FORMAT(ual.time, '%Y-%m-01'))
       ) d