SQL-запрос для игроков средней продолжительности горячей полосы - PullRequest
0 голосов
/ 20 сентября 2018

Допустим, у меня есть таблица с тремя столбцами и следующими данными:

* gamedate,playername,pointsScored
* 20180101,George,34
* 20180102,George,37
* 20180103,George,38
* 20180104,George,3
* 20180105,George,35
* 20180106,George,37
* 20180107,George,31
* 20180108,George,31
* 20180109,George,32
* 20180110,George,7

Я ищу sql query, который говорит мне в среднем, сколько игр подряд может поддерживать этот игрокоценка 30+.Я знаю, что это должна быть какая-то функция group by, но я застрял на том, как сформулировать этот запрос.Это Oracle table, если это имеет какое-либо значение.

Некоторые дополнительные даты для тестирования:

with
inputs(gamedate,playername,pointsscored) as (
select to_date('20180912','yyyymmdd'), 'George',52 from dual union all
select to_date('20180907','yyyymmdd'), 'George',47 from dual union all
select to_date('20180829','yyyymmdd'), 'George',9 from dual union all
select to_date('20180823','yyyymmdd'), 'George',55 from dual union all
select to_date('20180818','yyyymmdd'), 'George',49 from dual union all
select to_date('20180811','yyyymmdd'), 'George',58 from dual union all
select to_date('20180805','yyyymmdd'), 'George',31 from dual union all
select to_date('20180730','yyyymmdd'), 'George',40 from dual union all
select to_date('20180720','yyyymmdd'), 'George',44 from dual union all
select to_date('20180712','yyyymmdd'), 'George',45 from dual union all
select to_date('20180707','yyyymmdd'), 'George',29 from dual union all
select to_date('20180701','yyyymmdd'), 'George',-5 from dual union all
select to_date('20180626','yyyymmdd'), 'George',46 from dual union all
select to_date('20180620','yyyymmdd'), 'George',22 from dual union all
select to_date('20180614','yyyymmdd'), 'George',49 from dual union all
select to_date('20180609','yyyymmdd'), 'George',40 from dual union all
select to_date('20180602','yyyymmdd'), 'George',40 from dual
)

Ответы [ 2 ]

0 голосов
/ 20 сентября 2018

В Oracle 12.1 или выше, предложение MATCH_RECOGNIZE может выполнять быструю работу с такими назначениями:

with
  inputs(gamedate,playername,pointsscored) as (
    select to_date('20180101','yyyymmdd'), 'George', 34 from dual union all
    select to_date('20180102','yyyymmdd'), 'George', 37 from dual union all
    select to_date('20180103','yyyymmdd'), 'George', 38 from dual union all
    select to_date('20180104','yyyymmdd'), 'George',  3 from dual union all
    select to_date('20180105','yyyymmdd'), 'George', 35 from dual union all
    select to_date('20180106','yyyymmdd'), 'George', 37 from dual union all
    select to_date('20180107','yyyymmdd'), 'George', 31 from dual union all
    select to_date('20180108','yyyymmdd'), 'George', 31 from dual union all
    select to_date('20180109','yyyymmdd'), 'George', 32 from dual union all
    select to_date('20180109','yyyymmdd'), 'George',  7 from dual
  )
select playername, avg(cnt) as average_streak
from   inputs
match_recognize(
  partition by playername
  order by     gamedate
  measures     count(*) as cnt
  one row per match
  pattern ( a+ )
  define a as pointsscored >= 30
)
group by playername
;

PLAYER AVERAGE_STREAK
------ --------------
George              4

Объяснение:

MATCH_RECOGNIZE разбивает входные строки по игроку, иупорядочивает их в каждом разделе по дате игры.«Совпадение» - это вхождение одной или нескольких последовательных строк (a+ в подпункте PATTERN) с набранными 30 или более точками (см. Подпункт DEFINE).MATCH_RECOGNIZE возвращает по одной строке для каждого найденного совпадения, и, в частности, возвращает имя игрока и количество строк в матче (то есть длину серии, количество последовательных строк или игр).Внешний запрос группируется по игроку и принимает среднюю длину полосы.

0 голосов
/ 20 сентября 2018

Вот один из способов.Он использует метод Tabibitosan (или «фиксированные различия») для распознавания полос - в этом разница двух вызовов ROW_NUMBER во внутреннем запросе.Остальное - группировка и использование агрегатных функций.

Предложение WITH имитирует данные;оно не является частью решения, оно должно быть удалено перед тестированием решения на реальных данных.(Используйте собственное имя таблицы вместо INPUTS во внутреннем запросе.)

with
  inputs(gamedate,playername,pointsscored) as (
    select to_date('20180101','yyyymmdd'), 'George', 34 from dual union all
    select to_date('20180102','yyyymmdd'), 'George', 37 from dual union all
    select to_date('20180103','yyyymmdd'), 'George', 38 from dual union all
    select to_date('20180104','yyyymmdd'), 'George',  3 from dual union all
    select to_date('20180105','yyyymmdd'), 'George', 35 from dual union all
    select to_date('20180106','yyyymmdd'), 'George', 37 from dual union all
    select to_date('20180107','yyyymmdd'), 'George', 31 from dual union all
    select to_date('20180108','yyyymmdd'), 'George', 31 from dual union all
    select to_date('20180109','yyyymmdd'), 'George', 32 from dual union all
    select to_date('20180109','yyyymmdd'), 'George',  7 from dual
  )
select   playername, avg(ct) as average_streak
from     (
           select playername, count(*) as ct
           from   (
                    select playername, pointsscored,
                           row_number() over (partition by playername 
                                                order by gamedate)
                           - row_number() over (partition by playername,
                                                 case when pointsscored >= 30 
                                                      then 0 end
                                                 order by gamedate) as grp
                    from   inputs
                  )
           group by playername, grp
           having   min(pointsscored) >= 30
         )
group by playername
order by playername
;

OUTPUT :

PLAYER AVERAGE_STREAK
------ --------------
George              4
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...