MYSql оконная функция - получить последнее значение - PullRequest
0 голосов
/ 23 февраля 2020

Я пытаюсь получить последнее значение баланса игрока в определенном временном окне.

У меня есть стол transactions.

Баланс игрока не является максимальным или минимальным one.

SELECT  project_id, 
        player_id,
        FIRST_VALUE(balance) OVER (PARTITION BY player_id ORDER BY event_arrival_time DESC) AS balance
FROM transactions
WHERE event_arrival_time BETWEEN '2019-12-02 00:00:00' AND '2019-12-03 23:59:59'
        AND project_id='aaa' 
GROUP BY project_id, player_id

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

Кроме того, если я выполню этот запрос несколько раз, у меня будет другой баланс, как будто он выбирает другую транзакцию (речь идет о разнице в 10 минут).

SELECT * 
FROM transacitions
where event_arrival_time BETWEEN '2019-12-02 00:00:00' AND '2019-12-03 23:59:59'
        AND project_id='aaa' and player_id = 'player1'
ORDER BY event_arrival_time desc

Я хочу получить список игроков за этот период и их последний баланс (не МАКСИМАЛЬНОЕ значение - возможно, максимальная дата).

Ответы [ 3 ]

2 голосов
/ 23 февраля 2020

Удалите предложение GROUP BY и при необходимости используйте DISTINCT в SELECT:

SELECT DISTINCT 
  project_id, 
  player_id,
  FIRST_VALUE(balance) OVER (PARTITION BY player_id ORDER BY event_arrival_time DESC) AS balance
FROM transactions
WHERE event_arrival_time BETWEEN '2019-12-02 00:00:00' AND '2019-12-03 23:59:59'
  AND project_id='aaa'
1 голос
/ 23 февраля 2020

Вам нужна фильтрация, а не агрегация.

Вы можете сделать это с помощью коррелированного подзапроса:

SELECT project_id, player_id, balance
FROM transactions t
WHERE event_arrival_time = (
    SELECT MAX(t1. event_arrival_time)
    FROM transactions t1
    WHERE 
        t1.player_id = t.player_id
        AND t1.event_arrival_time >= '2019-12-02'
        AND t1.event_arrival_time < '2019-12-03'
        AND t1.project_id = 'aaa' 
    )

Для производительности вам нужен индекс на (project_id, player_id, event_arrival_time). Вы также можете попробовать покрытие индекс: (project_id, player_id, event_arrival_time, balance); при таком индексе база данных могла бы выполнить весь запрос, просматривая только индекс, без фактического доступа к базовым данным.

Вы также можете использовать оконные функции:


SELECT project_id, player_id, balance
FROM (
    SELECT 
        t.*,
        RANK() OVER(PARTITION BY player_id ORDER BY event_arrival_time DESC) rn
    FROM transactions t
    WHERE
        event_arrival_time >= '2019-12-02'
        AND event_arrival_time < '2019-12-03'
        AND project_id='aaa'
) t
WHERE rn = 1


0 голосов
/ 23 февраля 2020

Я думаю, что это должно работать. Трудно сказать без образца.

SELECT
     t.project_id,
     t.player_id,
     GROUP_CONCAT(t.balance) AS Balance -- supposed to have single value
FROM transacitions t
LEFT JOIN transactions t2 ON t.project_id = t2.project_id AND t.player_id = t2.player_id
AND t.event_arrival_time < t2.event_arrival_time
where t2.player_id IS NULL
AND t.event_arrival_time BETWEEN '2019-12-02 00:00:00' AND '2019-12-03 23:59:59'
GROUP BY t.project_id, t.player_id
ORDER BY t.event_arrival_time desc
...