Найти минимальную и максимальную дату на периоде времени ГГГГММ00 - PullRequest
0 голосов
/ 11 декабря 2018

У меня есть следующие две таблицы:

  • DimensionTime - это таблица, которая содержит каждый месяц, упорядоченный по идентификатору, в форме YYYMM00
  • LogPlayer - это таблица, в которой есть некоторая статистика, относящаяся к игроку и определенному месяцу.

Я хотел бы получить следующее:

+--------+--------+----------+----------+
| Player |  Team  |  Start   |   End    |
+--------+--------+----------+----------+
| John   | Red    | 20180100 | 20180300 |
| John   | Red    | 20180600 | 20180700 |
| Luke   | Yellow | 20180100 | 20180100 |
| Luke   | Yellow | 20190100 | 20190100 |
+--------+--------+----------+----------+

Я не могу использовать функции MIN и MAX, потому что периоды являются прерывистыми ... как я могу решить?Я пробовал с MIN / MAX в сочетании с GROUP BY, но я не получил ничего полезного.Я не нахожу здесь ни одного вопроса или ответа на Stackoverflow.

SELECT *
    INTO #DimensionTime
    FROM (
        SELECT 1 AS [ID], 20180100 AS [TIMEID]
        UNION ALL
        SELECT 2 AS [ID], 20180200 AS [TIMEID]
        UNION ALL
        SELECT 3 AS [ID], 20180300 AS [TIMEID]
        UNION ALL
        SELECT 4 AS [ID], 20180400 AS [TIMEID]
        UNION ALL
        SELECT 5 AS [ID], 20180500 AS [TIMEID]
        UNION ALL
        SELECT 6 AS [ID], 20180600 AS [TIMEID]
        UNION ALL
        SELECT 7 AS [ID], 20180700 AS [TIMEID]
        UNION ALL
        SELECT 8 AS [ID], 20180800 AS [TIMEID]
        UNION ALL
        SELECT 9 AS [ID], 20180900 AS [TIMEID]
        UNION ALL
        SELECT 10 AS [ID], 20181000 AS [TIMEID]
        UNION ALL
        SELECT 11 AS [ID], 20181100 AS [TIMEID]
        UNION ALL
        SELECT 12 AS [ID], 20181200 AS [TIMEID]
        UNION ALL
        SELECT 13 AS [ID], 20190100 AS [TIMEID]
        UNION ALL
        SELECT 14 AS [ID], 20190200 AS [TIMEID]
        UNION ALL
        SELECT 15 AS [ID], 20190300 AS [TIMEID]
    ) A

SELECT *
INTO #LogPlayer
FROM (
    SELECT 'John' AS [Player], 'Red' AS [Team], 20180100 AS [TIMEID]
    UNION ALL
    SELECT 'John' AS [Player], 'Red' AS [Team], 20180200 AS [TIMEID]
    UNION ALL
    SELECT 'John' AS [Player], 'Red' AS [Team], 20180300 AS [TIMEID]
    UNION ALL
    SELECT 'John' AS [Player], 'Red' AS [Team], 20180600 AS [TIMEID]
    UNION ALL
    SELECT 'John' AS [Player], 'Red' AS [Team], 20180700 AS [TIMEID]
    UNION ALL
    SELECT 'Luke' AS [Player], 'Yellow' AS [Team], 20180100 AS [TIMEID]
    UNION ALL
    SELECT 'Luke' AS [Player], 'Yellow' AS [Team], 20190100 AS [TIMEID]
) B

Ответы [ 2 ]

0 голосов
/ 11 декабря 2018

Это тип проблемы пробелов и островков.Это разрешимо даже в неподдерживаемых древних программах, таких как SQL Server 2005, потому что эта версия имеет row_number().

. Одна хитрость заключается в преобразовании идентификатора времени в истинную дату / время.Другой трюк заключается в определении групп путем вычитания последовательного числа месяцев из значения даты / времени:

select player, team, min(timeid), max(timeid)
from (select lp.*,
             row_number() over (partition by player, team order by timeid) as seqnum,
             cast(cast(timeid + 1 as varchar(255)) as datetime) as yyyymm
      from logplayer lp
     ) lp
group by player, team, dateadd(month, - seqnum, yyyymm)
order by player, team, min(timeid);

Здесь - это db <> скрипка.

0 голосов
/ 11 декабря 2018

вы можете сделать это, чтобы найти начало и конец серий дат.

Преобразовать в «дату» через CTE (который, я думаю, существует в 2005 году), а затем использовать Cross Apply EXIST длянайдите начало и конец серии дат

, которую вы не указали для игрока и команды, но вы можете добавить условия WHERE в EXISTS, затем GROUP BY - при необходимости

