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

话说这两个 sql 为啥和我预想的不太一样

  •  
  •   luxinfl · 2020-11-03 10:36:20 +08:00 · 3016 次点击
    这是一个创建于 1483 天前的主题,其中的信息可能已经有所发展或是发生改变。
    select * from t1  where  not exists (select 1 from t2 where t1.name = t2.name)
    
    select * from t1  where exists (select 1 from t2 where t1.name != t2.name)
    

    我本意是找 t1 比 t2 多的数据,结果把 t1 的所有东西都返回了

    24 条回复    2020-11-03 14:56:35 +08:00
    BrettD
        1
    BrettD  
       2020-11-03 10:47:09 +08:00 via iPhone
    为啥要这样写
    luxinfl
        2
    luxinfl  
    OP
       2020-11-03 10:47:35 +08:00
    @BrettD 因为不存在嘛。。。
    luxinfl
        3
    luxinfl  
    OP
       2020-11-03 10:50:03 +08:00
    话说换成 in,比较容易看出来一下吧,应该是等价于
    ```
    select * from t1 where not in(select name from t2)
    第二个好像不太对
    ```
    wisunny
        4
    wisunny  
       2020-11-03 10:50:47 +08:00 via Android
    翻译成汉语就好理解多了,一个是不存在相等的,一个是存在不等的。而存在不等的只要存在一个就始终为 true,结果自然不一样
    chendy
        5
    chendy  
       2020-11-03 10:51:49 +08:00
    select 1 from t2 where t1.name != t2.name 这个…只要有不同的就有返回,于是就返回全部呗
    luxinfl
        6
    luxinfl  
    OP
       2020-11-03 11:06:57 +08:00
    @wisunny 那这个怎么遍历的啊,感觉怪怪的
    luxinfl
        7
    luxinfl  
    OP
       2020-11-03 11:08:19 +08:00
    @chendy 所以说第二个 sql 就相当于直接 select * from t1 ?
    chendy
        8
    chendy  
       2020-11-03 11:11:20 +08:00
    @luxinfl 也不是但是差不多,只要 t2 有数据,而且不全都和 t1 的 name 一样就有返回
    kiracyan
        9
    kiracyan  
       2020-11-03 11:12:04 +08:00
    select * from t1 where name not in (select name from t2)
    no1xsyzy
        10
    no1xsyzy  
       2020-11-03 11:21:31 +08:00   ❤️ 1
    @luxinfl 除非 t2 里只有一条
    把 SQL 重新写为集合推导式:

    式 1 等价于
    \{ x | x \in t1, \neg \exists_{y \in t2} (x.name = y.name) \}
    = \{ x | x \in t1, \forall_{y \in t2} (x.name \neq y.name) \}

    式 2 等价于
    \{ x | x \in t1, \exists_{y \in t2} (x.name \neq y.name) \}

    你觉得一样吗?
    luxinfl
        11
    luxinfl  
    OP
       2020-11-03 11:23:45 +08:00
    @chendy 但是我 t1 和 t2 的表数据一样,第二个 sql 还是有返回啊
    YYYYMMDDHHSS
        12
    YYYYMMDDHHSS  
       2020-11-03 11:25:46 +08:00
    翻译:1,对于 T1 的某一行,只要存在一行 T2.NAME == T1.NAME,就返回 T1.*;
    2,对于 T1 的某一行,只要存在一行 T2.NAME <> T1.NAME.就返回 T1.*; 那么哪怕真的只有一个 name 不在 T1 中,对于任何一个 T1 行都满足....
    no1xsyzy
        13
    no1xsyzy  
       2020-11-03 11:27:39 +08:00
    话说
    select * from t1 where name not in (select name from t2)

    select t1.* from t1 left join t2 on t1.name = t2.name where t2.name = null
    两个相比效率如何?

    但第二个可读性太差了,又要 t1.name = t2.name 又要 t2.name = null…… 还是我的(奇技淫巧)写法有问题?
    如果效率只稍高一点还是不要用 2,如果效率提升非常高那就加注释
    no1xsyzy
        14
    no1xsyzy  
       2020-11-03 11:29:29 +08:00
    @luxinfl 注意 “不全都和”
    这个 name 被认为 TLD 太傻了……
    顺便试试:
    `t1`.name [t1].name
    wolfie
        15
    wolfie  
       2020-11-03 11:30:00 +08:00
    t2 如果是空表,exists 直接返回 false 。
    第二条 sql 跟你需求不一样。
    luxinfl
        16
    luxinfl  
    OP
       2020-11-03 11:34:05 +08:00
    @no1xsyzy 第一个是不是相当于
    for x in t1:
    for y in t2:
    if(x.name == y.name):
    result.add(x)
    break;
    luxinfl
        17
    luxinfl  
    OP
       2020-11-03 11:34:46 +08:00
    @luxinfl 不对,条件写错了。。。
    no1xsyzy
        18
    no1xsyzy  
       2020-11-03 12:53:18 +08:00
    @luxinfl 啊,用 Python 解释的话这么写吧:
    式 1:
    [x for x in t1 if not any(x['name'] == y['name'] for y in t2)]
    根据反演律展开,其等价于
    [x for x in t1 if all(x['name'] != y['name'] for y in t2)]

    式 2:
    [x for x in t1 if any(x['name'] != y['name'] for y in t2)]

    一个是 all 一个是 any
    luxinfl
        19
    luxinfl  
    OP
       2020-11-03 13:47:00 +08:00
    @no1xsyzy 谢谢大佬,这么看我就懂了。。
    samv2
        20
    samv2  
       2020-11-03 13:51:35 +08:00
    找 t1 比 t2 多的,可以这样写
    select t1.* from t1
    left join t2
    on t1.name=t2.name
    where t2.name is null
    c6h6benzene
        21
    c6h6benzene  
       2020-11-03 14:03:52 +08:00 via iPhone
    @no1xsyzy #13 第二个就是标准的 sql 啊,一天到晚都写这种,name=name 是连接条件,where 是限制条件,不会读混的。另外要用 is null
    xdsty
        22
    xdsty  
       2020-11-03 14:07:16 +08:00
    直接左连接找悬空的记录就可以了
    luxinfl
        23
    luxinfl  
    OP
       2020-11-03 14:10:23 +08:00
    @samv2 这个是可以,我只是没搞太懂 exists 和 not exists 怎么玩的
    xiyangzuile
        24
    xiyangzuile  
       2020-11-03 14:56:35 +08:00
    第二条是因为 内部查询判断 t1.name !=t2.name 会导致永远都返回 true , 所以返回结果是 t1 的所有结果
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3138 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 13:51 · PVG 21:51 · LAX 05:51 · JFK 08:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.