【发布时间】:2010-12-19 07:38:25
【问题描述】:
我有一个股票代码符号的值和日期列表,并想在 SQL 中计算季度回报。
CREATE TABLE `symbol_details` (
`symbol_header_id` INT(11) DEFAULT NULL,
`DATE` DATETIME DEFAULT NULL,
`NAV` DOUBLE DEFAULT NULL,
`ADJ_NAV` DOUBLE DEFAULT NULL)
对于可以正常工作的固定季度开始和结束日期:
set @quarterstart='2008-12-31';
set @quarterend='2009-3-31';
select sha, (100*(aend-abegin)/abegin) as q1_returns from
(select symbol_header_id as sha, ADJ_NAV as abegin from symbol_details
where date=@quarterstart) as a,
(select symbol_header_id as she, ADJ_NAV as aend from symbol_details
where date=@quarterend) as b
where sha=she;
这会计算所有品种的所有季度回报。有时季度末是非交易日,或者股票停止营业,所以我想获得最接近季度开始和结束日期的开始和结束日期。
解决方案是通过某种 GROUP BY 语句以某种方式仅获取每个 symbol_header_id 的一个开始和一个结束季度值,例如 (1)
SET @quarterstart = '2009-03-01';
SET @quarterend = '2009-4-31';
SELECT symbol_header_id, DATE, ADJ_NAV AS aend FROM symbol_details
WHERE
DATE BETWEEN @quarterstart AND @quarterend
AND symbol_header_id BETWEEN 18540 AND 18550
GROUP BY symbol_header_id asc;
这为每个 symbol_header_id 值提供了最接近季度开始日期的 ADJ_NAV 值。
最后,(2)
SET @quarterstart = '2008-12-31';
SET @quarterend = '2009-3-31';
SELECT sh1, a.date, b.date, aend, abegin,
(100*(aend-abegin)/abegin) AS quarter_returns FROM
(SELECT symbol_header_id sh1, DATE, ADJ_NAV AS abegin FROM symbol_details
WHERE
DATE BETWEEN @quarterstart AND @quarterend
GROUP BY symbol_header_id DESC) a,
(SELECT symbol_header_id sh2, DATE, ADJ_NAV AS aend FROM symbol_details
WHERE
DATE BETWEEN @quarterstart AND @quarterend
GROUP BY symbol_header_id ASC) b
WHERE sh1 = sh2;
应该计算每个品种的季度收益。
不幸的是,这不起作用。出于某种原因,当我像 (1) 那样限制 ID 时,使用了正确的开始日期和结束日期,但是当删除“AND symbol_header_id BETWEEN 18540 AND 18550”语句时,会出现相同的开始日期和结束日期。为什么????
展开 JOIN 的答案是:
SET @quarterstart = '2008-12-31';
SET @quarterend = '2009-3-31';
SELECT tq.sym AS sym,
(100*(alast.adj_nav - afirst.adj_nav)/afirst.adj_nav) AS quarterly_returns
FROM
-- First, determine first traded days ("ftd") and last traded days
-- ("ltd") in this quarter per symbol
(SELECT symbol_header_id AS sym,
MIN(DATE) AS ftd,
MAX(DATE) AS ltd
FROM symbol_details
WHERE DATE BETWEEN @quarterstart AND @quarterend
GROUP BY 1) tq
JOIN symbol_details afirst
-- Second, determine adjusted NAV for "ftd" per symbol (see WHERE)
ON afirst.DATE BETWEEN @quarterstart AND @quarterend
AND afirst.symbol_header_id = tq.sym
JOIN
-- Finally, determine adjusted NAV for "ltd" per symbol (see WHERE)
symbol_details alast
ON alast.DATE BETWEEN @quarterstart AND @quarterend
AND alast.symbol_header_id = tq.sym
WHERE
afirst.date = tq.ftd
AND
alast.date = tq.ltd;
【问题讨论】: