MYSql window 函数 - 获取最后一个值
MYSql window function - get last value
我正在尝试获取特定时间玩家余额的最新值window。
我有一个 transactions
table.
玩家余额不是最大值或最小值
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
我想获得那个时期的玩家列表,以及他们的最新余额(不是最大值 - 也许是最大日期)。
您需要过滤,而不是聚合。
您可以使用相关子查询来做到这一点:
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)
上的索引。您也可以尝试 covering 索引:(project_id, player_id, event_arrival_time, balance)
;使用这样的索引,数据库可能仅通过查看索引来执行整个查询,而不实际访问基础数据。
您还可以使用 window 函数:
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
删除 GROUP BY
子句,如果需要,在 SELECT
:
中使用 DISTINCT
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'
我认为这应该可行。没有样品很难说。
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
我正在尝试获取特定时间玩家余额的最新值window。
我有一个 transactions
table.
玩家余额不是最大值或最小值
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
我想获得那个时期的玩家列表,以及他们的最新余额(不是最大值 - 也许是最大日期)。
您需要过滤,而不是聚合。
您可以使用相关子查询来做到这一点:
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)
上的索引。您也可以尝试 covering 索引:(project_id, player_id, event_arrival_time, balance)
;使用这样的索引,数据库可能仅通过查看索引来执行整个查询,而不实际访问基础数据。
您还可以使用 window 函数:
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
删除 GROUP BY
子句,如果需要,在 SELECT
:
DISTINCT
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'
我认为这应该可行。没有样品很难说。
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