编写事件系列联接

此主题中的示例包含时间戳不匹配项,就像在现实情形中可能会遇到的一样;例如,在没有交易时,股票在一段时间内可能会处于非活动状态,这时要想比较时间戳不匹配的两支股票会有一定挑战。

hTicks 表和 aTicks 表

示例 ticks 架构所述,表 hTicks 在 12:02、12:03 和 12:04 缺少输入行,表 aTicks 在 12:01、12:02 和 12:04 缺少输入行。

通过全外联接查询事件系列

此查询使用传统的全外联接,在 hTicks 表和 aTicks 表之间找到了位于 12:00 和 12:05 的匹配项,然后用 NULL 值填充缺失的数据点。

=> SELECT * FROM hTicks h FULL OUTER JOIN aTicks a ON (h.time = a.time);
 stock |   time   | price | stock |   time   | price
-------+----------+-------+-------+----------+--------
 HPQ   | 12:00:00 | 50.00 | ACME  | 12:00:00 | 340.00
 HPQ   | 12:01:00 | 51.00 |       |          |
 HPQ   | 12:05:00 | 51.00 | ACME  | 12:05:00 | 333.80
 HPQ   | 12:05:00 | 51.00 | ACME  | 12:05:00 | 340.20
 HPQ   | 12:06:00 | 52.00 |       |          |
       |          |       | ACME  | 12:03:00 | 340.10
(6 rows)

要为缺失的数据点将空白替换为内插值,可使用 INTERPOLATE 谓词创建 事件序列联接。联接条件仅限于 ON 子句,该子句会在两个输入表的时间戳列中对等同谓词求值。换句话说,对于外表 hTicks 中的每个行,为内表 aTicks 中每个行的每个组合对 ON 子句谓词进行求值。

简单地重写全外联接可将 INTERPOLATE 谓词与所需的 PREVIOUS VALUE 关键字结合使用。请注意,对于事件序列数据,在事件序列数据上执行全外联接是最常见的场景,在此场景中,您可以同时保留两个表中的所有行。

=> SELECT * FROM hTicks h FULL OUTER JOIN aTicks a
   ON (h.time INTERPOLATE PREVIOUS VALUE a.time);

Vertica 使用此表以前的值内插缺失数据(在全外联接中显示为 NULL):

![event series join](/images/hticks1.png)

如果查看普通全外联接的输出,您可以发现这两个表在 12:00 和 12:05 时间列中存在一个匹配,但在 12:01,则不存在 ACME 的条目记录。因此,相关操作会根据 aTicks 表中以前的值为 ACME (ACME,12:00,340) 内插一个值。

通过左外联接查询事件系列

您也可以使用左外联接和右外联接。例如,您可能决定仅保留 hTicks 的值。因此,您将写入左外联接:

=> SELECT * FROM hTicks h LEFT OUTER JOIN aTicks a
   ON (h.time INTERPOLATE PREVIOUS VALUE a.time);
 stock |   time   | price | stock |   time   | price
-------+----------+-------+-------+----------+--------
 HPQ   | 12:00:00 | 50.00 | ACME  | 12:00:00 | 340.00
 HPQ   | 12:01:00 | 51.00 | ACME  | 12:00:00 | 340.00
 HPQ   | 12:05:00 | 51.00 | ACME  | 12:05:00 | 333.80
 HPQ   | 12:05:00 | 51.00 | ACME  | 12:05:00 | 340.20
 HPQ   | 12:06:00 | 52.00 | ACME  | 12:05:00 | 340.20
(5 rows)

以下数据与使用传统的左外联接得到的数据相似:

=> SELECT * FROM hTicks h LEFT OUTER JOIN aTicks a ON h.time = a.time;
 stock |   time   | price | stock |   time   | price
-------+----------+-------+-------+----------+--------
 HPQ   | 12:00:00 | 50.00 | ACME  | 12:00:00 | 340.00
 HPQ   | 12:01:00 | 51.00 |       |          |
 HPQ   | 12:05:00 | 51.00 | ACME  | 12:05:00 | 333.80
 HPQ   | 12:05:00 | 51.00 | ACME  | 12:05:00 | 340.20
 HPQ   | 12:06:00 | 52.00 |       |          |