;WITH dats as (SELECT CAST(LEFT(timeid, 6) + '01' as datetime) as DT from #DimensionTime)
    select CONVERT(varchar(7),d1.DT,112) +'0'  as strt, 
           CONVERT(varchar(7),dq.dt,112) +'0' as [end] from dats d1 
        CROSS  APPLY
          (SELECT TOP 1 d3.dt from dats d3 where 
                                            d3.dt >  d1.dt 
                                            and 
                                            not exists(
                                                    select 0 from dats d4 where d4.DT = dateadd(month,1,d3.DT)
                                                      )
        ORDER BY d3.dt asc) DQ           
        where not exists(select 0 from dats d2 where d2.DT = dateadd(month,-1,d1.DT)) ;

Догадываясь о некоторых образцах данных, я попытался

SELECT *
INTO #DimensionTime
FROM (
    SELECT 1 AS [ID], 20180100 AS [TIMEID], 'john' as player, 'red' as team 
    UNION ALL
    SELECT 2 AS [ID], 20180200 AS [TIMEID], 'john','red'
    UNION ALL
    SELECT 3 AS [ID], 20180300 AS [TIMEID], 'john','red'
    UNION ALL
    SELECT 4 AS [ID], 20180400 AS [TIMEID], 'john','red'
    UNION ALL
    SELECT 5 AS [ID], 20180500 AS [TIMEID], 'john','red'
    UNION ALL
    SELECT 7 AS [ID], 20180700 AS [TIMEID], 'john','red'
    UNION ALL
    SELECT 8 AS [ID], 20180800 AS [TIMEID], 'john','red'
    UNION ALL
    SELECT 9 AS [ID], 20180900 AS [TIMEID], 'john','red'
    UNION ALL
    SELECT 11 AS [ID], 20181100 AS [TIMEID], 'john','red'
    UNION ALL
    SELECT 12 AS [ID], 20181200 AS [TIMEID], 'john','red'
    UNION ALL
    SELECT 13 AS [ID], 20190100 AS [TIMEID], 'john','red'
    UNION ALL
    SELECT 14 AS [ID], 20190200 AS [TIMEID], 'john','red'
    UNION ALL
    SELECT 15 AS [ID], 20190300 AS [TIMEID], 'john','red'
    UNION ALL 
    SELECT 1 AS [ID], 20180100 AS [TIMEID], 'luke','yellow'
    UNION ALL
    SELECT 2 AS [ID], 20180200 AS [TIMEID], 'luke','yellow'
    UNION ALL
    SELECT 4 AS [ID], 20180400 AS [TIMEID], 'luke','yellow'
    UNION ALL
    SELECT 5 AS [ID], 20180500 AS [TIMEID], 'luke','yellow'
    UNION ALL
    SELECT 8 AS [ID], 20180800 AS [TIMEID], 'luke','yellow'
    UNION ALL
    SELECT 9 AS [ID], 20180900 AS [TIMEID], 'luke','yellow'
    UNION ALL
    SELECT 12 AS [ID], 20181200 AS [TIMEID], 'luke','yellow'
    UNION ALL
    SELECT 13 AS [ID], 20190100 AS [TIMEID], 'luke','yellow'
    UNION ALL
    SELECT 14 AS [ID], 20190200 AS [TIMEID], 'luke','yellow'
    UNION ALL
    SELECT 15 AS [ID], 20190300 AS [TIMEID], 'luke','yellow'


) A



;WITH dats as (SELECT CAST(LEFT(timeid, 6) + '01' as datetime) as DT,player,team from #DimensionTime)
    select d1.team,d1.player,
            CONVERT(varchar(7),d1.DT,112) +'0'  as strt, 
           CONVERT(varchar(7),dq.dt,112) +'0' as [end] from dats d1 
        CROSS  APPLY
          (SELECT TOP 1 d3.dt from dats d3 where 
                                            d3.dt >  d1.dt 
                                            and
                                            d3.player = d1.player
                                            and
                                            d3.team = d1.team
                                            and 
                                            not exists(
                                                    select 0 from dats d4 where d4.DT = dateadd(month,1,d3.Dt)
                                                         and  d4.team = d3.team
                                                         and d4.player = d3.player
                                                      )
        ORDER BY d3.dt asc) DQ           
        where not exists(select 0 from dats d2 where 
                    d2.player=d1.player
                    and
                    d2.team = d1.team
                    and 
                    d2.DT = dateadd(month,-1,d1.DT) and d1.team=d2.team and d1.player = d2.player ) ;

drop table #DimensionTime;

с последними таблицами, которые, к сожалению, я пропустил, я разработал

;WITH dats as (SELECT CAST(LEFT(timeid, 6) + '01' as datetime) as DT,player,team from #LogPlayer)
    select d1.team,d1.player,
            CONVERT(varchar(7),d1.DT,112) +'0'  as strt, 
           CONVERT(varchar(7),dq.dt,112) +'0' as [end] from dats d1 
        CROSS  APPLY
          (SELECT TOP 1 d3.dt from dats d3 where 
                                            d3.dt >  d1.dt 
                                            and
                                            d3.player = d1.player
                                            and
                                            d3.team = d1.team
                                            and 
                                            not exists(
                                                    select 0 from dats d4 where d4.DT = dateadd(month,1,d3.Dt)
                                                         and  d4.team = d3.team
                                                         and d4.player = d3.player
                                                      )
        ORDER BY d3.dt asc) DQ           
        where not exists(select 0 from dats d2 where 
                    d2.player=d1.player
                    and
                    d2.team = d1.team
                    and 
                    d2.DT = dateadd(month,-1,d1.DT) and d1.team=d2.team and d1.player = d2.player ) ;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...