Совокупная сумма определенных строк с разделами

#sql #sql-server #tsql

#sql #sql-сервер #tsql

Вопрос:

У нас есть таблица, в которой указаны ставки игроков и выигрыши в игровых автоматах. Данные, которые мы получаем, содержат транзакции ставок и выигрышей в отдельных строках, и мы хотим иметь возможность помещать их в одну строку, чтобы мы могли приписать каждый выигрыш ставке, из которой он получен.

Ниже приведен пример данных

 CREATE TABLE #temp1 (PlayerID smallint,GameID smallint,GamePlayDateTime varchar(20),StakeGBP money,WinGBP money);
INSERT INTO #temp1 (PlayerID,GameID,GamePlayDateTime,StakeGBP,WinGBP)
VALUES 
('123', '321',  '2019-08-20 10:21:38',  '0.4',  '0.0'),
('123', '321',  '2019-08-20 10:21:41',  '0.0',  '0.6'),
('123', '321',  '2019-08-20 10:21:44',  '0.4',  '0.0'),
('123', '321',  '2019-08-20 10:21:46',  '0.4',  '0.0'),
('123', '321',  '2019-08-20 10:21:49',  '0.0',  '1.2'),
('123', '321',  '2019-08-20 10:21:51',  '0.0',  '0.2'),
('123', '321',  '2019-08-20 10:21:54',  '0.0',  '1.0'),
('123', '321',  '2019-08-20 10:21:56',  '0.4',  '0.0'),
('824', '321',  '2019-08-20 10:21:39',  '0.2',  '0.0'),
('824', '321',  '2019-08-20 10:21:42',  '0.0',  '0.8'),
('824', '321',  '2019-08-20 10:21:45',  '0.0',  '0.4'),
('824', '321',  '2019-08-20 10:21:47',  '0.2',  '0.0'),
('824', '321',  '2019-08-20 10:21:50',  '0.0',  '1.2'),
('824', '321',  '2019-08-20 10:21:53',  '0.2',  '0.0'),
('824', '321',  '2019-08-20 10:21:55',  '0.2',  '0.0');
 

Со следующим выводом

 PlayerID GameID GamePlayDateTime     StakeGBP              WinGBP
-------- ------ -------------------- --------------------- ---------------------
123      321    2019-08-20 10:21:38  0.40                  0.00
123      321    2019-08-20 10:21:41  0.00                  0.60
123      321    2019-08-20 10:21:44  0.40                  0.00
123      321    2019-08-20 10:21:46  0.40                  0.00
123      321    2019-08-20 10:21:49  0.00                  1.20
123      321    2019-08-20 10:21:51  0.00                  0.20
123      321    2019-08-20 10:21:54  0.00                  1.00
123      321    2019-08-20 10:21:56  0.40                  0.00
824      321    2019-08-20 10:21:39  0.20                  0.00
824      321    2019-08-20 10:21:42  0.00                  0.80
824      321    2019-08-20 10:21:45  0.00                  0.40
824      321    2019-08-20 10:21:47  0.20                  0.00
824      321    2019-08-20 10:21:50  0.00                  1.20
824      321    2019-08-20 10:21:53  0.20                  0.00
824      321    2019-08-20 10:21:55  0.20                  0.00
 

Если ставка не приводит к выигрышу, следующая строка является последующей ставкой. Любая выигрышная транзакция проходит в строке после ставки, которой она принадлежит, со StakeGBP = 0.

В приведенном выше примере мы хотим, чтобы выигрыш 0,6 в 10:21:41 был на той же строке, что и ставка 0,4 в 10:21:38 (предыдущая строка). Возвращаемое значение GamePlayDateTime не имеет значения (может быть либо временем ставки, либо временем выигрыша), мы просто хотим знать, что ставка 0.40 принесла выигрыш 0.60.

Ранее я мог использовать функцию задержки, чтобы взять ставку из предыдущей строки, где выигрыш равен> 0.

Проблема, с которой я сталкиваюсь, заключается в том, что бывают случаи, когда одна ставка может привести к нескольким выигрышам. Мы хотим иметь возможность суммировать эти выигрыши и размещать их в той же строке, что и ставка.

