在窗口函数中如何引用正在定义的列,即引用自身?
Posted
技术标签:
【中文标题】在窗口函数中如何引用正在定义的列,即引用自身?【英文标题】:Within a window function how to refer back to the column that is being defined, namely reference to itself? 【发布时间】:2021-05-28 10:10:16 【问题描述】:为了计算调整后的成本基数 (ACB),它是价格 * 数量 + 佣金或先前 ACB/股份 * 数量的运行总和,具体取决于是销售还是购买。
我有下表,命名为transaction_t
:
Date | Action | Quantity | Price | Commission |
---|---|---|---|---|
2021-01-02 | buy | 150 | 110.21 | 5.95 |
2021-01-21 | buy | 360 | 106.87 | 5.95 |
2021-03-21 | sell | 360 | 106.87 | 5.95 |
为了计算运行中的“调整成本基数”,我有以下查询:
SELECT
SUM(CASE
WHEN T.Action in ("buy", "reinvest") THEN T.Quantity
WHEN Action = "sell" THEN -T.Quantity
END
) OVER (ORDER BY T.Date) AS quantity_balance,
SUM(CASE
WHEN T.Action in ("buy", "reinvest") THEN T.Quantity * T.Price + T.Commission
WHEN T.Action = "sell" THEN T.Quantity * ***(previous_total_acb / previous_quantity_balance)***[1]
END
) OVER (ORDER BY T.Date) AS total_acb
FROM transaction_t AS T;
此查询无效。因为伪代码previous_total_acb / previous_quantity_balance
指的是在该窗口函数中定义的列。
如何在 SQLite 中完成这项工作?
注意[1]:这里的previous_total_acb
是一个伪代码,我打算让它引用列本身,total_acb
。但是 sqlite 似乎不支持这种循环引用。
previous_quantity_balance
指的是同样由窗口函数创建的兄弟列quantity_balance
。这似乎也不起作用。
【问题讨论】:
编辑您的问题并解释什么是previous_total_acb 和previous_quantity_balance,更好地使用示例数据和预期结果。 【参考方案1】:您将使用 CTE(或子查询)来准备回溯计算,然后在最终查询中引用它们。 我不明白你的实际sql。这是一个可能没有意义的简化版本,只是简单地演示了结构:
第一个 CTE 只是给出一些值,在您的情况下,这些值来自您的表:
WITH TBL(d, a, q, p)
AS
(
SELECT * FROM (
VALUES (20210102, 'buy', 150, 110.21),
(20210121, 'buy', 380, 106.87),
(20210321, 'sell', 360, 104.33)
)
),
所以实际上你会从WITH
开始这里
SRC AS
(
SELECT d,
a,
q,
p,
q*p AS cost,
lag(q*p) OVER (ORDER BY d) AS prev_cost
FROM TBL
)
产生这个:
+--------+----+---+------+-------+---------+
|d |a |q |p |cost |prev_cost|
+--------+----+---+------+-------+---------+
|20210102|buy |150|110.21|16531.5|NULL |
|20210121|buy |380|106.87|40610.6|16531.5 |
|20210321|sell|360|104.33|37558.8|40610.6 |
+--------+----+---+------+-------+---------+
从那里您可以使用当前值和以前的值来生成计算字段
SELECT d, cost, cost-prev_cost AS diff FROM SRC ORDER BY d;
其中(正如我所说的只是为了演示,在这里没有实际意义)产生
+--------+-------+----------+
|d |cost |diff |
+--------+-------+----------+
|20210102|16531.5|NULL |
|20210121|40610.6|24079.1 |
|20210321|37558.8|-3051.79 |
+--------+-------+----------+
因此,将它们放在一起并假设您的数据存储在 TBL
中,它看起来像
WITH SRC AS
(
SELECT d,
a,
q,
p,
q*p AS cost,
lag(q*p) OVER (ORDER BY d) AS prev_cost
FROM TBL
)
SELECT d, cost, cost-prev_cost AS diff FROM SRC ORDER BY d;
您可以根据需要拥有尽可能多的 CTE 来准备“回溯”数据。不确定,但在您的最终查询中使用它之前,您可能需要至少一个中间准备 CTE 来计算 previous_total_acb
。
【讨论】:
这是相当丰富的信息,但我相信这是正确的方向。 为什么选择 CTE 而不是子查询? @JinghuiNiu 子查询应该可以正常工作。并不意味着听起来教条。 CTE 提供了一些可读性,并且可以被其他 CTE 引用,但如果编写正确,子查询也可以。在您的情况下,如果您需要嵌套子查询(不确定是否需要但可能),CTE 会更容易阅读。以上是关于在窗口函数中如何引用正在定义的列,即引用自身?的主要内容,如果未能解决你的问题,请参考以下文章