【问题标题】:Use MySQL LAG() within inner join iteratively在内部连接中迭代地使用 MySQL LAG()
【发布时间】:2020-10-27 07:13:29
【问题描述】:

我有两个表,我需要在一个循环中迭代地加入它们以创建值来填充其中一个表。 我主要是在寻找最简洁的方法来进行单周期移位连接,详情如下。以下两个输入表的示例:

DROP TABLE IF EXISTS holdings;

CREATE TABLE holdings
(date DATE NOT NULL
,ticker CHAR(4) NOT NULL
,wgt DECIMAL(5,2)
,PRIMARY KEY(date,ticker)
);

INSERT INTO holdings VALUES
('2019-03-29','MTUM',0.2),
('2019-03-29','QUAL',0.2),
('2019-03-29','SIZE',0.2),
('2019-03-29','USMV',0.2),
('2019-03-29','VLUE',0.2),
('2019-06-28','MTUM',0.2),
('2019-06-28','QUAL',0.2),
('2019-06-28','SIZE',0.2),
('2019-06-28','USMV',0.2),
('2019-06-28','VLUE',0.2);

DROP TABLE IF EXISTS returns;

CREATE TABLE returns
(monthEnd  DATE NOT NULL
,ticker CHAR(4) NOT NULL
,ret DECIMAL(11,8) NOT NULL
,PRIMARY KEY(monthend,ticker)
);

INSERT INTO returns VALUES
('2019-03-29',  'USMV' ,   0.02715291),
('2019-03-29',  'SIZE' ,   0.00512113),
('2019-03-29',  'VLUE' ,  -0.00943159),
('2019-03-29',  'MTUM' ,   0.02118479),
('2019-03-29',  'QUAL' ,   0.02533432),
('2019-04-30',  'USMV' ,   0.02176873),
('2019-04-30',  'SIZE' ,   0.03818616),
('2019-04-30',  'VLUE' ,   0.03418481),
('2019-04-30',  'MTUM' ,   0.02255305),
('2019-04-30',  'QUAL' ,   0.03794464),
('2019-05-31',  'VLUE' ,  -0.09601646),
('2019-05-31',  'MTUM' ,  -0.02196844),
('2019-05-31',  'QUAL' ,  -0.06582526),
('2019-05-31',  'USMV' ,  -0.01614514),
('2019-05-31',  'SIZE' ,  -0.06918445),
('2019-06-28',  'QUAL' ,   0.07073081),
('2019-06-28',  'VLUE' ,   0.09571038),
('2019-06-28',  'MTUM' ,   0.06121113),
('2019-06-28',  'USMV' ,   0.04984654),
('2019-06-28',  'SIZE' ,   0.07531133),
('2019-07-31',  'QUAL' ,   0.013775  ),
('2019-07-31',  'MTUM' ,   0.01795953),
('2019-07-31',  'SIZE' ,   0.01208791),
('2019-07-31',  'VLUE' ,   0.01601182),
('2019-07-31',  'USMV' ,   0.01668555);

这里的第一步是将 holdings 加入 returns,将日期对齐移动一个句点,这样第一次迭代的输出如下:

date    portName    ticker  wgt monthEnd    ticker  ret
2019-03-29  test    MTUM    0.2 2019-04-30  MTUM    0.02255305
2019-03-29  test    QUAL    0.2 2019-04-30  QUAL    0.03794464
2019-03-29  test    SIZE    0.2 2019-04-30  SIZE    0.03818616
2019-03-29  test    USMV    0.2 2019-04-30  USMV    0.02176873
2019-03-29  test    VLUE    0.2 2019-04-30  VLUE    0.03418481

此时,wgtret 组合在一起,为每个条目提供一个新的 wgt(为简单起见,省略了计算)。这些新的权重被插入到 holdings 表中,这些记录如下所示:

date    portName    ticker  wgt
2019-04-30  test    MTUM    0.201442484998052
2019-04-30  test    QUAL    0.202261035805858
2019-04-30  test    SIZE    0.198273711216605
2019-04-30  test    USMV    0.202619777232855
2019-04-30  test    VLUE    0.19540299074663

