我有一个记录日期的列,我想将另一列设置为日期列的滞后版本。换句话说,对于每个日期,我希望新列具有上一个日期。 我尝试了很多东西,大多是傻瓜,我无处可去。我的主要问题是我根据同一个表和同一列的where子句更新了一个列,并且MySQL不允许它。
以下是数据的示例。我的目标是更新colum PREVDATE,使用DATA_DATE中的上一行,条件是两行的GVKEY相同。我将如下定义前一行,按GVKEY和DATE_DATE ASC排序,并为每一行(假设GVKEY是相同的)我想要前一行
+--------------+--------+---------+-------+----------+-------------+
| DATA_DATE |PREVDATE| PRICE | GVKEY | CUR_DEBT | LT_DEBT |
+--------------+--------+---------+-------+----------+-------------+
| 1965-05-31 | NULL | -17.625 | 1004 | 0.198 | 1.63 |
| 1970-05-31 | NULL | -18.375 | 1004 | 2.298 | 1.58 |
+--------------+--------+---------+-------+----------+-------------+
答案 0 :(得分:2)
这是一种利用MySQL用户定义变量的方法,以及无法保证的行为,但看起来是一致的(至少在MySQL 5.1,5.5和5.6中)。
警告:这将返回表中的每个行。您可能需要考虑对有限范围的gvkey值执行此操作以进行测试。添加WHERE子句......
SELECT IF(r.gvkey=@prev_gvkey,@prev_ddate,NULL) AS prev_date
, @prev_gvkey := r.gvkey AS gvkey
, @prev_ddate := r.data_date AS data_date
FROM (SELECT @prev_ddate := NULL, @prev_gvkey := NULL) i
CROSS
JOIN mytable r
ORDER BY r.gvkey, r.data_date
SELECT列表中表达式的顺序很重要,我们需要在保存@prev_变量中的当前值之前,将当前行的值与前一行的“已保存”值进行比较。下一行。
我们需要一个条件测试来确保我们仍在使用相同的gvkey。 gvkey的第一个data_date不会有“previous”data_date,所以我们需要返回一个NULL。
为了获得最佳效果,我们希望有一个覆盖索引,其中gvkey
和data_date
为主要列:
... ON mytable (gvkey,data_data)
索引可以包含其他列,但是我们首先需要这两列,按顺序排列。这将允许MySQL使用索引“按顺序”返回行,并避免昂贵的“使用filesort”操作。 (EXPLAIN的额外列将显示MySQL“使用索引”。)
一旦我们正确运行,我们就可以将其用作UPDATE
语句中的内联视图。
例如:
UPDATE mytable t
JOIN (
SELECT IF(r.gvkey=@prev_gvkey,@prev_ddate,NULL) AS prev_date
, @prev_gvkey := r.gvkey AS gvkey
, @prev_ddate := r.data_date AS data_date
FROM (SELECT @prev_ddate := NULL, @prev_gvkey := NULL) i
CROSS
JOIN mytable r
ORDER BY r.gvkey, r.data_date
) s
ON t.gvkey = s.gvkey
AND t.data_date = s.data_date
SET t.prev_date = s.prev_date
(同样,对于一个非常大的表,我们可能希望通过在内联视图中包含gvkey的谓词来将该事务分解为更小的块,以限制返回/更新的行数。)
批量gvkey
范围内这样做是合理的方法......例如。
/* first batch */ WHERE r.gvkey >= 1 AND r.gvkey < 100
/* second run */ WHERE r.gvkey >= 100 AND r.gvkey < 200
/* third batch */ WHERE r.gvkey >= 200 AND r.gvkey < 300
显然,还有其他方法/ SQL模式可以实现相同的结果。我用这种方法取得了成功。
要强调早期的重要注意:这取决于无法保证的行为,以及MySQL参考手册警告的行为(使用这样的用户定义变量)。 )