V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
klausgao
V2EX  ›  程序员

这个需求能用一条 sql 完成吗?

  •  
  •   klausgao · 2017-08-11 09:43:38 +08:00 · 4192 次点击
    这是一个创建于 2666 天前的主题,其中的信息可能已经有所发展或是发生改变。
    一个用户发帖的 table,能用一条 sql 选出每个用户最新的那条帖子吗?
    例如 table 里的数据:
    id userName post postDate
    1 AA content1 2017-1-1
    2 AA content2 2017-1-2
    3 BB content3 2017-1-3
    4 BB content4 2017-1-4

    sql 选择后,得到结果集:
    id userName post postDate
    2 AA content2 2017-1-2
    4 BB content4 2017-1-4

    想了几天,不得其解。
    第 1 条附言  ·  2017-08-11 10:41:51 +08:00
    没有说清楚,我是用 mysql 的
    27 条回复    2017-08-12 15:06:18 +08:00
    daimazha
        1
    daimazha  
       2017-08-11 09:52:34 +08:00
    给你个思路:
    select * from x where id in ( select max(id) from x group by name);
    klausgao
        2
    klausgao  
    OP
       2017-08-11 10:00:17 +08:00
    谢谢,我去试试
    @daimazha
    HaoC12
        3
    HaoC12  
       2017-08-11 10:05:44 +08:00
    @daimazha 应该是选出 postdate 最大的吧
    klausgao
        4
    klausgao  
    OP
       2017-08-11 10:05:45 +08:00
    @daimazha 另外多问一句,我记得 in 的效率比较低,是不是这样呢?
    klausgao
        5
    klausgao  
    OP
       2017-08-11 10:06:22 +08:00
    @HaoC12 稍微改一下就好了,@daimazha 给出的是思路。
    LeeSeoung
        6
    LeeSeoung  
       2017-08-11 10:11:04 +08:00   ❤️ 1
    select distinct id,userName,post,max(postDate)over(partition by id,userName,post) from xxx
    LeeSeoung
        7
    LeeSeoung  
       2017-08-11 10:11:52 +08:00
    前提 postDate 得是 date 类型的,不是的话自己转换下
    ayumilove
        8
    ayumilove  
       2017-08-11 10:12:27 +08:00
    子查询结果比较大,建议用 exists
    ayumilove
        9
    ayumilove  
       2017-08-11 10:14:43 +08:00
    要是 Oracle 6 楼 的好~
    daimazha
        10
    daimazha  
       2017-08-11 10:28:11 +08:00
    @klausgao #2

    子查询效率不是很高,
    这个场景 in 和 exists 没区别,
    id 自增,最大的就是最新的一条,用 postdata 不如用主键 id
    daya0576
        11
    daya0576  
       2017-08-11 10:28:28 +08:00
    select * from (select * from <table> ORDER BY archiveTime DESC) as tmp GROUP BY tmp.userName
    这样也行把, 但不知道效率如何.
    CRVV
        12
    CRVV  
       2017-08-11 10:32:49 +08:00
    @ayumilove
    跟 Oracle 有什么关系,除了 MySQL 和 SQLite,其它的数据库都支持
    daya0576
        13
    daya0576  
       2017-08-11 10:35:56 +08:00
    如果有用**Django ORM**的同学可以参考这篇: https://changchen.me/blog/20170515/ele-interview-solution/
    用 annotate 实现楼主想要的效果 ^_^
    nullcc
        14
    nullcc  
       2017-08-11 10:42:52 +08:00
    select A.userName, postDate, post from table A
    inner join
    (select distinct userName, max(postDate) as maxPostDate
    from table
    group by userName) B
    on A.userName = b.userName and A.postDate = B.maxPostDate

    大概是这样
    anoymoux
        15
    anoymoux  
       2017-08-11 10:50:45 +08:00
    加一张表 latest_post(userid,postid)
    ayumilove
        16
    ayumilove  
       2017-08-11 11:11:44 +08:00
    @CRVV 恩,谢谢。 好多年没用过 mysql 了 ,还以为原生 不支持 over(partition by ~)
    x7395759
        17
    x7395759  
       2017-08-11 11:47:20 +08:00
    加表是一个不错的想法,view 也行呀。
    noNOno
        18
    noNOno  
       2017-08-11 11:55:03 +08:00
    select * from (select *,row_number over (partition by userName order by postdate desc ) as rn from table ) where rn=1

    能用 rownumber 吧
    syncher
        19
    syncher  
       2017-08-11 11:59:51 +08:00 via Android
    又是一个 group
    fxxkgw
        20
    fxxkgw  
       2017-08-11 12:44:17 +08:00
    order by 加 group by
    jeffpan
        21
    jeffpan  
       2017-08-11 14:58:20 +08:00
    SELECT max(login_time) ,user_id ,browser from tb_system_user_login_log group by user_id
    我本地有个类似表,好像这样是可以的。
    Buffer2Disk
        22
    Buffer2Disk  
       2017-08-11 15:02:30 +08:00
    @daimazha 的思路不错,但是如果 id 不是自增的,而是通过 uuid 生成的,这个时候下面这个方法可以解决问题。


    select b.*
    from (
    select
    max(post_date) as post_date,
    user_name
    from article
    group by user_name) as a
    inner join article b ON a.post_date = b.post_date AND a.user_name = b.user_name;

    把用户的名字和发帖时间作为一个联合主键来处理。
    daemonghost
        23
    daemonghost  
       2017-08-11 16:21:14 +08:00 via Android
    先按用户名分组,然后再按日期排序,选取指定个数就行了
    beginor
        24
    beginor  
       2017-08-11 16:39:31 +08:00 via Android
    最佳的方案是 `row_number` + `partition` , 但是 MySQL 不支持
    finull
        25
    finull  
       2017-08-11 21:09:55 +08:00
    select * from table t where not exists ( select * from table where userName = t.userName and postDate > t.postDate );

    不要用聚合什么的
    lenmore
        26
    lenmore  
       2017-08-12 10:34:29 +08:00
    终极做法是:
    当用户发帖时,将最新的 ID 记录到用户表或者单独的一张表。更极端一点把标题时间都冗余了。
    查询时 Join 帖子。
    tsotsi
        27
    tsotsi  
       2017-08-12 15:06:18 +08:00
    ```sql
    select *,if(@lastOne=userName,'',@lastOne:=userName) flag from (select * from table order by userName,postDate desc) a,(select @lastOne :='')b where flag <> ''
    ```
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5769 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 03:20 · PVG 11:20 · LAX 19:20 · JFK 22:20
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.