SQL查询查找x行前进最高值,中间没有较低的值

时间:2014-07-24 13:04:12

标签: sql sql-server

我有一张左2列的表格。 我试图基于某种逻辑来实现第3列。

逻辑:如果我们采取日期1/1并且进一步达到最高分,那么在分数下降之前进一步的分数将是3/1。得分为12.因此,作为HighestAchievedScore,我们将检索12为1/1。等等。

如果我们处于下一个得分下降的日期,我的最高成绩将是我的下一个得分。就像你在2014年3月1日看到的那样

date        score   HighestAchieveScore
1/01/2014   10      12
2/01/2014   11      12
3/01/2014   12      10
4/01/2014   10      11
5/01/2014   11      9
6/01/2014   9       8
7/01/2014   8       9
8/01/2014   9       9

我希望我能够清楚地解释清楚。 非常感谢您解决问题的所有输入。

4 个答案:

答案 0 :(得分:1)

让我们制作一些测试数据:

DECLARE @Score TABLE
(
    ScoreDate DATETIME,
    Score INT
)

INSERT INTO @Score
VALUES
('01-01-2014',   10),
('01-02-2014',   11),
('01-03-2014',   12),
('01-04-2014',   10),
('01-05-2014',   11),
('01-06-2014',   9),
('01-07-2014',   8),
('01-08-2014',   9);

现在我们要对行进行编号,然后链接到下一行,看看我们是否还在上升

WITH ScoreRows AS
(
    SELECT 
    s.ScoreDate,
    s.Score,
    ROW_NUMBER() OVER (ORDER BY ScoreDate) RN
    FROM @Score s
),
ScoreUpDown AS
(
    SELECT p.ScoreDate,
        p.Score,
        p.RN,
        CASE WHEN p.Score < n.Score THEN 1 ELSE 0 END GoingUp,
        ISNULL(n.Score, p.Score) NextScore
    FROM ScoreRows p
    LEFT JOIN ScoreRows n
        ON n.RN = p.RN + 1
)

我们以递归方式查找下一行的数据,然后将该值作为我们仍在上升的行的最大值。否则,我们将得分用于下一行。

SELECT 
    s.ScoreDate,
    s.Score,
    CASE WHEN s.GoingUp = 1 THEN d.Score ELSE s.NextScore END Test
FROM ScoreUpDown s
OUTER APPLY
(
    SELECT TOP 1 * FROM ScoreUpDown d 
    WHERE d.ScoreDate > s.ScoreDate
        AND GoingUp = 0
) d;

输出:

ScoreDate   Score   Test
2014-01-01 00:00:00.000 10  12
2014-01-02 00:00:00.000 11  12
2014-01-03 00:00:00.000 12  10
2014-01-04 00:00:00.000 10  11
2014-01-05 00:00:00.000 11  9
2014-01-06 00:00:00.000 9   8
2014-01-07 00:00:00.000 8   9
2014-01-08 00:00:00.000 9   9

答案 1 :(得分:0)

我不确定这会起作用......但这是一般概念。

自我加入A.Date&lt; B.Date获得最大分数,但在CTE中指定的rowID上使用coalesce和第3个self连接来确定分数是否在下一个记录中下降,如果它确实合并了该分数,否则使用最大分数。 / p>

需要测试,但必须设置一个小提琴这样做..

WITH CTE as
(SELECT Date, Score, ROW_NUMBER() OVER(ORDER BY A.Date ASC) AS Row FROM tableName)
SELECT A.Date, A.Score, coalesce(c.score, Max(A.Score)) as HighestArchievedScore
FROM CTE A
LEFT JOIN CTE B
 on A.Date < B.Date
LEFT JOIN CTE C
 on A.Row+1=B.Row
and A.Score > C.Score
GROUP BY A.DATE, 
         A.SCORE 

答案 2 :(得分:0)

假设您想要计算第三列,您可以像这样创建表(或将列添加到现有表中),使用function来确定第三列的值:

Create Function dbo.fnGetMaxScore(@Date Date)
Returns Int
As Begin
    Declare @Ret Int

    Select  @Ret = Max(Score)
    From    YourTable
    Where   Date > @Date

    Return @Ret
End

Create Table YourTable
(
    Date     Date,
    Score    Int,
    HighestAchieveScore As dbo.fnGetMaxScore(Date)
)

答案 3 :(得分:0)

这应该适用于SQL Server 2012但不适用于早期版本:

WITH cte AS (
    SELECT date,
        LEAD(score) OVER (ORDER BY date) nextScore
    FROM yourTable
)
SELECT t.date, score,
    CASE 
        WHEN nextScore < score THEN nextScore
        ELSE (
            SELECT ISNULL(MAX(t1.score), t.score)
            FROM yourTable t1
            JOIN cte ON t1.date = cte.date
            WHERE t1.date > t.date
              AND ISNULL(nextScore, 0) < score
            )
    END AS HighestAchieveScore
FROM yourTable t
JOIN cte ON t.date = cte.date