• MySQL:至少参与xxx参与的全部事件


    MySQL:至少参与xxx参与的全部事件 – WhiteNight's Site

    标签:MySQL, 数据库

    这玩意,期末要考,还是重点。所以不得不仔细思考思考怎么写了。

    什么时候用NOT EXISTS

    双重否定表肯定

    之前虽然已经讲过了,不过那一篇文章讲的是参与了全部事件的xxx,而本文相比于那篇文章还多了一个限制条件:参与的是xxx参与的全部事件。

    等会我们会用具体例子来解释什么叫“参与了xxx参与的全部事件”,现在先来回顾一下什么时候要用嵌套NOT EXISTS查询。

    假设我要找出购买了全部商品的顾客,能用EXISTS吗?不行。因为EXISTS只要碰到任意一条匹配的记录就会退出循环,并返回true。

    那我们只能用NOT EXISTS去查询“没有购买全部商品的用户”,再在最外层套层NOT EXISTS,表示“查询不存在没有购买全部商品的用户”,原理总的来说就是:双重否定表肯定。

    具体例子

    查询至少参与了xxx参与的全部事件的对象

    首先理解这句话是啥意思:查询至少参与了A参与的全部事件的对象B。

    “至少”,那么意味着B除了参与了A参与的全部事件,还有可能参与了A没有参与的事件。

    但这部分我们并不需要管,我们只需要先查询出A参与了哪些事件,得到结果集firstset;再对firstset查询B是否有参与firstset中的全部事件,最后即可得到结果。

    这里以头歌的两道题为例。

    用 NOT EXISTS 实现查询至少参与过”202002020217″选手参与过的所有比赛的选手信息

    先筛选,再查询

    任务描述

    用 NOT EXISTS 实现查询至少参与过”202002020217″选手参与过的所有比赛的选手信息,contest_id不为NULL

    相关知识

    1、users为选手信息表; users表如下图(仅显示前几条):

    ,

    现已构建users表,结构信息如下:

    ,

    2、solution为选手提交的题目解答 solution表如下图(仅显示前几条):

    ,

    现已构建solution表,结构信息如下:

    ,

    怎么写呢?首先我们要先筛选,筛选出A参与了哪些比赛,再对得到的结果集进行二次筛选。

    单纯查询“A参与的全部比赛”并不难。However,在solution表中,contest_id可能为空,表示“该题目不属于任意比赛。所以我们要作个非空判断。

    1. SELECT *
    2. FROM solution AS B
    3. WHERE B.user_id='202002020217' AND B.contest_id IS NOT NULL

    此时我们得到了第一个结果集firstset。这个结果集包含了所有A参与的比赛。那么接下来就是进行二次筛选,找出哪些人参与的比赛都能在firstset中找到记录。

    那么最内层的NOT EXISTS就表示:

    • 如果有个B人对于A参与的任意比赛都没有参与,那它肯定不是我们要找的对象;
    • 如果有个B人只参与了部分A参与的比赛,虽然能匹配到部分比赛的记录,但是由于内层循环会匹配每一条记录,即它会去匹配所有A参与过的比赛。那么对于剩下B没参加的比赛而言它仍然找不到匹配的记录。

    上面这两种情况都会导致内层的NOT EXISTS最后返回true。而true对与最外层的NOT EXISTS而言,就相当于在告诉它:不要选择这些条件为true的记录。所以最后我们才能得到“参与了A参与的全部比赛的选手”。

    1. SELECT A.*
    2. FROM users AS A
    3. WHERE NOT EXISTS(
    4. SELECT 1
    5. FROM solution AS B
    6. WHERE B.user_id='202002020217' AND B.contest_id IS NOT NULL
    7. AND NOT EXISTS(
    8. SELECT 1
    9. FROM solution AS C
    10. WHERE A.user_id=C.user_id AND B.contest_id=C.contest_id
    11. )
    12. )

    总的来说,这种题的重点

    • 先对哪个结果集进行筛选?(条件筛选)
    • 最后得到的结果集应由哪些记录组成?(逐条筛选)
    • 条件有没有可能为NULL?(因为NOT EXISTS无法判断NULL,它会把所有为NULL的记录都当作“存在”并返回true)

    第7关:求至少用了供应商 S1所供应的全部零件的工程号 JNO

    先看懂题

    这种题要是能看懂题目,再套两个NOT EXISTS就差不多能写出来了。问题是能不能看懂题。

    任务描述

    求至少用了供应商 S1所供应的全部零件的工程号 JNO

    相关知识

    供应情况表SPJ由供应商代码(SNO)、零件代码(PNO)、工程项目代码(JNO)、供应数量(QTY)组成,标识某供应商 供应某种零件 给某工程项目的数量为QTY。 SPJ表如下图:

    ,

    现已构建SPJ表,结构信息如下:

    ,

    我反正是第一眼没看懂。什么玩意?什么叫用了供应商S1供应的全部零件?我看不懂啊。

    再仔细看看,S1就供应了两种零件,P1和P2。简单来说,这么长一句话浓缩之后就是:找出用过P1和P2的工程。我也真的是服了出题人了,这句子都能给你想到。

    那么还是老样子,先条件筛选再逐条筛选。条件是什么?S1生产的零件。那么先条件筛选

    1. SELECT B.*
    2. FROM SPJ AS B
    3. WHERE SNO='S1'

    接下来对上面得到的结果集firstset逐条筛选,也就是套两个NOT EXISTS

    1. SELECT DISTINCT A.JNO
    2. FROM SPJ AS A
    3. WHERE NOT EXISTS(
    4. SELECT B.*
    5. FROM SPJ AS B
    6. WHERE SNO='S1'
    7. AND NOT EXISTS(
    8. SELECT C.*
    9. FROM SPJ AS C
    10. WHERE B.PNO=C.PNO AND A.JNO=C.JNO
    11. )
    12. )

  • 相关阅读:
    03【深度学习】YOLOV3-WIN11环境搭建(配置+训练)
    外包干了2个月,技术退步明显...
    xcode打包macos报错:FlutterInputs.xcfilelist 和 FlutterOutputs.xcfilelist
    vue3自定义指令看完就入门!
    Matlab之并行程序设计实战教程
    51单片机仿真软件 Proteus 8 Pro 安装步骤
    关于回文判断(c语言版)
    高级同步机制:Phaser与CountDownLatch详解
    程序设计原则
    Selenium自动访问Firefox和Chrome并实现搜索截图
  • 原文地址:https://blog.csdn.net/white_night_SZTU/article/details/134067011