下一步是应用与之前相同的程序,获取这些权重,并结合一个周期移位的回报,以产生如下所示的输出:

date    portName    ticker  wgt monthEnd    ticker  ret
2019-04-30  test    MTUM    0.201442484998052   2019-05-31  MTUM    -0.02196844
2019-04-30  test    QUAL    0.202261035805858   2019-05-31  QUAL    -0.06582526
2019-04-30  test    SIZE    0.198273711216605   2019-05-31  SIZE    -0.06918445
2019-04-30  test    USMV    0.202619777232855   2019-05-31  USMV    -0.01614514
2019-04-30  test    VLUE    0.19540299074663    2019-05-31  VLUE    -0.09601646

我们再次组合wgtret 以确定新的wgt 值并将它们插入到holdings 表中。

这将持续到所有日期,直到我们到达日期列表的末尾(鉴于上述示例,holdings 表中的最后一个条目将具有 date2019-07-31)。

需要注意的是,当日期条目已存在时,此过程用于填充 holdingsexcept。换句话说,我们会为 4/30、5/31 和 7/31 执行此过程,但会将 6/28 记录保留在 holdings 表中。

所需的样本输出(对于子集)如下所示:

date    portName    ticker  wgt
2019-03-29  test    MTUM    0.2
2019-03-29  test    QUAL    0.2
2019-03-29  test    SIZE    0.2
2019-03-29  test    USMV    0.2
2019-03-29  test    VLUE    0.2
2019-04-30  test    MTUM    0.201442484998052
2019-04-30  test    QUAL    0.202261035805858
2019-04-30  test    SIZE    0.198273711216605
2019-04-30  test    USMV    0.202619777232855
2019-04-30  test    VLUE    0.19540299074663
2019-05-31  test    MTUM    0.205430582
2019-05-31  test    QUAL    0.201024226
2019-05-31  test    SIZE    0.198113682
2019-05-31  test    USMV    0.204236958
2019-05-31  test    VLUE    0.205066864
2019-06-28  test    MTUM    0.2
2019-06-28  test    QUAL    0.2
2019-06-28  test    SIZE    0.2
2019-06-28  test    USMV    0.2
2019-06-28  test    VLUE    0.2

我的基本方法是在唯一的日期列表上使用循环,首先检查“currentDate”值是否已经在 holdings 表中,然后在按照所述进行计算之前加入. 专门寻找有关执行上述单周期移位联接的最简洁方法的输入。 我来自 SQL Server,我通常会在其中创建一个可以使用的虚拟“rowNum”列(即,a.rowNum = b.rowNum+1)进行移位。想知道是否有办法在连接中使用 LAG() (或其他运算符),是否有另一种更简洁的方法。

我认为没有更简洁(即非基于循环)的方法,因为每组条目都依赖于最后一个。欢迎对方法提出其他想法。

【问题讨论】:

  • “句号”只是序列中的下一个日期?
  • @Strawberry 没错。

标签: mysql mysql-8.0


【解决方案1】:

考虑以下事项;我仍在使用 MySQL 8.0 之前的版本(我知道),所以这里没有窗口函数...

DROP TABLE IF EXISTS holdings;

CREATE TABLE holdings
(date DATE NOT NULL
,ticker CHAR(4) NOT NULL
,wgt DECIMAL(5,2)
,PRIMARY KEY(date,ticker)
);

INSERT INTO holdings VALUES
('2019-03-29','MTUM',0.2),
('2019-03-29','QUAL',0.2),
('2019-03-29','SIZE',0.2),
('2019-03-29','USMV',0.2),
('2019-03-29','VLUE',0.2),
('2019-06-28','MTUM',0.2),
('2019-06-28','QUAL',0.2),
('2019-06-28','SIZE',0.2),
('2019-06-28','USMV',0.2),
('2019-06-28','VLUE',0.2);

DROP TABLE IF EXISTS returns;

