当前位置: 首页 > 面试题库 >

查找列值连续增加的行

周和安
2023-03-14
问题内容

我有一个sql表,用于存储股票的每日价格。收市后每天都会插入新的记录。我想找到价格连续上涨的股票。

该表有很多列,但这是相关的子集:

quoteid     stockid      closeprice     createdate
--------------------------------------------------
    1           1               1       01/01/2012
    2           2              10       01/01/2012
    3           3              15       01/01/2012

    4           1               2       01/02/2012
    5           2              11       01/02/2012
    6           3              13       01/02/2012

    7           1               5       01/03/2012
    8           2              13       01/03/2012
    9           3              17       01/03/2012

   10           1               7       01/04/2012
   11           2              14       01/04/2012
   12           3              18       01/04/2012

   13           1               9       01/05/2012
   14           2              11       01/05/2012
   15           3              10       01/05/2012

quoteid列是主键。

在表中,股票编号1的收盘价每天都在增加。股票ID 3的波动很大,股票ID 2的价格在最后一天下跌。

我正在寻找这样的结果:

stockid     Consecutive Count (CC)
----------------------------------
    1                5
    2                4

如果您可以获得带有连续条纹的日期的输出,那就更好了:

stockid     Consecutive Count (CC)      StartDate      EndDate
---------------------------------------------------------------
    1                5                 01/01/2012    01/05/2012
    2                4                 01/01/2012    01/04/2012

StartDate价格开始上涨EndDate的时间,牛市实际上结束的时间。

我认为这不是一个容易的问题。我在这里查看了其他帖子,这些帖子也处理了这种连续的情况,但是它们不符合我的需求。如果您知道有任何与我相似的帖子,请告诉我。


问题答案:

无论如何,将它放在增加每张纸的行数方面quoteid是有帮助的(实际值在这里并不是真的有帮助)。 捕获 的天数(在此表中)是最简单的-
如果您想要其他内容(例如仅工作日,忽略周末/节假日等),则它会涉及更多;您可能需要一个日历html" target="_blank">文件。如果您还没有索引,您将要在[
stockidcreatedate]上建立索引

WITH StockRow AS (SELECT stockId, closePrice, createdDate,
                         ROW_NUMBER() OVER(PARTITION BY stockId 
                                           ORDER BY createdDate) rn
                  FROM Quote),

     RunGroup AS (SELECT Base.stockId, Base.createdDate,
                         MAX(Restart.rn) OVER(PARTITION BY Base.stockId
                                              ORDER BY Base.createdDate) groupingId
                  FROM StockRow Base
                  LEFT JOIN StockRow Restart
                         ON Restart.stockId = Base.stockId
                            AND Restart.rn = Base.rn - 1
                            AND Restart.closePrice > Base.closePrice)

SELECT stockId, 
       COUNT(*) AS consecutiveCount, 
       MIN(createdDate) AS startDate, MAX(createdDate) AS endDate
FROM RunGroup
GROUP BY stockId, groupingId
HAVING COUNT(*) >= 3
ORDER BY stockId, startDate

从提供的数据中得出以下结果:

Increasing_Run
stockId   consecutiveCount  startDate    endDate
===================================================
1         5                 2012-01-01   2012-01-05
2         4                 2012-01-01   2012-01-04
3         3                 2012-01-02   2012-01-04

