V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
movq
V2EX  ›  程序员

这到底是什么 SQL 语句

  •  1
     
  •   movq · 2021-07-12 21:32:24 +08:00 · 5657 次点击
    这是一个创建于 1259 天前的主题,其中的信息可能已经有所发展或是发生改变。

    有点看不懂下面的第一段语句。

    SELECT 后面不是接一个 output 吗?为什么可以在里面再写一个 SELECT ?

    SELECT (SELECT S.name FROM student AS S
    	WHERE S.sid = E.sid) AS sname
       
    FROM enrolled as E
    WHERE cid='15-455'
    

    第二段语句和第一段语句的效果是一样的,但是第二段就很好理解。把第二个 SELECT 的 output 作为 input 传递给 IN 函数。

    SELECT name FROM student
    
    WHERE sid IN ( 
    	SELECT sid FROM enrolled
        WHERE cid = '15-445'
    )
    

    这里面是原始表格:

    gA5OszQe4ZPySiw

    33 条回复    2021-07-19 08:30:28 +08:00
    akira
        1
    akira  
       2021-07-12 21:47:32 +08:00
    SELECT 后面不是接一个 output 吗?为什么可以在里面再写一个 SELECT ?
    把第二个 SELECT 的 output 作为 input 传递给 IN 函数。

    你自己的这 2 句话,再琢磨琢磨?
    xcstream
        2
    xcstream  
       2021-07-12 22:04:30 +08:00
    结果可以作为一个表
    WalkerCeng
        3
    WalkerCeng  
       2021-07-12 22:05:56 +08:00
    建议复习一下 MySQL
    movq
        4
    movq  
    OP
       2021-07-12 22:06:41 +08:00
    @akira 你的意思是第一个 query 里面,括号包着的那个部分,作为一个 output,传递给括号外面的 SELECT 吗?
    movq
        5
    movq  
    OP
       2021-07-12 22:06:56 +08:00
    @WalkerCeng 正在从 0 开始学
    JamesMackerel
        6
    JamesMackerel  
       2021-07-13 00:55:16 +08:00 via iPhone
    关键字:子查询
    Rocketer
        7
    Rocketer  
       2021-07-13 01:08:35 +08:00 via iPhone
    各个部分皆可子查询,只要输出的结果符合那个部分的格式即可
    xiangyuecn
        8
    xiangyuecn  
       2021-07-13 09:00:31 +08:00
    select (select count(...) from A ...) from B ... 这种写法 我这用的非常多 简直到了出神入化的境界🐶😂 通用性极强 基本上无法用其他写法来改写 否则要么看不懂要么性能极低
    l0ve1o24
        9
    l0ve1o24  
       2021-07-13 09:07:44 +08:00
    @xiangyuecn 可以用外连接,然后 sum(case when A.id is not null then 1 else 0) ,我记得这样好像速度会快一点
    css3
        10
    css3  
       2021-07-13 09:12:27 +08:00   ❤️ 1
    发帖格式点赞,楼主需要看下 sql 最基础的语法
    dk7952638
        11
    dk7952638  
       2021-07-13 09:18:22 +08:00   ❤️ 1
    @xiangyuecn 这种写法可读性差,但性能真的比 join 要高很多
    qwer666df
        12
    qwer666df  
       2021-07-13 09:18:22 +08:00
    子查询的基操, 好几种变换格式, 贴个链接: https://www.cnblogs.com/CL-King/p/13730529.html
    aguesuka
        13
    aguesuka  
       2021-07-13 09:24:35 +08:00
    https://docs.oracle.com/cd/E11882_01/server.112/e41084/expressions013.htm#SQLRF52093
    Scalar Subquery Expressions

    这是为什么 SQL 没有静态安全的万恶之源之一
    xiangyuecn
        14
    xiangyuecn  
       2021-07-13 09:42:23 +08:00
    @l0ve1o24 #9 @dk7952638 #11 子查询是多个结果的聚合查询(留意我那个是 count,实际操作中是很多个带 count 的子查询),基本上无法用简单的 join 来改写,强行 join 结果集必然指数级暴增
    onionKnight888
        15
    onionKnight888  
       2021-07-13 10:11:52 +08:00
    我们业务系统如果用 oracle 的话,基本上都是这种子查询
    chanchan
        16
    chanchan  
       2021-07-13 10:27:41 +08:00
    垃圾 DSL 确实恶心
    aliveyang
        17
    aliveyang  
       2021-07-13 11:09:20 +08:00
    你把他看作程序一步一步执行就行了,只要格式输出符合,怎么玩都可以
    sytnishizuiai
        18
    sytnishizuiai  
       2021-07-13 11:35:54 +08:00
    这种可以写的,而且有时候情况复杂的时候还不得不这么写。

    不过你的问题描述的仔细,格式真不错,我之前提问,描述的没你直观。
    hanssx
        19
    hanssx  
       2021-07-13 11:39:35 +08:00
    确实有点反直觉,第 1 个是相关子查询,第 2 个是不相关子查询,如果相关子查询没优化的情况下,效率应该比不相关子查询低?
    way2explore2
        20
    way2explore2  
       2021-07-13 11:50:25 +08:00
    SUBQuery liao jie yi xia
    yolee599
        21
    yolee599  
       2021-07-13 12:37:57 +08:00 via Android
    这叫子查询,基本操作
    huigeer
        22
    huigeer  
       2021-07-13 12:39:06 +08:00
    万物皆可子查询
    levon
        23
    levon  
       2021-07-13 15:44:38 +08:00
    order by (select ....)
    landfill
        24
    landfill  
       2021-07-13 16:21:41 +08:00
    这是 andy pavlo 的课吗 我今天也刚看到这里
    movq
        25
    movq  
    OP
       2021-07-13 16:35:52 +08:00
    snw
        26
    snw  
       2021-07-13 17:37:36 +08:00 via Android   ❤️ 4
    其实吧,SQL 真实的逻辑顺序是:
    FROM ... //从某个表中
    WHERE ... //筛选出某些行
    SELECT ... //返回这些行的某些列的数据

    只是为了迎合英文的语法习惯所以规定成了 SELECT ... FROM ... WHERE ...

    所以改写一下就比较符合人类阅读了(虽然 SQL 会报错):

    FROM enrolled as E
    WHERE cid='15-455'
    SELECT (
    FROM student AS S
    WHERE S.sid = E.sid
    SELECT S.name
    ) AS sname
    zxCoder
        27
    zxCoder  
       2021-07-13 18:08:01 +08:00
    楼上的解释就比较清楚了
    zhangysh1995
        28
    zhangysh1995  
       2021-07-13 18:17:55 +08:00
    上面都没回答到点上。。
    楼主应该问的是为什么我们在一个子语句使用了外层的 E.sid 。
    这里需要知道表是否存在 index 。
    在有 index 的情况下,第一条语句首先 cid 过滤,然后再比较 S.did = E.sid 的时候,可以直接使用 index,速度比第二条的 IN 要快非常多。因为有 E.sid 的值可以直接 hash index 看 S.sid 的数据置是否存在,只有 E.sid 数量的比较次数 O(E.sid)。
    但是对于 IN 来说,它需要比每一条 S.sid 是否在 IN 后面的结果里面,没有 index 情况下 IN 的复杂度是 O(E.sid * S.sid),有 index 情况下 IN 的复杂度是 O(E.sid) 。
    这里说的都是理论的复杂度,实际数据库实现中 IN 不一定可以用 index 。
    另外一个区别是,因为第一条用了 scalar function, 在进行 cid 过滤的时候,满足的一行会直接送给子查询去判断 S.sid = E.sid 是否存在(这里是因为行变量的值可以传递到子查询),第二条是做完了过滤才去用 IN 查询,所以速度会变慢。
    zhangysh1995
        29
    zhangysh1995  
       2021-07-13 18:21:16 +08:00   ❤️ 1
    楼主如果要知道更多一些关于 SQL 的理论知识,可以考虑看 https://db.inf.uni-tuebingen.de/team/TorstenGrust.html 这位教授的课程,youtube 有视频。CMU 的课程重点是数据库系统本身和现代系统应用,而不是 SQL 。
    Divinook
        30
    Divinook  
       2021-07-13 18:51:21 +08:00 via Android
    @zhangysh1995 exists 也使用外层的字段,楼主应该问的就是 select 为什么也可以用子语句
    no1xsyzy
        31
    no1xsyzy  
       2021-07-14 09:51:12 +08:00   ❤️ 2
    @snw 准确地说不是为了迎合英文语法,而是因为它是拟似数学上的集合推导式 comprehension

    Y = { x | x ∈ X, x < 10 }
    SELECT x FROM X WHERE x < 10

    但是显然从数据流式处理角度描述要清晰准确地多,我不知道这语法是否存在歧义的情况,没有的话为什么各 SQL 引擎不进行两种语法同时支持呢?
    zbinlin
        32
    zbinlin  
       2021-07-18 19:35:29 +08:00
    @no1xsyzy 因为 `∈` 符号不好打 😹
    no1xsyzy
        33
    no1xsyzy  
       2021-07-19 08:30:28 +08:00
    @zbinlin 我说的支持两种语法是
    SELECT ... FROM ... WHERE ...

    FROM ... WHERE ... SELECT ...
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1302 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 75ms · UTC 17:19 · PVG 01:19 · LAX 09:19 · JFK 12:19
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.