将数据拆分到窗口并从tsql中的该窗口获取最小值

时间:2016-07-12 15:21:45

标签: sql-server tsql split

我无法将数据集拆分成其他几个数据集,因此我可以从中获取最小值。基线:Key可以在不同国家/地区同时使用(国家/地区ID位于 a 列中)。一段时间后,一个键(图中的列 b )可以再次重复使用,在这种情况下为120天。一个密钥可以包含大约10个事件以及日期。

Picture with sample data (I have colored the theoretical boundaries for each of the periods or whatever you call them)

我尝试做的事情是,获取整个集合的第一个日期并对 a b 列进行分区,并使用datediff()来获取数字在整个集合的最小日期和每个单独的事件之间的天数。然后使用datediff / 120返回的数字对它们进行分组。我真正想要做的是获取每组的最小日期(而不是整组)并根据它进行计算。我真的希望我能够清楚地解释清楚,让你帮助我了解我的目标。现在我想起了......我很担心,即使我确实得到了一套的最小日期,然后除以120,我也会得到不正确的结果。任何建议赞赏!

我使用了这样的东西:DATEDIFF(d,min(dates) OVER (PARTITION BY a, b), dates)/120

Visual explanation of what I need to achieve and how.

                sample data                                   desired outcome
|  CountryId  |    Key      |     date     |    |  CountryId  |      Key    |     date     | 
|-------------|-------------|--------------|    |-------------|-------------|--------------|
|  2          |  093123124  |  2015-04-16  |    |  2          |  093123124  |  2015-04-16  |
|  2          |  093123124  |  2015-04-16  |    |  2          |  093123124  |  2015-11-24  |
|  2          |  093123124  |  2015-04-17  |    |  2          |  093123124  |  2016-04-17  |
|  2          |  093123124  |  2015-04-17  |
|  2          |  093123124  |  2015-11-24  |
|  2          |  093123124  |  2015-11-24  |
|  2          |  093123124  |  2015-11-25  |
|  2          |  093123124  |  2015-11-25  |
|  2          |  093123124  |  2015-11-25  |
|  2          |  093123124  |  2016-04-17  |
|  2          |  093123124  |  2016-04-18  |
|  2          |  093123124  |  2016-04-20  |
|  2          |  093123124  |  2016-04-21  |
|  2          |  093123124  |  2016-04-22  |

1 个答案:

答案 0 :(得分:0)

这似乎是CTE的情况。以下代码每次递归递归地为每个递归添加120天。

SET DATEFORMAT YMD
DECLARE @SampleData TABLE(  A   INT,
                            B   NVARCHAR(25),
                            C   DATETIME)


INSERT INTO @SampleData(A, B, C)
VALUES (2,'093123124', CONVERT(DATETIME, '2015-04-16')),
       (2,'093123124', CONVERT(DATETIME, '2015-04-16')),
       (2,'093123124', CONVERT(DATETIME, '2015-04-17')),
       (2,'093123124', CONVERT(DATETIME, '2015-04-17')),
       (2,'093123124', CONVERT(DATETIME, '2015-11-24')),
       (2,'093123124', CONVERT(DATETIME, '2015-11-24')),
       (2,'093123124', CONVERT(DATETIME, '2015-11-25')),
       (2,'093123124', CONVERT(DATETIME, '2015-11-25')),
       (2,'093123124', CONVERT(DATETIME, '2015-11-25')),
       (2,'093123124', CONVERT(DATETIME, '2016-04-17')),
       (2,'093123124', CONVERT(DATETIME, '2016-04-18')),
       (2,'093123124', CONVERT(DATETIME, '2016-04-20')),
       (2,'093123124', CONVERT(DATETIME, '2016-04-21')),
      -- (2,'093123124', CONVERT(DATETIME, '2016-03-24')),
       (2,'093123124', CONVERT(DATETIME, '2016-04-22'));

WITH lvl1
AS
(
    SELECT  A, 
            B, 
            C = MIN(C)
    FROM @SampleData
    GROUP BY    A,
                B
),
lvlOthers
AS
(
    SELECT  A,
            B,
            C
    FROM lvl1
    UNION ALL
    SELECT  S.A,
            S.B,
            C = MIN(S.C) OVER(PARTITION BY S.A, S.B)
    FROM lvlOthers
    INNER JOIN @SampleData AS S ON  lvlOthers.A = S.A
                                AND lvlOthers.B = S.B
                                AND S.C > DATEADD(DAY, 120, lvlOthers.C)
)

SELECT DISTINCT A, B, C
FROM lvlOthers
OPTION (MAXRECURSION 100)

请注意,此代码未针对性能进行微调。事实上,它将在大型数据集上表现不佳。

此外,如果日期范围超过〜32年,则应增加maxrecursion。