V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
MySQL 5.5 Community Server
MySQL 5.6 Community Server
Percona Configuration Wizard
XtraBackup 搭建主从复制
Great Sites on MySQL
Percona
MySQL Performance Blog
Severalnines
推荐管理工具
Sequel Pro
phpMyAdmin
推荐书目
MySQL Cookbook
MySQL 相关项目
MariaDB
Drizzle
参考文档
http://mysql-python.sourceforge.net/MySQLdb.html
lbmjsls1
V2EX  ›  MySQL

最新连续输的 sql 统计

  •  
  •   lbmjsls1 · 2021-01-27 22:34:01 +08:00 · 3539 次点击
    这是一个创建于 1390 天前的主题,其中的信息可能已经有所发展或是发生改变。

    有一个玩家,有输有赢,每局有记录,比如玩家 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 条附言  ·  2021-01-28 11:57:03 +08:00
    根据 @bugmakerxs 暂时修改了一下,测试下来没发现问题,大家帮忙看一下有没有漏洞

    select count(1) from test where userid=2222 and id > IFNULL((
    select id from test where userid=2222 and score > 0 order by id desc limit 1
    ), 0)
    第 2 条附言  ·  2022-06-02 09:27:18 +08:00
    是豆腐干山豆根山豆根山豆根山豆根士大夫 v 复古如图一要让他也让豆腐干豆腐干恢复人文 34 同仁堂也让图与体育体育风格恢复举报你不更符合瑞特瑞特让他感到给对方
    第 3 条附言  ·  2022-06-02 09:27:23 +08:00
    是豆腐干山豆根山豆根山豆根山豆根士大夫 v 复古如图一要让他也让豆腐干豆腐干恢复人文 34 同仁堂也让图与体育体育风格恢复举报你不更符合瑞特瑞特让他感到给对方
    第 4 条附言  ·  2022-06-02 09:27:26 +08:00
    是豆腐干山豆根山豆根山豆根山豆根士大夫 v 复古如图一要让他也让豆腐干豆腐干恢复人文 34 同仁堂也让图与体育体育风格恢复举报你不更符合瑞特瑞特让他感到给对方
    第 5 条附言  ·  2022-06-02 09:27:40 +08:00
    是豆腐干山豆根山豆根山豆根山豆根士大夫 v 复古如图一要让他也让豆腐干豆腐干恢复人文 34 同仁堂也让图与体育体育风格恢复举报你不更符合瑞特瑞特让他感到给对方
    第 6 条附言  ·  2022-06-02 09:27:45 +08:00
    是豆腐干山豆根山豆根山豆根山豆根士大夫 v 复古如图一要让他也让豆腐干豆腐干恢复人文 34 同仁堂也让图与体育体育风格恢复举报你不更符合瑞特瑞特让他感到给对方
    第 7 条附言  ·  2022-06-02 09:27:49 +08:00
    是豆腐干山豆根山豆根山豆根山豆根士大夫 v 复古如图一要让他也让豆腐干豆腐干恢复人文 34 同仁堂也让图与体育体育风格恢复举报你不更符合瑞特瑞特让他感到给对方
    32 条回复    2021-01-28 12:12:32 +08:00
    xuanbg
        1
    xuanbg  
       2021-01-27 23:30:08 +08:00
    楼主你这个需求就触及 SQL 的盲区了……
    RedBeanIce
        2
    RedBeanIce  
       2021-01-27 23:31:24 +08:00
    正负这个。。。。。
    no1xsyzy
        3
    no1xsyzy  
       2021-01-27 23:59:47 +08:00
    如果有一个标记顺序的字段就行(比如自动编码)
    大致思路是分两步查询,第一步查询最后一个 score > 0 在哪行,第二步查出在那行之后有几行
    yzdobest
        4
    yzdobest  
       2021-01-28 00:05:31 +08:00 via iPhone
    https://mp.weixin.qq.com/s/d0fdqAzCE9FopNWBcMSYnw
    楼主可以参考下这篇文章
    dswyzx
        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

    另可以设计:如果这个功能要实时统计,不如加个字段作为连输次数字段,每次插入时读取上一条记录逻辑算一下,这样如果逻辑需要处理连输的人就读上一条即可
    LLLYang
        6
    LLLYang  
       2021-01-28 08:40:39 +08:00
    加个字段标记本局输赢情况不好么
    weizhen199
        7
    weizhen199  
       2021-01-28 09:00:41 +08:00
    lz 应该不是做统计的吧。

    前台用的话 decode + open window 应该就可以了

    慢的话,给 decode 列加上函数索引。
    Rache1
        8
    Rache1  
       2021-01-28 09:26:23 +08:00
    用 Redis 的 BitMap 来做~
    sarices
        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;
    ```
    gwbw
        10
    gwbw  
       2021-01-28 09:55:42 +08:00
    可能部分时序数据库有办法做,看看 timescaledb
    liuzhen
        11
    liuzhen  
       2021-01-28 10:01:01 +08:00
    这个需求和统计用户连续签到天数基本一致,网上能找到 sql
    liprais
        12
    liprais  
       2021-01-28 10:07:08 +08:00
    这个问题不就是在所有输的记录里面找到连续的么
    bugmakerxs
        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 的行数量
    lbmjsls1
        14
    lbmjsls1  
    OP
       2021-01-28 10:30:41 +08:00
    @sarices 这种方法不对,不是求历史连输的记录,是求最新连输的记录
    lbmjsls1
        15
    lbmjsls1  
    OP
       2021-01-28 10:35:32 +08:00
    @bugmakerxs 这种方法也不对,首先你应该说反了,找到最小的 id 或者小于最大的 id,另外,同样不能保证找到的这个 id 就是最后一条数据
    lbmjsls1
        16
    lbmjsls1  
    OP
       2021-01-28 10:43:12 +08:00
    @liuzhen 连续签到的也不行,连续签到的少了一个条件,也就是插入到数据库的数据肯定是有效的,可以使用判断连续了多少次,而输赢的是插入的数据有输的,有赢的,如果过滤掉其中的赢的,就是连续签到的问题,但是不符合我的需求
    sarices
        17
    sarices  
       2021-01-28 10:49:43 +08:00
    对的,tablename 是最新记录子查询就好了
    @lbmjsls1
    sarices
        18
    sarices  
       2021-01-28 10:50:42 +08:00
    @lbmjsls1 如果你不会,创建一个最新记录的视图也行,tablename 改为视图名称
    c6h6benzene
        19
    c6h6benzene  
       2021-01-28 10:54:45 +08:00 via iPhone
    count over partition by 胜负 order by 时间也许可解
    no1xsyzy
        20
    no1xsyzy  
       2021-01-28 11:00:26 +08:00
    @lbmjsls1 #13 就是我 #2 的思路。
    没反,是你僵掉了

    就是 reversed takewhile,放 SQL 里就是 count before first not
    no1xsyzy
        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

    但注意事务隔离级别,不可重复读会有问题。
    no1xsyzy
        22
    no1xsyzy  
       2021-01-28 11:05:42 +08:00
    草了,我还是把 < > 弄反了……

    X | reverse | takewhile _ => _.score < 0 | len
    等效于
    X | after (X | last _ => not _.score < 0) | len
    bugmakerxs
        23
    bugmakerxs  
       2021-01-28 11:10:48 +08:00
    @lbmjsls1 你再捋一捋,我看了半天没懂你回复我的是什么意思。
    bugmakerxs
        24
    bugmakerxs  
       2021-01-28 11:13:01 +08:00
    @lbmjsls1 我这个 sql 应该没问题
    liuzhen
        25
    liuzhen  
       2021-01-28 11:21:37 +08:00
    @lbmjsls1 你这个需求为什么加个字段记录连续输 /赢次数,在插入输赢的时候做个判断上次是输 /赢,来累加这个字段的次数呢?
    lbmjsls1
        26
    lbmjsls1  
    OP
       2021-01-28 11:51:28 +08:00
    @sarices 我又试了一边,这个确实是不对的,你写几个测试例子试试
    lbmjsls1
        27
    lbmjsls1  
    OP
       2021-01-28 11:52:50 +08:00
    @bugmakerxs 这个思路是对的,我想反了,不过有情况不对,就是如果玩家全是输的,那么就没有最后一个 id,那么统计下来就是 0.
    NeezerGu
        28
    NeezerGu  
       2021-01-28 11:55:25 +08:00
    hive 可以

    窗口函数加个 if, 再 row_number() over() 一下应该能出来
    dswyzx
        29
    dswyzx  
       2021-01-28 12:00:24 +08:00 via iPhone
    @lbmjsls1 #27 判断 isnull 呀,不存在置为 0
    sarices
        30
    sarices  
       2021-01-28 12:01:17 +08:00
    @lbmjsls1 不好意思,没看清楚你的问题,以为是计算胜负而已,参照这篇文章,应该可以解决你的问题 https://blog.csdn.net/u013887008/article/details/89105994
    kiracyan
        31
    kiracyan  
       2021-01-28 12:01:50 +08:00
    从游玩记录里统计有点费事 直接在用户表加一个字段插入游玩记录的时候更新
    bugmakerxs
        32
    bugmakerxs  
       2021-01-28 12:12:32 +08:00
    @lbmjsls1 嗯,那就里边 sql 加个判断,如果为 null 则设置为 0 就好了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1029 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 18:59 · PVG 02:59 · LAX 10:59 · JFK 13:59
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.