Подсчет упорядоченных данных - PullRequest
3 голосов
/ 13 марта 2012

Мне нужно решить следующую проблему, и я пока не могу придумать алгоритм, не говоря уже о реальном решении.

У меня есть таблица с аналогичной структурой / данными, как показано ниже, где идентификаторы не всегда в последовательности для одного и того же тикера / 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 (строка 2) = 2901,67, но ниже, чем ClosePrice (строка 3) = 2909,64. Таким образом, оглядываясь на последнюю цену, мы имеем 2 ряда, которые «идут в одном направлении».

Конечно, я должен сделать это для многих других имен, поэтому скорость очень важна.

PS: Спасибо всем за вашу помощь, я черпал вдохновение во всех ваших ответах при построении финальной процедуры. Вы все очень добры!

Ответы [ 4 ]

2 голосов
/ 13 марта 2012

Попробуйте это: (Я упростил данные теста, которые я использую, поскольку для демонстрации логики требуются только 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 голос
/ 13 марта 2012

Решение, приведенное ниже, должно быть достаточно эффективным, но оно не даст результатов, если в последовательности идентификаторов есть пробелы.

Пожалуйста, обновите вашу тему, если это точка.

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 голосов
/ 13 марта 2012

Я бы подошел к этому с помощью рекурсивных общих табличных выражений:

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 голосов
/ 13 марта 2012

Я бы присоединил ваши данные к себе (с +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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...