(5 rows)

请注意,右外联接与保存表的行为相同,只是顺序相反。

通过内联接查询事件系列

请注意,如果忽视所有空白,INNER 事件序列联接的行为方式与普通的 ANSI SQL-99 联接相同。因此,这时不会内插任何内容,而且以下两个查询等效,都会返回相同的结果集。

普通的内联接:

=> SELECT * FROM HTicks h JOIN aTicks a
    ON (h.time INTERPOLATE PREVIOUS VALUE a.time);
 stock |   time   | price | stock |   time   | price
-------+----------+-------+-------+----------+--------
 HPQ   | 12:00:00 | 50.00 | ACME  | 12:00:00 | 340.00
 HPQ   | 12:05:00 | 51.00 | ACME  | 12:05:00 | 333.80
 HPQ   | 12:05:00 | 51.00 | ACME  | 12:05:00 | 340.20
(3 rows)

事件序列内联接:

=> SELECT * FROM hTicks h INNER JOIN aTicks a ON (h.time = a.time);
 stock |   time   | price | stock |   time   | price
-------+----------+-------+-------+----------+--------
 HPQ   | 12:00:00 | 50.00 | ACME  | 12:00:00 | 340.00
 HPQ   | 12:05:00 | 51.00 | ACME  | 12:05:00 | 333.80
 HPQ   | 12:05:00 | 51.00 | ACME  | 12:05:00 | 340.20
(3 rows)

Bid 表和 Ask 表

使用 bid 表和 ask 表的示例架构,编写全外联接以内插缺失的数据点:

=> SELECT * FROM bid b FULL OUTER JOIN ask a
    ON (b.stock = a.stock AND b.time INTERPOLATE PREVIOUS VALUE a.time);

在下列输出中,股票 HPQ 的第一行显示了 NULL,因为在 12:01 之前不存在 HPQ 的条目记录。

 stock |   time   | price  | stock |   time   | price
-------+----------+--------+-------+----------+--------
 ACME  | 12:00:00 |  80.00 | ACME  | 12:00:00 |  80.00
 ACME  | 12:00:00 |  80.00 | ACME  | 12:02:00 |  75.00
 ACME  | 12:03:00 |  79.80 | ACME  | 12:02:00 |  75.00
 ACME  | 12:05:00 |  79.90 | ACME  | 12:02:00 |  75.00
 HPQ   | 12:00:00 | 100.10 |       |          |
 HPQ   | 12:01:00 | 100.00 | HPQ   | 12:01:00 | 101.00
(6 rows)

另外,请注意 ask 表的同一个行 (ACME,12:02,75) 出现了三次。第一次出现是因为 bid 表中没有 ask 中的行,因此 Vertica 使用 12:02 的 ACME 值 (75.00) 插入了缺失值。第二次出现是因为 bid 中的行 (ACME,12:05,79.9) 在 ask 中没有相应的匹配项。ask 中包含 (ACME,12:02,75) 的行是最接近的行,因此使用它来插入值。

如果编写普通的全外联接,则可以发现哪些地方出现了不匹配的时间戳:

=> SELECT * FROM bid b FULL OUTER JOIN ask a ON (b.time = a.time);
 stock |   time   | price  | stock |   time   | price
-------+----------+--------+-------+----------+--------
 ACME  | 12:00:00 |  80.00 | ACME  | 12:00:00 |  80.00
 ACME  | 12:03:00 |  79.80 |       |          |
 ACME  | 12:05:00 |  79.90 |       |          |
 HPQ   | 12:00:00 | 100.10 | ACME  | 12:00:00 |  80.00
 HPQ   | 12:01:00 | 100.00 | HPQ   | 12:01:00 | 101.00
       |          |        | ACME  | 12:02:00 |  75.00
(6 rows)