2012-03-13 18 views
3

我有以下問題需要解決,而且我似乎無法提出一個算法,從來沒有想到一個實際的解決方案。計數有序數據

我具有類似結構的表/數據作爲以下內容,其中的ID並不總是按順序對同一定單/ 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 

我需要從該數據中提取的信息是下列:

  • 有多少個連續的行?從最近(如PriceDateTime中記錄)向下計數,查看ClosePrice?

IE:對於當前的例子中,答案是2. ClosePrice(行1)= 2901.71比ClosePrice(第3行)= 2909.64大於ClosePrice(行2)= 2901.67但較低。因此,從最近的價格來看,我們有2排「走向同一個方向」。

當然,我必須通過很多其他名稱來做到這一點,所以速度非常重要。 PS:謝謝大家的幫助,我在構建最終程序時從所有答案中獲得靈感。你們都很親切!

+0

如果第三排有'ClosePrice = 2901.69'(即大於第二行但小於第一行),它會被計算在內嗎?如果它是「2901.67」(與第二行相同)呢? – 2012-03-13 16:24:31

+0

不,它不會,因爲它會打破序列,比第二個更高。整個想法是將價格從一個時期持續增加/下降,並顯示持續增長持續了多久。 如果它是相等的,它就是重要的。 – user1158959 2012-03-14 12:24:02

回答

2

嘗試這種情況:(I已經簡化我使用,因爲它僅需要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 

我試過評論答案,因爲我去解釋。如果有什麼不從註釋清楚,讓我知道,我會試着解釋進一步

+0

非常感謝,它工作得很好。不知道這些CTE的存在/使用,從現在開始肯定會使用它們! – user1158959 2012-03-14 12:14:37

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 
+0

非常感謝,我會試試這個,讓你知道結果! – user1158959 2012-03-13 14:26:21

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 
+0

非常感謝,我會試試這個,讓你知道結果! – user1158959 2012-03-13 14:26:14

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 
+0

非常感謝,我會試試這個,讓你知道結果! – user1158959 2012-03-13 14:25:57