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

这到底是什么 SQL 语句

  •  1
     
  •   movq · 148 天前 · 4620 次点击
    这是一个创建于 148 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    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  
       148 天前
    SELECT 后面不是接一个 output 吗?为什么可以在里面再写一个 SELECT ?
    把第二个 SELECT 的 output 作为 input 传递给 IN 函数。

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

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

    不过你的问题描述的仔细,格式真不错,我之前提问,描述的没你直观。
    hanssx
        19
    hanssx  
       148 天前
    确实有点反直觉,第 1 个是相关子查询,第 2 个是不相关子查询,如果相关子查询没优化的情况下,效率应该比不相关子查询低?
    way2explore2
        20
    way2explore2  
       148 天前
    SUBQuery liao jie yi xia
    yolee599
        21
    yolee599  
       148 天前 via Android
    这叫子查询,基本操作
    huigeer
        22
    huigeer  
       148 天前
    万物皆可子查询
    levon
        23
    levon  
       147 天前
    order by (select ....)
    landfill
        24
    landfill  
       147 天前
    这是 andy pavlo 的课吗 我今天也刚看到这里
    movq
        25
    movq  
    OP
       147 天前
    snw
        26
    snw  
       147 天前 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  
       147 天前
    楼上的解释就比较清楚了
    zhangysh1995
        28
    zhangysh1995  
       147 天前
    上面都没回答到点上。。
    楼主应该问的是为什么我们在一个子语句使用了外层的 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  
       147 天前   ❤️ 1
    楼主如果要知道更多一些关于 SQL 的理论知识,可以考虑看 https://db.inf.uni-tuebingen.de/team/TorstenGrust.html 这位教授的课程,youtube 有视频。CMU 的课程重点是数据库系统本身和现代系统应用,而不是 SQL 。
    Divinook
        30
    Divinook  
       147 天前 via Android
    @zhangysh1995 exists 也使用外层的字段,楼主应该问的就是 select 为什么也可以用子语句
    no1xsyzy
        31
    no1xsyzy  
       147 天前   ❤️ 2
    @snw 准确地说不是为了迎合英文语法,而是因为它是拟似数学上的集合推导式 comprehension

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

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

    FROM ... WHERE ... SELECT ...
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   4314 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 06:13 · PVG 14:13 · LAX 22:13 · JFK 01:13
    ♥ Do have faith in what you're doing.