[SQL Fiddle Example](http://sqlfiddle.com/#!6/b1e78/4/0)
(提琴还有一个多次运行的示例)

该分析将忽略所有差距,正确匹配所有运行(下次开始运行正运行时)。

那么这是怎么回事?

StockRow AS (SELECT stockId, closePrice, createdDate,
                    ROW_NUMBER() OVER(PARTITION BY stockId 
                                      ORDER BY createdDate) rn
             FROM Quote)

此CTE用于一个目的:我们需要一种方法来查找下一行/上一行,因此首先我们按(日期)的顺序对每一行进行编号…

RunGroup AS (SELECT Base.stockId, Base.createdDate,
                    MAX(Restart.rn) OVER(PARTITION BY Base.stockId
                                         ORDER BY Base.createdDate) groupingId
             FROM StockRow Base
             LEFT JOIN StockRow Restart
                    ON Restart.stockId = Base.stockId
                       AND Restart.rn = Base.rn - 1
                           AND Restart.closePrice > Base.closePrice)

…然后根据索引将它们加入。如果最后得到的是带有LAG()/的东西LEAD(),那么使用它们代替几乎可以肯定是一个更好的选择。不过,这里有一件关键的事情-
仅当行 不按顺序 (小于前一行)时才进行匹配。否则,该值最终会是null(使用LAG(),您需要使用类似CASEafter
after的东西来实现此目的)。您得到一个看起来像这样的临时集:

B.rn   B.closePrice   B.createdDate  R.rn   R.closePrice   R.createdDate  groupingId
1      15             2012-01-01     -      -              -              -
2      13             2012-01-02     1      15             2012-01-01     1
3      17             2012-01-03     -      -              -              1
4      18             2012-01-04     -      -              -              1
5      10             2012-01-05     4      18             2012-01-04     4

…因此,Restart仅当上一个大于“当前”行时才有值。MAX()到目前为止,在窗口函数中使用的值已达到最大值……这null是最低值,它会导致所有其他行的行索引都保留下来,直到发生另一个不匹配(给出新值)为止。至此,我们基本上有了间隔和孤岛查询的中间结果,可以进行最终汇总了。

SELECT stockId, 
       COUNT(*) AS consecutiveCount, 
       MIN(createdDate) AS startDate, MAX(createdDate) AS endDate
FROM RunGroup
GROUP BY stockId, groupingId
HAVING COUNT(*) >= 3
ORDER BY stockId, startDate

查询的最后一部分是获取运行的开始日期和结束日期,并计算这些日期之间的条目数。如果日期计算有些复杂,则可能需要在此时进行。在GROUP BY被示出的几个合法实例中的一个 包括在列SELECT子句。该HAVING子句用于消除“过短”的运行。



 类似资料:
  • 假设我有一个如下所示的数据框,我需要识别每行,其中一个或多个缺失值 (NA) 后跟至少一个有效值(任何数字)。你可以帮我吗?

  • 问题内容: 对于这个例子说,我有两个字段的表,和。 该表具有以下数据 我想回来 我想返回的结果是每个区域递增连续值的最长长度。对于。 我将如何在MS Sql 2005上执行此操作? 问题答案: 一种方法是使用遍历每一行的递归CTE。如果该行符合条件(增加同一区域的订单号),则将链长增加一。如果没有,则启动一个新链: SQL Fiddle的实时示例。 另一种方法是使用查询查找“中断”,即以相同区域的

  • 问题内容: 如果我有串,我要检查,如果它作为一个连续存在 串 中,我可以使用: 在非连续子 序列 的情况下,我可以使用什么?例: 问题答案: 我不知道是否有内置功能,但是手动操作相当简单

  • 问题内容: 我有带有示例数据的下表: 桌子: 样本数据: 预期结果 : 注意 :我试图找出节点的连通性以及节点之间的长度之和。 我尝试以下查询相同: 我的尝试 : 无法获得预期的结果。 问题答案: 我很确定您需要递归CTE。但是,您的样本结果没有任何意义。 以下内容基本上可以满足您的要求: 这是一个。

  • 问题内容: 我需要查询方面的帮助。 我有这个简单的表: 看起来像这样: 我想为给定的readVal获得最后的连续行: 在上面的示例中将是: id:3 for readVal = 2 id:8 for readVal = 3 我尝试了以下查询: 只要该系列中没有缺失的ID,它就可以工作。在上面的示例中,编号4缺失,查询将不会返回预期的结果。 谢谢! 问题答案: 返回: 对于还需要最后一行的情况: 返

  • 问题内容: 我正在尝试使用蒙特卡洛算法查找下周的乐透数字包含连续数字的概率。我认为对数字进行排序可能会使实际查找连续项更加容易,但是在网上搜索了很多之后,似乎并没有什么真正可以帮助我寻找所需内容的信息 到目前为止,这就是我所知道的,我知道我将使用计数器来查找百万结果中的连续数,但实际上我只是为如何真正找到连续数而烦恼 问题答案: 首先我读错了问题,对不起,答案很抱歉! 好吧,让我们分手吧。那么首先