#sqlite #window-functions
Вопрос:
Для расчета скорректированной базы затрат (ACB) это текущая сумма либо Цены * Количества Комиссии, либо Предыдущего ACB/Доли * Количества, в зависимости от того, является ли это продажей или покупкой.
У меня есть следующая таблица с именем transaction_t
:
Дата | Экшен | Количество | Цена | Комиссия |
---|---|---|---|---|
2021-01-02 | Купить | 150 | 110.21 | 5.95 |
2021-01-21 | Купить | 360 | 106.87 | 5.95 |
2021-03-21 | Продать | 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
это псевдонимный код, я намерен ссылаться на сам столбец, the total_acb
. Но sqlite, похоже, не поддерживает такую обратную ссылку. Это previous_quantity_balance
относится к столбцу «брат», который также создается оконной функцией, the quantity_balance
. Похоже, это тоже не работает.
Комментарии:
1. Отредактируйте свой вопрос и объясните, что такое 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
, прежде чем вы сможете использовать его в своем окончательном запросе.
Комментарии:
1. Это довольно информативно, но я считаю, что это правильное направление.
2. Есть ли причина, по которой вы выбираете CTE вместо подзапросов?
3. Подзапрос @JinghuiNiu должен работать просто отлично. Это не должно было звучать догматично. CTE обеспечивают некоторую читабельность и могут ссылаться на другие CTE, но также могут и подзапросы, если они написаны правильно. В вашем случае, если бы вам требовалось вложить подзапросы (не уверен, что вам это нужно, но возможно), CTE было бы немного легче читать.