В приведенном выше примере ставка 0,40 в 10:21:46 приводит к выигрышам в 1,2, 0,2 и 1,0 до следующей ставки 0,4 в 10: 21: 56.

Что мы хотим сделать, так это просуммировать эти ставки, чтобы получить выигрыш 2,4 и получить этот выигрыш в той же строке со ставкой 0,4, из которой он был получен.

Желаемые результаты из приведенного выше примера будут

 PlayerID GameID GamePlayDateTime     StakeGBP              WinGBP
-------- ------ -------------------- --------------------- ---------------------
123      321    2019-08-20 10:21:38  0.40                  0.60
123      321    2019-08-20 10:21:44  0.40                  0.00
123      321    2019-08-20 10:21:46  0.40                  2.40
123      321    2019-08-20 10:21:56  0.40                  0.00
824      321    2019-08-20 10:21:39  0.20                  1.20
824      321    2019-08-20 10:21:47  0.20                  1.20
824      321    2019-08-20 10:21:53  0.20                  0.00
824      321    2019-08-20 10:21:55  0.20                  0.00
 

Если ставка не приводит к выигрышу, столбец WinGBP в строке ставки равен 0.
Там, где ставка приводит к одному выигрышу, столбец WinGBP показывает выигрыш в той же строке, что и ставка (например, первый выигрыш 0,6)
В тех случаях, когда ставка приводит к нескольким выигрышам, эти выигрыши суммируются и отображаются в той же строке, что и ставка (например, выигрыш 2,40, который получается из отдельных выигрышей 1,2, 0,2 и 1,0)

Я не понял, как использовать задержку при попытке вернуть значения из более чем одной строки.

Я также пытался использовать SUM OVER, чтобы получить текущую сумму для нескольких выигрышей, но не смог понять, как ее разделить. Текущий итог должен быть остановлен, когда значение WinGBP = 0, поскольку это сигнализирует о том, что была установлена новая ставка.

Если выигрыша нет, мы просто хотим вернуть ставку. Если есть один выигрыш, мы хотим вернуть ставку (из предыдущей строки) и выигрыш. Если выигрышей несколько, мы хотим вернуть ставку (из строки до первого выигрыша), а затем объединить выигрыши в один. Затем агрегацию необходимо будет остановить при последнем выигрыше.

Надеюсь, это имеет смысл. Любая помощь будет принята с благодарностью! Спасибо

Комментарии:

1. Я понимаю, что следую логике, когда кто-то какие деньги. Я не следую логике для строк, где нет выигрыша.

2. Кроме того: почему все значения smallint и money в вашем примере данных заключены в кавычки?

Ответ №1:

Это интересный вариант проблемы с пробелами и островами, когда вы хотите сгруппировать только выигрышные строки вместе.

Вы можете определить острова как сумму ставок до каждой строки. Тогда остальное — это в основном агрегирование и фильтрация:

 select playerid, gameid, min(GamePlayDateTime) as GamePlayDateTime,
       sum(WinGBP) as WinGBP,
       sum(StakeGBP)) over (partition by playerid, gameid order by min(GamePlayDateTime) as prev_StakeGBP
 from (select t.*,
               sum(StakeGBP) over (partition by playerid, gameid order by GamePlayDateTime) as grp 
       from temp1 t
      ) t
group by playerid, gameid, grp, StakeGBP
order by playerid, gameid, GamePlayDateTime;
 

Вот скрипка SQL.

Ответ №2:

 with data as (
    select *,
        sum(case when StakeGBP > 0 then 1 end)
            over (partition by PlayerID, GameID order by GamePlayDateTime) as StakeNum
    from temp1
)
select
    PlayerID,
    GameID,
    min(GamePlayDateTime) as GamePlayDateTime,
    max(StakeGBP) as StakeGBP,
    sum(WinGBP) as WinGBP
from data
group by PlayerID, GameID, StakeNum
order by PlayerID, GameID, GamePlayDateTime;
 

РЕДАКТИРОВАТЬ: скорректировано для обработки игроков и игр отдельно.

http://sqlfiddle.com /#!18/1e6b22/20