V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
s609926202
V2EX  ›  数据库

请教一个关于 MySQL 子查询的问题

  •  
  •   s609926202 · 2021-06-10 19:58:41 +08:00 · 1775 次点击
    这是一个创建于 1241 天前的主题,其中的信息可能已经有所发展或是发生改变。

    准备一张表:t_user

    首先,按年龄和性别进行分组:select id from t_user where 1=1 group by sex,age,有 4 条结果,ID 分别为:3,5,7,9

    然后,我按照子查询的方式:select * from t_user where id in (select id from t_user where 1=1 group by sex,age) order by id,却超出了 4 条结果,而子查询体正是上一个分组查询的结果。

    所以请教一下,为何把分组查询的结果放到子查询,再次查询时结果不是分组查询的结果呢?

    19 条回复    2021-06-12 12:53:01 +08:00
    JasonLaw
        1
    JasonLaw  
       2021-06-10 20:37:07 +08:00 via iPhone
    描述一下你的重现步骤吧,不然都是靠猜。还有,你的写法真的很奇怪。
    c6h6benzene
        2
    c6h6benzene  
       2021-06-10 21:07:03 +08:00 via iPhone
    where 1=1 是为了啥…

    话说我主要写 t-sql 的,看到 group by 没有聚合函数总觉得浑身不自在。
    aragakiyuii
        3
    aragakiyuii  
       2021-06-10 22:07:34 +08:00 via iPhone
    select 的 column 不应该是在 group by 里吗?

    https://dev.mysql.com/doc/refman/8.0/en/group-by-handling.html

    If ONLY_FULL_GROUP_BY is disabled, a MySQL extension to the standard SQL use of GROUP BY permits the select list, HAVING condition, or ORDER BY list to refer to nonaggregated columns even if the columns are not functionally dependent on GROUP BY columns. This causes MySQL to accept the preceding query. In this case, the server is free to choose any value from each group, so unless they are the same, the values chosen are nondeterministic, which is probably not what you want. Furthermore, the selection of values from each group cannot be influenced by adding an ORDER BY clause. Result set sorting occurs after values have been chosen, and ORDER BY does not affect which value within each group the server chooses. Disabling ONLY_FULL_GROUP_BY is useful primarily when you know that, due to some property of the data, all values in each nonaggregated column not named in the GROUP BY are the same for each group.
    Euthpic
        4
    Euthpic  
       2021-06-10 23:37:46 +08:00   ❤️ 1
    如果 id 是唯一值,那么第二条查询的数目等于第一条,如果不是就大于第一条.

    @c6h6benzene 为了 SQL 拼装,后面要加条件的话都是 and xxx=aaa.
    NotFoundEgg
        5
    NotFoundEgg  
       2021-06-10 23:50:06 +08:00
    可以考虑把子查询的结果 放在 select * from t_user where id in () 里试下有几条
    T0m008
        6
    T0m008  
       2021-06-11 07:34:41 +08:00
    你这是要按照年龄性别排序么?你先描述一下,你这查询写的没什么意义
    xiangyuecn
        7
    xiangyuecn  
       2021-06-11 09:25:06 +08:00
    一看就知道是低版本 mysql,居然无理取闹的支持 select AA group by BB 😂 mysql 自己都看不下去了
    sanggao
        8
    sanggao  
       2021-06-11 09:33:25 +08:00
    @xiangyuecn 高版本也支持,5.6 5.7 5.8 都支持 也有啥问题?
    enderftt
        9
    enderftt  
       2021-06-11 09:46:25 +08:00
    仅有 mysql 有这种写法 你把 sex ,age 也放到结果列里面就知道了
    s609926202
        10
    s609926202  
    OP
       2021-06-11 10:06:23 +08:00
    @T0m008 实际查询大概也是这个意思。
    s609926202
        11
    s609926202  
    OP
       2021-06-11 10:07:30 +08:00
    @enderftt
    放到结果列?
    s609926202
        12
    s609926202  
    OP
       2021-06-11 10:09:59 +08:00
    @NotFoundEgg 子查询结果放在 select * from t_user where id in () 里,有几个 id 就有几条结果。
    s609926202
        13
    s609926202  
    OP
       2021-06-11 10:10:30 +08:00
    @c6h6benzene where 中 1=1 查询全部结果
    xiangyuecn
        14
    xiangyuecn  
       2021-06-11 10:16:29 +08:00
    @sanggao #8 说的就是 5.x == 低版本😂
    c6h6benzene
        15
    c6h6benzene  
       2021-06-11 10:44:33 +08:00
    @s609926202 主要不写 1=1 也是全部结果,除非是后续有拼接需求,不然这部分就是多此一举。

    就跟 @Euthpic 说的,你这 ID 可能会有重复,你看看每个 ID 有几条就知道了:

    select id, COUNT(id) from t_user group by id
    sanggao
        16
    sanggao  
       2021-06-11 11:49:53 +08:00
    @xiangyuecn 啥意思啊 这个语法 mysql 全部版本都支持,你说的是什么版本不支持?
    sanggao
        17
    sanggao  
       2021-06-11 11:50:57 +08:00
    @xiangyuecn mysql 最高版本现在就是 5.8 也支持
    kisick
        18
    kisick  
       2021-06-11 12:37:06 +08:00 via iPhone
    @sanggao 5.7 以上,默认就不支持了,需要改配置文件
    512357301
        19
    512357301  
       2021-06-12 12:53:01 +08:00 via Android
    你是想取每个分组的第一个 id 对吧?
    这种写法是第一次见,不过也可以理解,5.8 以下版本不支持开窗函数,只能这样写

    你可以尝试把你的第一段 sql 作为左表,括起来后,别名 temp_a,然后 left join t_user 表,on temp_a.id = t_user.id
    然后,select t_user.*

    看下结果是否符合要求(想当于把子查询变成了虚拟表,效率应该也会高一些)
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2854 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 14:28 · PVG 22:28 · LAX 07:28 · JFK 10:28
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.