我有以下问题要解决,我似乎无法想出一个算法,从来没有找到实际的解决方案。
我有一个类似于以下结构/数据的表,其中ID对于相同的Ticker / QuouteType并不总是按顺序排列:
ID Ticker PriceDateTime QuoteType OpenPrice HighPrice LowPrice ClosePrice
------- ------ ---------------- --------- --------- --------- -------- ----------
2036430 ^COMP 2012-02-10 20:50 95/Minute 2901.57 2905.04 2895.37 2901.71
2036429 ^COMP 2012-02-10 19:15 95/Minute 2909.63 2910.98 2899.95 2901.67
2036428 ^COMP 2012-02-10 17:40 95/Minute 2905.9 2910.27 2904.29 2909.64
2036427 ^COMP 2012-02-10 16:05 95/Minute 2902 2908.29 2895.1 2905.89
2036426 ^COMP 2012-02-09 21:00 95/Minute 2926.12 2928.01 2925.53 2927.21
我需要从这些数据中提取的信息如下:
IE:对于当前示例,答案应该是2. ClosePrice(第1行)= 2901.71,它大于ClosePrice(第2行)= 2901.67但低于ClosePrice(第3行)= 2909.64。因此,从最近的价格回顾,我们有两行“走向同一个方向”。
当然,我必须通过许多其他名称来做到这一点,所以速度非常重要。
PS:谢谢大家的帮助,在构建最终程序时,我从所有答案中汲取灵感。你们都很善良!
答案 0 :(得分:2)
试试这个:(我已经简化了我正在使用的测试数据,因为它只需要2列来演示逻辑)。
CREATE TABLE #Test (PriceDateTime DATETIME, ClosePrice DECIMAL(6, 2))
INSERT #Test VALUES
('20120210 20:50:00.000', 2901.71),
('20120210 19:15:00.000', 2901.67),
('20120210 17:40:00.000', 2900.64),
('20120210 16:05:00.000', 2905.89),
('20120209 21:00:00.000', 2927.21)
-- FIRST CTE, JUST DEFINES A VIEW GIVING EACH ENTRY A ROW NUMBER
;WITH CTE AS
( SELECT *,
ROW_NUMBER() OVER(ORDER BY PriceDateTime DESC) [RowNumber]
FROM #Test
),
-- SECOND CTE, ASSIGNES EACH ENTRY +1 OR -1 DEPENDING ON HOW THE VALUE HAS CHANGED COMPARED TO THE PREVIOUS RECORD
CTE2 AS
( SELECT a.*, SIGN(a.ClosePrice - b.ClosePrice) [Movement]
FROM CTE a
LEFT JOIN CTE b
ON a.RowNumber = b.RowNumber - 1
),
-- THIRD CTE, WILL LOOP THROUGH THE DATA AS MANY TIMES AS POSSIBLE WHILE THE PREVIOUS ENTRY HAS THE SAME "MOVEMENT"
CTE3 AS
( SELECT *, 1 [Recursion]
FROM CTE2
UNION ALL
SELECT a.PriceDateTime, a.ClosePrice, a.RowNumber, a.Movement, b.Recursion + 1
FROM CTE2 a
INNER JOIN CTE3 b
ON a.RowNumber = b.RowNumber - 1
AND a.Movement = b.Movement
)
SELECT MAX(Recursion) + 1 -- ADD 1 TO THE RECORD BECAUSE THERE WILL ALWAYS BE AT LEAST TWO ROWS
FROM CTE3
WHERE RowNumber = 1 -- LATEST ENTRY
DROP TABLE #Test
我试着回答这个问题来解释。如果评论中有任何不明确的地方,请告诉我,我会尝试进一步解释
答案 1 :(得分:1)
下面的解决方案应该足够有效,但如果ID序列中存在间隙,它将失败。
如果重要的话,请更新您的主题。
DECLARE @t TABLE (
ID INT,
ClosePrice DECIMAL(10, 5)
)
INSERT @t (ID, ClosePrice)
VALUES (2036430, 2901.71), (2036429, 2901.67), (2036428, 2909.64), (2036427, 2905.89), (2036426, 2927.21)
;WITH CTE AS (
SELECT TOP 1 ID, ClosePrice, 1 AS lvl
FROM @t
ORDER BY ID DESC
UNION ALL
SELECT s.ID, s.ClosePrice, CTE.lvl + 1
FROM @t AS s
INNER JOIN CTE
ON s.ID = CTE.ID - 1 AND s.ClosePrice < CTE.ClosePrice
)
SELECT MAX(lvl) AS answer
FROM CTE
答案 2 :(得分:0)
我自己加入您的数据(主键/订购密钥为+1),然后使用简单的CASE跟踪更改(假设我已正确理解您的问题)。
例如:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[tbl_NumericSequence](
[ID] [int] NULL,
[Value] [int] NULL
) ON [PRIMARY]
GO
INSERT [dbo].[tbl_NumericSequence] ([ID], [Value]) VALUES (1, 1)
GO
INSERT [dbo].[tbl_NumericSequence] ([ID], [Value]) VALUES (2, 2)
GO
INSERT [dbo].[tbl_NumericSequence] ([ID], [Value]) VALUES (3, 3)
GO
INSERT [dbo].[tbl_NumericSequence] ([ID], [Value]) VALUES (4, 2)
GO
INSERT [dbo].[tbl_NumericSequence] ([ID], [Value]) VALUES (5, 1)
GO
INSERT [dbo].[tbl_NumericSequence] ([ID], [Value]) VALUES (6, 3)
GO
INSERT [dbo].[tbl_NumericSequence] ([ID], [Value]) VALUES (7, 3)
GO
INSERT [dbo].[tbl_NumericSequence] ([ID], [Value]) VALUES (8, 8)
GO
INSERT [dbo].[tbl_NumericSequence] ([ID], [Value]) VALUES (9, 1)
GO
WITH RawData ( [ID], [Value] )
AS ( SELECT [ID] ,
[Value]
FROM [Test].[dbo].[tbl_NumericSequence]
)
SELECT RawData.ID ,
RawData.Value ,
CASE WHEN RawDataLag.Value = RawData.Value THEN 'No Change'
WHEN RawDataLag.Value > RawData.Value THEN 'Down'
WHEN RawDataLag.Value < RawData.Value THEN 'Up'
END AS Change
FROM RawData
LEFT OUTER JOIN RawData RawDataLag ON RawData.ID = RawDataLag.iD + 1
ORDER BY RawData.ID ASC
答案 3 :(得分:0)
我会用递归公用表表达式来处理它:
CREATE TABLE #MyTable (ID INT, ClosePrice MONEY)
INSERT INTO #MyTable ( ID, ClosePrice )
VALUES (2036430,2901.71),
(2036429,2901.67),
(2036428,2909.64),
(2036427,2905.89),
(2036426,2927.21)
WITH CTE AS (
SELECT TOP 1 id, closeprice, 1 Consecutive
FROM #MyTable
ORDER BY id DESC
UNION ALL
SELECT A.id, A.closeprice, CASE WHEN A.ClosePrice < B.ClosePrice THEN Consecutive+1 ELSE 1 END
FROM #MyTable A INNER JOIN cte B ON A.ID=B.id -1
)
SELECT * FROM cte
--OR to just get the max consecutive
--select max(Consecutive) from cte
DROP TABLE #MyTable