• 请不要在回答技术问题时复制粘贴 AI 生成的内容
movq
V2EX  ›  程序员

这到底是什么 SQL 语句

  •  1
     
  •   movq · Jul 12, 2021 · 6773 views
    This topic created in 1944 days ago, the information mentioned may be changed or developed.

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

    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 replies  •  2021-07-19 08:30:28 +08:00
    akira
    akira
    Jul 12, 2021
    1
    SELECT 后面不是接一个 output 吗?为什么可以在里面再写一个 SELECT ?
    把第二个 SELECT 的 output 作为 input 传递给 IN 函数。

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

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

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

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

    但是显然从数据流式处理角度描述要清晰准确地多,我不知道这语法是否存在歧义的情况,没有的话为什么各 SQL 引擎不进行两种语法同时支持呢?
    zbinlin
    zbinlin
    Jul 18, 2021
    32
    @no1xsyzy 因为 `∈` 符号不好打 😹
    no1xsyzy
    no1xsyzy
    Jul 19, 2021
    33
    @zbinlin 我说的支持两种语法是
    SELECT ... FROM ... WHERE ...
    和
    FROM ... WHERE ... SELECT ...
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   663 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 103ms · UTC 21:33 · PVG 05:33 · LAX 13:33 · JFK 16:33
    ♥ Do have faith in what you're doing.