我有一个名为“ t1”的表,我的表是-
+------+------+
| c1 | c2 |
+------+------+
| 1 | 12 |
| 2 | 13 |
| 3 | 14 |
+------+------+
我想获取所有行以及col2的先前值。 我使用的查询:-
Select c1,@prev,@prev:=c2 from t1;
我得到以下输出-
+------+---------+------------+
| c1 | @prev | @prev:=c2 |
+------+---------+------------+
| 1 | NULL | 12 |
| 2 | NULL | 13 |
| 3 | NULL | 14 |
+------+---------+------------+
我期望第一行只得到NULL。但是我在所有行中都得到NULL。 请解释为什么在所有行中都给出NULL。
答案 0 :(得分:1)
您可以在下面尝试-
SET @prev=-1;
Select c1,@prev prev_col,@prev:=c2 cur_col
from t1 order by c1
输出:
c1 prev_col cur_col
1 -1 12
2 12 13
3 13 14
答案 1 :(得分:1)
获得所有NULL
值的原因是因为您没有初始化@prev
变量。您可以使用SET @prev := 0
语句对其进行初始化,或者,如果仅需单个查询即可获得此结果,则可以使用CROSS JOIN
来初始化变量:
SELECT c1, @prev AS prev, @prev:=c2 AS c2
FROM t1
CROSS JOIN (SELECT @prev := 0) v;
输出:
c1 prev c2
1 0 12
2 12 13
3 13 14
如果您没有必须使用变量,并且您的c1
值是连续的,则也可以使用LEFT JOIN
获得相同的结果:
SELECT t1.c1, t1.c2, t2.c2 AS prev
FROM t1
LEFT JOIN t1 t2 ON t2.c1 = t1.c1 - 1
ORDER BY t1.c1
如果您的c1
值可能不连续,则以上LEFT JOIN
将无法正常工作。在这种情况下,您需要JOIN
的{{1}}值是最高值,小于要c1
设置为的值:
JOIN
在两种情况下,输出都是相同的:
SELECT t1.c1, t1.c2, t2.c2 AS prev
FROM t1
LEFT JOIN t1 t2 ON t2.c1 = (SELECT MAX(c1)
FROM t1 t3
WHERE t3.c1 < t1.c1)
ORDER BY t1.c1
答案 2 :(得分:0)
您可以通过子查询获取先前的值:
SET @def = 0;
Select
t.c1,
coalesce(
(select c2 from tablename where c1 < t.c1 order by c1 desc limit 1),
@def) prev_col,
t.c2 cur_col
from tablename t order by t.c1;
请参见demo 或者:
SET @def = 0;
Select
t.c1,
coalesce(
(select max(c2) from tablename where c1 < t.c1),
@def) prev_col,
t.c2 cur_col
from tablename t order by t.c1;
请参见demo
答案 3 :(得分:0)
记录为NULL的原因here:
另一个问题是为变量分配值并读取 在同一非SET语句中的值是默认结果 变量的类型取决于语句开头的类型。
由于@prev
在首次读取之前未定义,因此我们甚至无法说出它的类型。
现在,您可以将其预设为某个值,例如set @prev = 0;
。但是0
可能是有效值,因此您可能希望第一行的值为NULL。 set @prev = null;
均无效。但是您可以执行以下操作:
set @prev = -1; -- define type as SIGNED
set @prev = null; -- set NULL
现在查询应该返回
c1 @prev @prev:=c2
1 null 12
2 12 13
3 13 14
您还可以在单个语句中定义类型并分配NULL:
set @prev = cast(null as signed);
请参见Demo
但是-在同一条语句(SET除外)中读写用户变量时-未定义行为。在文档中,您将找到以下语句:
还可以在语句中为用户变量分配值 除
SET
以外。 ( MySQL 8.0 中已弃用此功能 ,并且 可能会在后续版本中删除。)...
作为一般规则,除了SET语句中的内容外,绝对不要 为用户变量分配一个值,并在同一变量内读取该值 声明。
...
对于其他语句,例如
SELECT
,您可能会得到结果 期望,但是不能保证。
我已经用粗体标记了重要部分,因此您可以发现不建议以这种方式使用变量。
较新的版本(MySQL 8.0和MariaDB 10.2)现在支持window functions like LEAD()
and LAG()
。因此,您可以通过以下方式编写查询:
Select c1, c2, lag(c2) over (order by c1) as prev
from t1
这不仅对将来的MySQL版本可靠。它还将在许多(所有主要的)RDBM系统上工作。