У меня есть две таблицы. Один с ценами на акции и один с номерами акций для каждой акции. Я хочу объединить две таблицы и рассчитать рыночную капитализацию для каждой акции.
Вот примерная таблица данных с 3-мя запасами, которые я создал, чтобы повторить проблему.
CREATE TABLE stock_prices (country_exchange_code VARCHAR(2), stock_code VARCHAR(4), date DATE, close FLOAT, PRIMARY KEY (country_exchange_code,stock_code,date));
INSERT INTO stock_prices VALUES
("T", "1301", '2019-10-29', 75.2),
("T", "1301", '2019-10-30', 76.6),
("T", "1301", '2019-10-31', 77.6),
("T", "1301", '2019-11-01', 77.2),
("T", "1332", '2019-10-29', 52.5),
("T", "1332", '2019-10-30', 49.7),
("T", "1332", '2019-10-31', 50.8),
("T", "1332", '2019-11-01', 50.4),
("T", "1333", '2019-10-29', 13.9),
("T", "1333", '2019-10-30', 13.8),
("T", "1333", '2019-10-31', 14.3),
("T", "1333", '2019-11-01', 14.4);
CREATE TABLE stock_shares (country_exchange_code VARCHAR(2), stock_code VARCHAR(4), Num_Shares INT, PRIMARY KEY (country_exchange_code,stock_code));
INSERT INTO stock_shares VALUES
("T", "1301", 241587962),
("T", "1332", 369875187),
("T", "1333", 958621587);
Следующий запрос объединяет две таблицы с кодом страны и кодом акции, а затем перечисляет количество акций и цену последнего закрытия, которые являются входными данными для рассчитанного значения рыночной капитализации. Я использую оконную функцию last_value для получения цены последнего закрытия.
SELECT Stock_Code, Date, Num_Shares,
last_value(Close) OVER (PARTITION BY Stock_Code ORDER BY Date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS Last_Close,
Num_Shares * last_value(Close) OVER (PARTITION BY Stock_Code ORDER BY Date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS Mkt_Cap
FROM stock_prices LEFT JOIN stock_shares USING (Country_Exchange_Code, Stock_Code)
WHERE Country_Exchange_Code = 'T' AND Date >= '2019-10-29'
ORDER BY Stock_Code, Date;
Это работает, как и ожидалось, и дает следующий результат:
Результат 1:
Далее я хочу использовать инструкцию DISTINCT, чтобы получить только одну строку для каждой акции. Однако сначала мне нужно избавиться от всех столбцов, кроме Stock_Code и Mkt_Cap. Это где проблема возникает. Когда я исключаю столбец Last_Close из оператора select:
SELECT Stock_Code, Date, Num_Shares,
Num_Shares * last_value(Close) OVER (PARTITION BY Stock_Code ORDER BY Date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS Mkt_Cap
FROM stock_prices LEFT JOIN stock_shares USING (Country_Exchange_Code, Stock_Code)
WHERE Country_Exchange_Code = 'T' AND Date >= '2019-10-29'
ORDER BY Stock_Code, Date;
, я получаю эти неожиданные значения NULL, появляющиеся в первой строке каждого раздела фондового кода.
Результат 2:
Почему это происходит? В моих таблицах нет пустых значений, и, как мы видели из первого результата, все данные, необходимые для вычисления Mkt_Cap, есть.
Дополнительная информация. Когда я удаляю Date и / или Num_Shares из оператора SELECT, проблем не возникает. Проблема заключается только в удалении функции last_value.
Интересно, что когда предложение WHERE будет удалено, проблема исчезнет. Я не могу понять, как это влияет на результат, потому что в моем небольшом примере это предложение WHERE даже ничего не делает. Все мои данные имеют Country_Exchange_Code = 'T' и имеют дату> = '2019-10-29'. Но в моем реальном наборе данных с миллионами строк это предложение WHERE крайне необходимо. Поэтому удаление предложения WHERE не является решением.