有一个玩家,有输有赢,每局有记录,比如玩家 id 是 userid,输赢根据得分字段 score 正负判断,如何写一个 sql 语句统计最近的连续输的次数。
比如
userid score
12345 100
12345 -100
12345 100
统计出来是 0
userid score
12345 100
12345 -100
12345 -100
统计出来是 2
userid score
12345 -100
12345 100
12345 -100
统计出来是 1
1
xuanbg 2021-01-27 23:30:08 +08:00
楼主你这个需求就触及 SQL 的盲区了……
|
2
RedBeanIce 2021-01-27 23:31:24 +08:00
正负这个。。。。。
|
3
no1xsyzy 2021-01-27 23:59:47 +08:00
如果有一个标记顺序的字段就行(比如自动编码)
大致思路是分两步查询,第一步查询最后一个 score > 0 在哪行,第二步查出在那行之后有几行 |
4
yzdobest 2021-01-28 00:05:31 +08:00 via iPhone
|
5
dswyzx 2021-01-28 01:34:11 +08:00 via iPhone
思路:先通过 max(time)来获取最后一条 score 小于 0 的数据,可获得临时表:userid lasttime count=1
然后 for 循环临时表数据处理 每一个 userid+lasttime 往前面 time 读 score<0 然后 count+1 另可以设计:如果这个功能要实时统计,不如加个字段作为连输次数字段,每次插入时读取上一条记录逻辑算一下,这样如果逻辑需要处理连输的人就读上一条即可 |
6
LLLYang 2021-01-28 08:40:39 +08:00
加个字段标记本局输赢情况不好么
|
7
weizhen199 2021-01-28 09:00:41 +08:00
lz 应该不是做统计的吧。
前台用的话 decode + open window 应该就可以了 慢的话,给 decode 列加上函数索引。 |
8
Rache1 2021-01-28 09:26:23 +08:00
用 Redis 的 BitMap 来做~
|
9
sarices 2021-01-28 09:26:59 +08:00
```sql
SELECT userid, count( CASE score>0 WHEN TRUE THEN 1 END ) AS victory, count( CASE score<0 WHEN TRUE THEN 1 END ) AS failure FROM tablename GROUP BY userid; ``` |
10
gwbw 2021-01-28 09:55:42 +08:00
可能部分时序数据库有办法做,看看 timescaledb
|
11
liuzhen 2021-01-28 10:01:01 +08:00
这个需求和统计用户连续签到天数基本一致,网上能找到 sql
|
12
liprais 2021-01-28 10:07:08 +08:00
这个问题不就是在所有输的记录里面找到连续的么
|
13
bugmakerxs 2021-01-28 10:16:45 +08:00
select count(1) from user_score where userid=1 and id > (
select id from user_score where userid=1 and score > 0 order by id desc limit 1 ) 内层找到 score>0 的最大 id 外层统计大于这个 id 的行数量 |
15
lbmjsls1 OP @bugmakerxs 这种方法也不对,首先你应该说反了,找到最小的 id 或者小于最大的 id,另外,同样不能保证找到的这个 id 就是最后一条数据
|
16
lbmjsls1 OP @liuzhen 连续签到的也不行,连续签到的少了一个条件,也就是插入到数据库的数据肯定是有效的,可以使用判断连续了多少次,而输赢的是插入的数据有输的,有赢的,如果过滤掉其中的赢的,就是连续签到的问题,但是不符合我的需求
|
19
c6h6benzene 2021-01-28 10:54:45 +08:00 via iPhone
count over partition by 胜负 order by 时间也许可解
|
20
no1xsyzy 2021-01-28 11:00:26 +08:00
|
21
no1xsyzy 2021-01-28 11:04:10 +08:00
@no1xsyzy 啊
就是 reversed takewhile len,放 SQL 里就是 count after last not 换一下代码: Given series X X | reverse | takewhile _ => _.score > 0 | len 等效于 X | after (X | last _ => not _.score > 0) | len 但注意事务隔离级别,不可重复读会有问题。 |
22
no1xsyzy 2021-01-28 11:05:42 +08:00
草了,我还是把 < > 弄反了……
X | reverse | takewhile _ => _.score < 0 | len 等效于 X | after (X | last _ => not _.score < 0) | len |
23
bugmakerxs 2021-01-28 11:10:48 +08:00
@lbmjsls1 你再捋一捋,我看了半天没懂你回复我的是什么意思。
|
24
bugmakerxs 2021-01-28 11:13:01 +08:00
@lbmjsls1 我这个 sql 应该没问题
|
25
liuzhen 2021-01-28 11:21:37 +08:00
@lbmjsls1 你这个需求为什么加个字段记录连续输 /赢次数,在插入输赢的时候做个判断上次是输 /赢,来累加这个字段的次数呢?
|
27
lbmjsls1 OP @bugmakerxs 这个思路是对的,我想反了,不过有情况不对,就是如果玩家全是输的,那么就没有最后一个 id,那么统计下来就是 0.
|
28
NeezerGu 2021-01-28 11:55:25 +08:00
hive 可以
窗口函数加个 if, 再 row_number() over() 一下应该能出来 |
30
sarices 2021-01-28 12:01:17 +08:00
@lbmjsls1 不好意思,没看清楚你的问题,以为是计算胜负而已,参照这篇文章,应该可以解决你的问题 https://blog.csdn.net/u013887008/article/details/89105994
|
31
kiracyan 2021-01-28 12:01:50 +08:00
从游玩记录里统计有点费事 直接在用户表加一个字段插入游玩记录的时候更新
|
32
bugmakerxs 2021-01-28 12:12:32 +08:00
@lbmjsls1 嗯,那就里边 sql 加个判断,如果为 null 则设置为 0 就好了。
|