与SQL结合使用的日期范围标记算法

时间:2018-06-21 08:50:31

标签: sql sql-server

我有一个体育项目。

Country     League      StartDate           EndDate
------------------------------------------------------------
USA         UPA         10.10.2015          13.06.2018

当我使用下面的代码时,我得到的结果如上所述。

SELECT Country
      ,League
      ,MIN(MatchDateTimeUtc) AS StartDate
      ,MAX(MatchDateTimeUtc) AS EndDate
FROM Games
WHERE Country = 'USA'
GROUP BY Country
        ,League

我需要按日期范围标记季节。 但是日期范围不是恒定的。 我的意思是每个联赛的开始或结束日期不确定。 任何联赛的开始或结束日期可能会改变。 只有国家和联赛领域是不变的。 例如,实际上以上结果有3个赛季。 我的预期结果如下。

Country     League      StartDate           EndDate
------------------------------------------------------------
USA         UPA         10.10.2015          09.04.2016
USA         UPA         22.10.2016          11.05.2017
USA         UPA         30.09.2017          13.06.2018

有什么聪明的逻辑吗?

2 个答案:

答案 0 :(得分:1)

显然,您需要更多有关如何区分不同季节的游戏的信息。

最简单的示例是进行限制性假设,例如“所有季节的游戏都在同一年,并且每年仅包含1个季节的游戏”。在这种情况下,您可以按年份将分组添加为wel,例如:year(startDate)

SELECT Country, 
    League, 
    MIN(MatchDateTimeUtc) AS StartDate, 
    MAX(MatchDateTimeUtc) AS EndDate 
FROM Games 
WHERE Country = 'USA' 
GROUP BY Country, League, year(startDate)

如果无法解决关于季节的这种简单约定,那么您需要为League_seasons引入另一个表,并加入League_season表进行分组。


由于“季节”是由OP注释定义的,是根据游戏之间的间隔时间定义的,因此您可以使用以下查询:

;with removedDuplicates as (
    select distinct * from games    
),
gamesWithSeasonNumber AS (
    select g.*,
    SUM(
        case when not exists (
            select 1 from removedDuplicates previousG
            where previousG.Country = g.Country and previousG.League = g.League
                and previousG.MatchDateTimeUtc < g.MatchDateTimeUtc
                and (DATEDIFF(d, previousG.MatchDateTimeUtc, g.MatchDateTimeUtc) < 60)) 
            then 1 else 0 
        end) 
    OVER(Partition By Country, LEague ORDER BY MatchDateTimeUtc) as SeasonNumber
    from removedDuplicates g
)
select Country, League, min(MatchDateTimeUtc) as startDate, max(MatchDateTimeUtc) as EndDate
from gamesWithSeasonNumber 
group by Country, League, SeasonNumber

该解决方案的关键部分是:

  1. 我们知道哪些游戏是本赛季开始的比赛-他们在开始之前不得有任何比赛过于接近(我假设此处以60天为淡季的最短时间)
  2. 如果您按游戏日期排序,则入门游戏的累积总和将为所有行提供一个季节编号。 See OVER-clause in documentation
  3. 一旦有了季节编号,它对于日期最小/最大的分组就不重要了。

Common Table Expressions,以逐步保持查询的可读性。

答案 1 :(得分:0)

根据您的样本数据,可以通过减去8个月并使用年份来计算季节:

SELECT Country, League, 
       MIN(MatchDateTimeUtc) AS StartDate, 
       MAX(MatchDateTimeUtc) AS EndDate 
FROM Games 
WHERE Country = 'USA' 
GROUP BY Country, League, 
      YEAR(DATEADD(month, -8, startDate));

这应该适用于从9月-12月到8月之前结束的任何季节。您的所有数据都支持该定义。如果您有更详细的数据,我真的建议您再问一个问题,以更好地定义“季节”和更好的原始数据示例。