[英]Calculating from self-join
我有股票報價器符號的值和日期的列表,想計算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;
更新:
完全結合@ Hogan的建議...並對其進行測試。 :)這EXPLAIN
要簡單許多了,而應該是一個更好的表演。
同樣,假定ANSI_QUOTES
行為:
SELECT tq.sym AS sym,
(100*(alast.adj_nav - afirst.adj_nav)/afirst.adj_nav) AS quarterly_returns
FROM
(SELECT symbol_header_id AS sym, -- find first/last traded day ("ftd", "ltd")
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 -- JOIN for ADJ_NAV on first traded day
ON tq.sym = afirst.symbol_header_id
AND
tq.ftd = afirst."date"
JOIN symbol_details alast -- JOIN for ADJ_NAV on last traded day
ON tq.sym = alast.symbol_header_id
AND
tq.ltd = alast."date"
原版的:
假設SET SESSION sql_mode = 'ANSI_QUOTES'
,請嘗試以下操作:
SELECT tq.sym AS sym,
(100*(adj_end - adj_begin)/adj_begin) 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
-- Second, determine adjusted NAV for "ftd" per symbol (see WHERE)
(SELECT symbol_header_id AS sym,
"date" AS adate,
adj_nav AS adj_begin
FROM symbol_details) afirst
ON afirst.sym = tq.sym
JOIN
-- Finally, determine adjusted NAV for "ltd" per symbol (see WHERE)
(SELECT symbol_header_id AS sym,
"date" AS adate,
adj_nav AS adj_end
FROM symbol_details) alast
ON alast.sym = tq.sym
WHERE
afirst.adate = tq.ftd
AND
alast.adate = tq.ltd;
從以下查詢中展開最后一個子查詢的示例:
(注意-我沒有測試)
SELECT tq.sym AS sym,
(100*(alast.adj_nav - adj_begin)/adj_begin) 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
-- Second, determine adjusted NAV for "ftd" per symbol (see WHERE)
(SELECT symbol_header_id AS sym,
"date" AS adate,
adj_nav AS adj_begin
FROM symbol_details) afirst
ON afirst.sym = tq.sym
-- Finally, determine adjusted NAV for "ltd" per symbol (see WHERE)
LEFT JOIN symbol_details alast ON tq.sym = alast.symbol_header_id AND tg.ltd = alast."date"
WHERE
afirst.adate = tq.ftd
您確定在查詢中使用的是GROUP BY ... ASC嗎? GROUP BY將那些滿足某些條件的行分組,並且使用ASC / DESC沒有意義。 順便說一句,在您的情況下,您的標准是symbol_header_id列的相等性,假設“ id”表示它是鍵,則有效地使組由單個行組成。
無論如何,如果您的組是真正的組,則可能會遇到問題,因為您不僅要選擇分組屬性和聚合函數,還要選擇其他一些屬性。 在這種情況下,它們的價值不可預測。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.