3

我正在尝试直接从数据库中检索 Open-high-low-close (OHLC) 图表的数据,这是您看到的股票图表。这是可能的,如果,如何?

我有一张这样的表(简化):

日期 | 价格 | 价格类型

每天都会创建一个记录,我将每月/每年报告一次,而不是每天报告用于股票。

我想查询这样的事情:

SELECT PriceType, MAX(Price) as High, MIN(Price) as Low, [Price of first item of the month] as Open, [Price of last item of the month] as Close GROUP BY PriceType, Year(Date), Month(Date )

要访问 SQL Server,我使用 LLBLGen,因此基于该技术的 anwser 会很棒,通用 SQL Server 也可以!

它是 SQL 2005,但 2008 也是一个选项。

谢谢。

4

2 回答 2

2

这似乎有效。很可能有一种不那么冗长的方法来做到这一点。

--create test data
CREATE TABLE #t
(priceDate DATETIME
,price MONEY
,priceType CHAR(1)
)

INSERT #t
      SELECT '20090101',100,'A'
UNION SELECT '20090102',500,'A'
UNION SELECT '20090103',20 ,'A'
UNION SELECT '20090104',25 ,'A'
UNION SELECT '20090105',28 ,'A'
UNION SELECT '20090131',150,'A'


UNION SELECT '20090201',501,'A'
UNION SELECT '20090203',21 ,'A'
UNION SELECT '20090204',26 ,'A'
UNION SELECT '20090205',29 ,'A'
UNION SELECT '20090228',151,'A'


UNION SELECT '20090101',100,'B'
UNION SELECT '20090102',500,'B'
UNION SELECT '20090103',20 ,'B'
UNION SELECT '20090104',25 ,'B'
UNION SELECT '20090105',28 ,'B'
UNION SELECT '20090131',150,'B'


UNION SELECT '20090201',501,'B'
UNION SELECT '20090203',21 ,'B'
UNION SELECT '20090204',26 ,'B'
UNION SELECT '20090205',29 ,'B'
UNION SELECT '20090228',151,'B'

--query
;WITH rangeCTE
AS
(
        SELECT  MIN(priceDate) minDate
                ,MAX(priceDate) maxDate
        FROM #t
)
,datelistCTE
AS
(
        SELECT CAST(CONVERT(CHAR(6),minDate,112) + '01' AS DATETIME) AS monthStart
               ,DATEADD(mm,1,CAST(CONVERT(CHAR(6),minDate,112) + '01' AS DATETIME)) -1 AS monthEnd
               ,1 AS monthID
        FROM rangeCTE

        UNION ALL

        SELECT DATEADD(mm,1,monthStart)
               ,DATEADD(mm,2,monthStart) - 1
               ,monthID + 1
        FROM datelistCTE
        WHERE monthStart <= (SELECT maxDate FROM rangeCTE)
)
,priceOrderCTE
AS
(
        SELECT * 
               ,ROW_NUMBER() OVER (PARTITION BY monthID, priceType
                                   ORDER BY priceDate
                                   ) AS rn1
               ,ROW_NUMBER() OVER (PARTITION BY monthID, priceType
                                   ORDER BY priceDate DESC
                                   ) AS rn2
               ,ROW_NUMBER() OVER (PARTITION BY monthID, priceType
                                   ORDER BY price DESC
                                   ) AS rn3                                   
               ,ROW_NUMBER() OVER (PARTITION BY monthID, priceType
                                   ORDER BY price 
                                   ) AS rn4
        FROM datelistCTE AS d
        JOIN #t          AS t
        ON t.priceDate BETWEEN d.monthStart AND d.monthEnd
        WHERE monthStart <= (SELECT maxDate FROM rangeCTE)
)
SELECT o.MonthStart
       ,o.priceType
       ,o.Price AS opening
       ,c.price AS closing
       ,h.price AS high
       ,l.price AS low
FROM priceOrderCTE AS o
JOIN priceOrderCTE AS c
ON   c.priceType = o.PriceType 
AND  c.monthID   = o.MonthID
JOIN priceOrderCTE AS h
ON   h.priceType = o.PriceType 
AND  h.monthID   = o.MonthID
JOIN priceOrderCTE AS l
ON   l.priceType = o.PriceType 
AND  l.monthID   = o.MonthID
WHERE o.rn1 = 1
AND   c.rn2 = 1
AND   h.rn3 = 1
AND   l.rn4 = 1
于 2009-09-29T11:47:59.363 回答
1

这是我写的一个小查询,似乎一次可以很好地工作一段时间。您需要做的就是评论选择的 DATEPARTS 以获得您正在寻找的时间跨度。或者,您可以针对不同的时间跨度制作多个视图。基础数据表也使用 Bid Ask 分时样式数据。如果您使用中间价或最后价,则可以从选择中消除案例陈述。

Select 
tmp.num,
rf.CurveName, 
rf.Period as Period,
CASE WHEN (tmp2.Bid is null or tmp2.Ask is null) then isnull(tmp2.Bid,0)+isnull(tmp2.Ask,0) else (tmp2.Bid+tmp2.Ask)/2 end as [Open],
tmp.Hi,
tmp.Lo,
CASE WHEN (rf.Bid is null or Rf.Ask is null) then isnull(rf.Bid,0)+isnull(rf.Ask,0) else (rf.Bid+rf.Ask)/2 end as [Close],
tmp.OpenDate,
tmp.CloseDate,
tmp.yr,
tmp.mth,
tmp.wk,
tmp.dy,
tmp.hr
from BidAsk rf inner join 
(SELECT count(CurveName)as num,CurveName,
Period,
max(CASE WHEN (Bid is null or Ask is null) then isnull(Bid,0)+isnull(Ask,0) else (Bid+Ask)/2 end) as Hi,
min(CASE WHEN (Bid is null or Ask is null) then isnull(Bid,0)+isnull(Ask,0) else (Bid+Ask)/2 end) as Lo, 
max(CurveDateTime) as CloseDate, min(CurveDateTime) as OpenDate,
    DATEPART(year, CurveDateTime) As yr,  
    DATEPART(month, CurveDateTime) As mth,  
    DATEPART(week, CurveDateTime) As wk,  
    DATEPART(Day, CurveDateTime) as dy,
    DATEPART(Hour, CurveDateTime) as hr  
    --DATEPART(minute, CurveDateTime) as mnt 
FROM  
    BidAsk 
GROUP BY  
CurveName,Period,
    DATEPART(year, CurveDateTime),  
    DATEPART(month, CurveDateTime),  
    DATEPART(week, CurveDateTime),
    DATEPART(Day, CurveDateTime) ,
    DATEPART(Hour, CurveDateTime)
    --DATEPART(minute, CurveDateTime) 
) tmp on 
tmp.CurveName=rf.CurveName and 
tmp.CloseDate=rf.CurveDateTime and 
tmp.Period=rf.Period

inner join BidAsk tmp2 on 
tmp2.CurveName=rf.CurveName and 
tmp2.CurveDateTime=tmp.Opendate and 
tmp2.Period=rf.Period

ORDER BY  
CurveName,Period,tmp.yr,tmp.mth
    --DATEPART(year, CurveDateTime), 
    --DATEPART(month, CurveDateTime)  
    --DATEPART(day, CurveDateTime),  
    --DATEPART(Hour, CurveDateTime), 
    --DATEPART(minute, CurveDateTime) ) 
于 2012-09-27T13:42:06.067 回答