在一组行中查找n个最高连续值

时间:2015-05-12 15:10:51

标签: sql-server tsql

我在表格中有一些数据如下:

FileDate  SumAmount
20150401  90.99
20150401  313
20150403  481.2
20150404  321.27
20150405  103
20150406  25
20150407  180.5
20150408  319.91
20150409  688
20150411  69
20150412  65
20150413  322
20150414  100
20150415  111.97
20150416  979.15
20150417  655.4
20150418  124
20150419  30
20150420  457
20150421  192.6
20150422  191.96
20150423  220
20150424  252.5
20150425  109.1
20150426  135.25
20150427  648.08
20150428  692
20150429  410.99
20150430  170
20150501  166.19
20150502  92
20150503  100
20150504  59
20150505  124.01
20150506  44.5
20150507  331.64
20150508  299.8

我正在尝试设计一个查询,该查询将在数据中找到最高连续4天的值。

基本上,我认为我需要按日期进行分区并对其执行行编号,但我似乎无法正确评估值的语法。

5 个答案:

答案 0 :(得分:2)

所以我在连接条件中使用-3,因为这一天本身算作一个。让我知道你的想法。此外,我使用一年中的一天(DY)来确保它只是连续几天,因此我不必手动排列日期。希望这有帮助!

DECLARE @yourTable TABLE(FileDate DATE ,SumAmount FLOAT);
INSERT INTO @yourTable
VALUES  ('20150401',90.99),
        ('20150402',313),
        ('20150403',481.2),
        ('20150404',321.27),
        ('20150405',103),
        ('20150406',25),
        ('20150407',180.5),
        ('20150408',319.91),
        ('20150409',688),
        ('20150411',69),
        ('20150412',65),
        ('20150413',322),
        ('20150414',100),
        ('20150415',111.97),
        ('20150416',979.15),
        ('20150417',655.4),
        ('20150418',124),
        ('20150419',30),
        ('20150420',457),
        ('20150421',192.6),
        ('20150422',191.96),
        ('20150423',220),
        ('20150424',252.5),
        ('20150425',109.1),
        ('20150426',135.25),
        ('20150427',648.08),
        ('20150428',692),
        ('20150429',410.99),
        ('20150430',170),
        ('20150501',166.19),
        ('20150502',92),
        ('20150503',100),
        ('20150504',59),
        ('20150505',124.01),
        ('20150506',44.5),
        ('20150507',331.64),
        ('20150508',299.8);

WITH CTE
AS
(
    SELECT YEAR(FileDate) yr,DATEPART(DY,FileDate) dy,fileDate,SumAmount
    FROM @yourTable
),
CTE_Max_Sum
AS
(
    SELECT TOP 1 A.yr,A.dy,A.FileDate,SUM(B.SumAmount) consec4DaySum
    FROM CTE A
    INNER JOIN CTE B
    ON B.dy BETWEEN A.dy - 3 AND A.dy
    AND A.yr = B.yr
    GROUP BY A.yr,A.dy,A.FileDate
    ORDER BY SUM(B.SumAmount) DESC
)

SELECT A.*,B.consec4DaySum
FROM CTE A
INNER JOIN CTE_Max_Sum B
ON A.dy BETWEEN B.dy - 3 AND B.dy
AND A.yr = B.yr

结果:

yr          dy          fileDate   SumAmount              consec4DaySum
----------- ----------- ---------- ---------------------- ----------------------
2015        117         2015-04-27 648.08                 1921.07
2015        118         2015-04-28 692                    1921.07
2015        119         2015-04-29 410.99                 1921.07
2015        120         2015-04-30 170                    1921.07

答案 1 :(得分:0)

你可以使用CTE来加入每一行及其后续三行(每天)并总结。这个Fiddle遗憾地对我不起作用,它在我的SQL服务器上运行并为你工作。注意递归深度,没有WHERE cte.Consecutive < 4您很快就会遇到错误。

WITH cte (StartDate, EndDate, Consecutive, SumAmount)
AS (
    SELECT t.FileDate, t.FileDate, 1, t.SumAmount FROM dbo.table30194903 t
    UNION ALL
    SELECT cte.StartDate, t.FileDate, cte.Consecutive + 1, cte.SumAmount + t.SumAmount
    FROM dbo.table30194903 t INNER JOIN cte ON DATEADD(DAY, 1, cte.EndDate) = t.FileDate
    WHERE cte.Consecutive < 5
)
SELECT *
FROM cte
WHERE cte.Consecutive = 4
ORDER BY cte.SumAmount DESC

编辑:我的查询中有两个错误,它总结了错误的行并显示了系列中的最后一天。

答案 2 :(得分:0)

我认为最简单的方法是使用APPLY获取每行后n天内的记录数,然后将其限制为{{1} } date,这可确保您连续几天。然后您可以按总和排序并选择前1:

n

<强> Example on SQL Fiddle

答案 3 :(得分:0)

我想使用子查询添加答案,但与我的cte相比确实需要更多时间......

SELECT t.FileDate, SUM(s.SumAmount)
FROM dbo.table30194903 t
LEFT JOIN dbo.table30194903 s ON t.FileDate <= s.FileDate AND DATEDIFF(DAY, t.FileDate, s.FileDate) < 4 
GROUP BY t.FileDate
HAVING COUNT(s.SumAmount) = 4
ORDER BY SUM(s.SumAmount) DESC

答案 4 :(得分:-2)

如何简单地阻止并对一系列日期的值求和?

mViewPager.setOnTouchListener(new OnSwipeTouchListener() {
        public void onSwipeRight() 
{
            if (FirstFragment.btnImage.isPressed())
            {
                Toast.makeText(getApplicationContext(), "msg",Toast.LENGTH_LONG).show();} }});