MySQL用户var没有递增

时间:2015-05-11 03:30:38

标签: mysql

我有一个在SQL Fiddle中完美运行的查询:http://sqlfiddle.com/#!9/ffcba/22但是当我在我的生产服务器上尝试它时,在@user = user时@row_number没有递增的意义上它不起作用最终得到以下结果:

+------+-------+-----+---------+
| user | file  | log | billing |
+------+-------+-----+---------+
|    1 | b.pdf |   3 |       1 |
|    1 | b.pdf |   3 |       1 |
|    1 | a.pdf |   2 |       0 |
|    2 | d.pdf |   2 |       1 |
|    2 | d.pdf |   2 |       1 |
|    2 | c.pdf |   1 |       0 |
|    3 | f.pdf |   3 |       0 |
|    3 | e.pdf |   1 |       0 |
|    4 | g.pdf |   0 |       1 |
|    4 | i.pdf |   2 |       1 |
|    4 | g.pdf |   0 |       1 |
|    4 | j.pdf |   3 |       0 |
|    4 | i.pdf |   2 |       1 |
|    4 | h.pdf |   1 |       0 |
+------+-------+-----+---------+

...而不是小提琴归结为的4行结果,这应该是它应该是什么。小提琴是一个测试,虽然我的生产变量略有不同,但我最终还是从小提琴复制模式来构建测试表,以确认所有内容,据我所知,完全相同。我目前正在运行MySQL 5.6.23,而小提琴正在下拉列表中使用5.6。

似乎在小提琴上正确运行以下设置:

架构:

create table tests ( ID int, user int, log int);
insert into tests values 
(  1,     1,    2), 
(  2,     1,    2), 
(  3,     2,    2), 
(  4,     3,    2), 
(  5,     3,    2), 
(  6,     4,    2); 

create table files (ID int, file varchar(10),  log int, billing int, user int);
insert into files values
(  1,  'a.pdf',    2,        0,     1), 
(  2,  'b.pdf',    3,        1,     1), 
(  3,  'c.pdf',    1,        0,     2), 
(  4,  'd.pdf',    2,        1,     2), 
(  5,  'e.pdf',    1,        0,     3), 
(  6,  'f.pdf',    3,        0,     3), 
(  7,  'g.pdf',    0,        1,     4), 
(  8,  'h.pdf',    1,        0,     4), 
(  9,  'i.pdf',    2,        1,     4), 
( 10,  'j.pdf',    3,        0,     4) 

查询

SELECT user, file, log, billing
FROM (
SELECT @row_number:=CASE WHEN @user=user THEN @row_number+1 
                         ELSE 1 
                    END AS row_number,
       @user:=user AS user,
       file, log, billing
FROM (        
SELECT 1 AS pri, t.user, f.file, f.log, f.billing
FROM (SELECT DISTINCT user, log
      FROM tests 
      WHERE log = 2) AS t
INNER JOIN files AS f 
ON (t.user = f.user AND t.log = f.log AND f.billing = 1)   

UNION ALL

SELECT 2 AS pri, t.user, f.file, f.log, f.billing
FROM (SELECT DISTINCT user, log
      FROM tests 
      WHERE log = 2) AS t
INNER JOIN files AS f 
ON (t.user = f.user AND f.billing = 1)   
WHERE f.log > t.log OR f.log = 0

UNION ALL

SELECT 3 AS pri, t.user, f.file, f.log, f.billing       
FROM (SELECT DISTINCT user, log
      FROM tests 
      WHERE log = 2) AS t
INNER JOIN files AS f ON (t.user = f.user)  
ORDER BY user, pri, log DESC ) s ) r
WHERE r.row_number = 1
ORDER BY user

小提琴所需的结果

+------+-------+-----+---------+
| user | file  | log | billing |
+------+-------+-----+---------+
|    1 | b.pdf |   3 |       1 |
|    2 | d.pdf |   2 |       1 |
|    3 | f.pdf |   3 |       0 |
|    4 | i.pdf |   2 |       1 |
+------+-------+-----+---------+

如果有人知道为什么这可能不起作用的任何原因,也许是一个设置或其他什么,任何有关纠正它的见解将不胜感激

谢谢!

1 个答案:

答案 0 :(得分:1)

当您尝试在修改它时在同一个选择中读取变量时,MySQL结果是不确定的。

5.6 User Variables

  

对于其他语句,例如SELECT,您可能会得到结果   期待,但这不能保证。在以下声明中,您   可能会认为MySQL会首先评估@a然后做一个   第二个任务:

     

SELECT @ a,@ a:= @ a + 1,...;但是,评估顺序为   涉及用户变量的表达式是未定义的。

为了解决这个问题,我们可以使用嵌套的条件语句来强制执行顺序。您应该尝试做的是将case语句更改为嵌套的if语句。

所以改变这个:

SELECT @row_number:=CASE WHEN @user=user THEN @row_number+1   -- do i happen first?
                         ELSE 1 
                    END AS row_number,
       @user:=user AS user,                                   -- or do i?

哪个地方可能遇到麻烦 - 我们不知道首先会评估case@user := user,对此:

select if(@user = user,                        -- if we are processing the same user
          @row_number := @row_number + 1,      -- increment row number
          if(@user := user,                    -- otherwise set current user
             @row_number := 1,                 -- then set row number to 1
             @row_number := 1)) as row_number, -- failsafe if user is null
       user,
       file, log, billing

ifs链将确保您的变量包含您期望的值。

我修改了你的小提琴here,你可以看到结果与之前的结果相同,但它们应该更加可靠。请尝试使用其他数据,看看它是如何进行的。

此外,变量未初始化,这是需要发生的事情。你可以通过在查询之前在语句中明确设置它们来做到这一点,或者你可以cross join到一个简单的选择来设置它们 - 我倾向于选择后者。

cross join (select @row_number := 1, @user := 0) q

fiddle updated once again