我有一个相当不寻常的问题,从本地环境迁移到临时服务器时出现。 MySQL 版本不同,但我无法找到发生此问题的任何原因。
我使用的代码是:
DECLARE _first_event_time datetime;
SELECT event_time INTO _first_event_time
FROM session_events
WHERE session_id = _session_id
ORDER BY event_id ASC LIMIT 0,1;
-- Select Data
SELECT event_id,
event_time,
timediff(event_time, _first_event_time) AS event_time_from_start,
(@previous := unix_timestamp(event_time) - @previous) AS event_duration,
(@previous := unix_timestamp(event_time)) AS previous_event_timestamp
FROM session_events e,
(SELECT @previous:=0) c
ORDER BY event_id ASC LIMIT 0, 400;
我期望得到以下结果,这是我在运行 MAMP 的 DEV 版本上运行 5.5 时得到的结果:
+----------+------------------+-----------------------+----------------+--------------------------+
| event_id | event_time | event_time_from_start | event_duration | previous_event_timestamp |
+----------+------------------+-----------------------+----------------+--------------------------+
| 5074 | 24/09/2015 20:35 | 00:00:00 | 1443123315 | 1443123315 |
| 5075 | 24/09/2015 20:35 | 00:00:02 | 2 | 1443123317 |
| 5076 | 24/09/2015 20:35 | 00:00:03 | 1 | 1443123318 |
| 5077 | 24/09/2015 20:35 | 00:00:03 | 0 | 1443123318 |
| 5078 | 24/09/2015 20:35 | 00:00:04 | 1 | 1443123319 |
| 5079 | 24/09/2015 20:35 | 00:00:05 | 1 | 1443123320 |
| 5080 | 24/09/2015 20:35 | 00:00:06 | 1 | 1443123321 |
| 5081 | 24/09/2015 20:35 | 00:00:06 | 0 | 1443123321 |
| 5082 | 24/09/2015 20:35 | 00:00:07 | 1 | 1443123322 |
| 5083 | 24/09/2015 20:35 | 00:00:08 | 1 | 1443123323 |
| 5084 | 24/09/2015 20:35 | 00:00:09 | 1 | 1443123324 |
| 5085 | 24/09/2015 20:35 | 00:00:10 | 1 | 1443123325 |
+----------+------------------+-----------------------+----------------+--------------------------+
但是数据却像这样输出(请注意,数据值不同,因为我在两台服务器上创建了相同的值,但您可以看到数据偏移的位置,存储过程中的代码是相同的在两台服务器上):
+----------+------------------+-----------------------+----------------+--------------------------+
| event_id | event_time | event_time_from_start | event_duration | previous_event_timestamp |
+----------+------------------+-----------------------+----------------+--------------------------+
| 5307 | 24/09/2015 20:32 | 00:00:00 | -17 | 1443123174 |
| 5308 | 24/09/2015 20:33 | 00:00:07 | 1443123181 | 1443123181 |
| 5309 | 24/09/2015 20:33 | 00:00:08 | -7 | 1443123182 |
| 5310 | 24/09/2015 20:33 | 00:00:09 | 2 | 1443123183 |
| 5311 | 24/09/2015 20:33 | 00:00:11 | 3 | 1443123185 |
| 5312 | 24/09/2015 20:33 | 00:00:12 | 3 | 1443123186 |
| 5313 | 24/09/2015 20:33 | 00:00:13 | 2 | 1443123187 |
| 5314 | 24/09/2015 20:33 | 00:00:14 | 2 | 1443123188 |
| 5315 | 24/09/2015 20:33 | 00:00:15 | 2 | 1443123189 |
| 5316 | 24/09/2015 20:33 | 00:00:15 | 1 | 1443123189 |
| 5317 | 24/09/2015 20:33 | 00:00:17 | 2 | 1443123191 |
| 5318 | 24/09/2015 20:33 | 00:00:18 | 18 | 1443123192 |
+----------+------------------+-----------------------+----------------+--------------------------+
时区不应该产生影响,因为这是从数据和存储过程运行的。我还尝试使用以下命令从时间戳更改为仅使用 datediff:
, ( TIME_TO_SEC(TIMEDIFF(event_time, @previous))) AS event_duration
, ( @previous := event_time ) AS previous_event_timestamp
进一步研究一下,问题似乎出在 ORDER BY 子句的某个地方,在该服务器上初始运行时填充 @previous 字段时,它似乎以未排序的顺序选择结果,就好像我删除了 ORDER BY 子句,然后将 @previous 设置为 event_time,然后该订单就是导致问题的订单。
如果我只运行一个没有 @previous 且没有 ORDER BY 子句的 select 语句,则 5.6 服务器返回的数据集似乎与第二个示例中显示的异常顺序相匹配,其中 @previous 似乎正在选择随机值。
我只能知道 SELECT 语句中运行数据并设置 @previous 值的部分首先运行,然后当它返回数据时运行 ORDER BY,这就是问题的根源。
浏览 MySQL 手册,我没有发现 5.5 和 5.6 之间的任何内容(至少没有找到我能够解释的原因)。我认为有一种方法可以让它发挥作用。
任何建议将不胜感激,因为我无法弄清楚为什么它按照 ORDER BY 子句之前的顺序进行选择。
最佳答案
MySQL明确警告不要在同一select
中使用变量并在不同表达式中分配它们。我建议您使用子查询来执行此操作:
SELECT t.*,
(unix_timestamp(event_time) - previous_event_timestamp) as event_duration
FROM (SELECT event_id, event_time,
timediff(event_time, _first_event_time) AS event_time_from_start,
if((@pp := @p) = null, null, -- never happens
if(@p := unix_timestamp(event_time), @pp, @pp)
) AS previous_event_timestamp
FROM session_events e CROSS JOIN
(SELECT @p := 0, @pp := 0) c
ORDER BY event_id ASC
LIMIT 0, 400
) t;
if
逻辑只是将赋值放在同一语句中的一种方法。第一个将 @pp
指定为当前的先前值(在 @p
中)。第二个重新分配@p
,然后返回@pp
。
然后外部查询对值进行计算。
As a general rule, other than in SET statements, you should never assign a value to a user variable and read the value within the same statement.
最好避免使用文档明确警告不要使用的“功能”。
关于mysql - 在 MySQL 5.5 中,用户变量可以从上一行中选择值,但在 5.6 中,它似乎以不同的顺序运行查询的 SELECT 部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32973350/