CREATE TABLE returns
(monthEnd  DATE NOT NULL
,ticker CHAR(4) NOT NULL
,ret DECIMAL(11,8) NOT NULL
,PRIMARY KEY(monthend,ticker)
);

INSERT INTO returns VALUES
('2019-03-29',  'USMV' ,   0.02715291),
('2019-03-29',  'SIZE' ,   0.00512113),
('2019-03-29',  'VLUE' ,  -0.00943159),
('2019-03-29',  'MTUM' ,   0.02118479),
('2019-03-29',  'QUAL' ,   0.02533432),
('2019-04-30',  'USMV' ,   0.02176873),
('2019-04-30',  'SIZE' ,   0.03818616),
('2019-04-30',  'VLUE' ,   0.03418481),
('2019-04-30',  'MTUM' ,   0.02255305),
('2019-04-30',  'QUAL' ,   0.03794464),
('2019-05-31',  'VLUE' ,  -0.09601646),
('2019-05-31',  'MTUM' ,  -0.02196844),
('2019-05-31',  'QUAL' ,  -0.06582526),
('2019-05-31',  'USMV' ,  -0.01614514),
('2019-05-31',  'SIZE' ,  -0.06918445),
('2019-06-28',  'QUAL' ,   0.07073081),
('2019-06-28',  'VLUE' ,   0.09571038),
('2019-06-28',  'MTUM' ,   0.06121113),
('2019-06-28',  'USMV' ,   0.04984654),
('2019-06-28',  'SIZE' ,   0.07531133),
('2019-07-31',  'QUAL' ,   0.013775  ),
('2019-07-31',  'MTUM' ,   0.01795953),
('2019-07-31',  'SIZE' ,   0.01208791),
('2019-07-31',  'VLUE' ,   0.01601182),
('2019-07-31',  'USMV' ,   0.01668555);

SELECT a.date
     , a.ticker a_ticker
     , a.wgt
     , b.monthend
     , b.ticker b_ticker
     , b.ret
  FROM 
     ( SELECT h.*
            , MIN(monthend) monthend 
         FROM holdings h 
         LEFT -- if appropriate
         JOIN returns r 
           ON r.monthend > h.date 
          AND r.ticker = h.ticker 
        GROUP 
           BY h.date
            , h.ticker
     ) a 
  LEFT -- if appropriate
  JOIN returns b 
    ON b.monthend = a.monthen
d AND b.ticker = a.ticker;
+------------+--------+------+------------+------------+--------+------------+
| date       | ticker | wgt  | monthend   | monthEnd   | ticker | ret        |
+------------+--------+------+------------+------------+--------+------------+
| 2019-03-29 | MTUM   | 0.20 | 2019-04-30 | 2019-04-30 | MTUM   | 0.02255305 |
| 2019-03-29 | QUAL   | 0.20 | 2019-04-30 | 2019-04-30 | QUAL   | 0.03794464 |
| 2019-03-29 | SIZE   | 0.20 | 2019-04-30 | 2019-04-30 | SIZE   | 0.03818616 |
| 2019-03-29 | USMV   | 0.20 | 2019-04-30 | 2019-04-30 | USMV   | 0.02176873 |
| 2019-03-29 | VLUE   | 0.20 | 2019-04-30 | 2019-04-30 | VLUE   | 0.03418481 |
| 2019-06-28 | MTUM   | 0.20 | 2019-07-31 | 2019-07-31 | MTUM   | 0.01795953 |
| 2019-06-28 | QUAL   | 0.20 | 2019-07-31 | 2019-07-31 | QUAL   | 0.01377500 |
| 2019-06-28 | SIZE   | 0.20 | 2019-07-31 | 2019-07-31 | SIZE   | 0.01208791 |
| 2019-06-28 | USMV   | 0.20 | 2019-07-31 | 2019-07-31 | USMV   | 0.01668555 |
| 2019-06-28 | VLUE   | 0.20 | 2019-07-31 | 2019-07-31 | VLUE   | 0.01601182 |
+------------+--------+------+------------+------------+--------+------------+

冲洗并重复。

【讨论】:

    猜你喜欢
    • 2017-08-30
    • 2017-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多