Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/85.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 将列设置为同一表中另一列的滞后值_Mysql_Sql - Fatal编程技术网

Mysql 将列设置为同一表中另一列的滞后值

Mysql 将列设置为同一表中另一列的滞后值,mysql,sql,Mysql,Sql,我有一个记录日期的列,我想将另一列设置为日期列的滞后版本。换句话说,对于每个日期,我都希望新列具有上一个日期。 我尝试了很多东西,大部分都是愚蠢的,结果一无所获。我的主要问题是,我根据同一个表和同一个列中的where子句更新了一个列,MySQL不允许这样做 下面是一个数据示例。我的目标是使用DATA_DATE中的前一行更新columprevdate,条件是两行的GVKEY相同。我将按如下方式定义前一行,按GVKEY和DATE_DATE ASC排序,对于每一行,如果GVKEY相同,我想要前一行 +

我有一个记录日期的列,我想将另一列设置为日期列的滞后版本。换句话说,对于每个日期,我都希望新列具有上一个日期。 我尝试了很多东西,大部分都是愚蠢的,结果一无所获。我的主要问题是,我根据同一个表和同一个列中的where子句更新了一个列,MySQL不允许这样做

下面是一个数据示例。我的目标是使用DATA_DATE中的前一行更新columprevdate,条件是两行的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        |
+--------------+--------+---------+-------+----------+-------------+

这里有一种方法可以使用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
选择列表中表达式的顺序很重要,我们需要将当前行的值与前一行保存的值进行比较,然后再将当前值保存在@prev_uuu变量中,以用于下一行

我们需要一个条件测试来确保我们仍然在使用同一个gvkey。gvkey的第一个数据_日期不会有以前的数据_日期,因此我们需要返回NULL

为了获得最佳性能,我们需要一个覆盖索引,以gvkey和data_date作为前导列:

   ... ON mytable (gvkey,data_data)
索引可以在这些列之后包含其他列,但我们需要按顺序首先包含这两列。这将允许MySQL使用索引按顺序返回行,并避免使用filesort操作带来的开销。解释中的额外列将显示使用索引的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参考手册警告不要使用这样的用户定义变量。

我想您需要一个连接更新。MySQL不允许您在子查询中更新同一个表。有多少行可能具有给定的GVKEY?从订购角度定义上一个日期的定义可能有数千个。我会定义前一行如下,按GVKEY和DATE_DATE ASC排序,对于我想要的每一行,前一行和DATA_DATE是Datetime,而不是hometype@DrewPierce这是日期格式的。谢谢@spencer7593,效果非常好。我花了一段时间才弄明白,但解释也很棒!为了得到下一个日期,我只需要按降序排序,对吗?另外,我的桌子不是太大,所以性能根本不是问题。我花了不到一分钟的时间。是的,你也可以做同样的事情来获得下一个日期,只需取消订单。为了确保可以有效地使用可用索引,请按降序执行整个操作。。。按gvkey DESC、data_date DESC订购。如果您想存储前一行的价格,您可以使用相同的模式从前一行获取任何列。显然,在以后插入或删除行时,prev_date列不会自动维护。