美文网首页
Oracle中的连接查询讲解

Oracle中的连接查询讲解

作者: LeonardoEzio | 来源:发表于2019-02-28 17:18 被阅读0次

    最近在写需求的时候遇上一个连接查询的问题,趁此机会讲解下Oracle中的连接查询

    Oracle中主要的连接操作

    连接类型 说明
    INNER JOIN 内联接,结果为两个联接表中的匹配行的联接
    LEFT JOIN 左联接:结果包括左表(出现在JOIN子句最左边)中的所有行,不包括右表中的不匹配行
    RIGHT JOIN 右联接:结果包括右表(出现在JOIN子句最右边)中的所有行,不包括左表中的不匹配行
    FULL JOIN 完全联接:结果包括所有联接中的所有行,不论他们是否匹配
    CROSS JOIN 交叉联接:结果包括两个联接表中的所有可能的行组合,交叉连接返回的是两个表的笛卡儿积(Oracle不支持)
    NATURAL JOIN 自然连接时在两张表中寻找那些数据类型 和列名都相等的字段,然后自动地将他们连接起来

    不同的联接类型决定了如何处理联接条件中不匹配的元素,接下来就以左联接为例来描述我所遇到的问题。

    示例所需SQL脚本

    此处直接选用了我在项目中的数据脚本,有需要的可以直接download下来操作

    1. https://github.com/LeonardoEzio/Oracle-Join/blob/master/SQL/FORE_TICKET_CANCEL.sql
    2. https://github.com/LeonardoEzio/Oracle-Join/blob/master/SQL/FORE_TICKETCANCEL_SEGMENT.sql

    在Idea 中执行SQL脚本

    1. 首先将所下载的sql脚本放入工程目录中,如下图:


      SQL脚本所在工程目录结构.png
    2. 在打开的SQL文件中按 Ctrl + Shift + F10 在弹出的页面中选择在哪个库执行即可(本列使用的是oracle数据库)


      数据库选择.png

    本人所遇问题描述

    • 问题1:

    执行SQL片段1

    SELECT
      FTC.FTC_TICKETCANCEL_NO,
      FTC.FTC_TA_NO AS TA_NO,
      FTS.FTCS_ARR_DATE AS ARR_DATE,
      FTS.FTCS_DEP_DATE AS DEP_DATE,
      FTC.FTC_CREATEDATATIME AS createTm
    FROM FORE_TICKET_CANCEL FTC
      LEFT  JOIN  FORE_TICKETCANCEL_SEGMENT FTS
        ON FTC.FTC_TICKETCANCEL_NO =  FTS.FTCS_TICKETCANCEL_NO
        AND FTC.FTC_TA_NO='2019021900003';--查询结果 3657条记录
    
    SELECT FTC.* FROM FORE_TICKET_CANCEL FTC;-- 主表(左表FTC)记录总数 3657
    
    SELECT
      FTC.FTC_TICKETCANCEL_NO,
      FTC.FTC_TA_NO AS TA_NO,
      FTS.FTCS_ARR_DATE AS ARR_DATE,
      FTS.FTCS_DEP_DATE AS DEP_DATE,
      FTC.FTC_CREATEDATATIME as createTm
    FROM FORE_TICKETCANCEL_SEGMENT FTS
      LEFT JOIN FORE_TICKET_CANCEL FTC
        ON FTS.FTCS_TICKETCANCEL_NO = FTC.FTC_TICKETCANCEL_NO
        AND FTC.FTC_TA_NO='2019021900003';--查询结果 4669条记录
    
    SELECT FTS.* FROM FORE_TICKETCANCEL_SEGMENT FTS;-- 主表(左表FTS)记录总数 4669
    

    执行SQL片段2

    SELECT
      FTC.FTC_TICKETCANCEL_NO,
      FTC.FTC_TA_NO AS TA_NO,
      FTS.FTCS_ARR_DATE AS ARR_DATE,
      FTS.FTCS_DEP_DATE AS DEP_DATE,
      FTC.FTC_CREATEDATATIME as createTm
    FROM FORE_TICKET_CANCEL FTC
      LEFT  JOIN  FORE_TICKETCANCEL_SEGMENT FTS
      ON FTC.FTC_TICKETCANCEL_NO =  FTS.FTCS_TICKETCANCEL_NO;--查询结果 4669条记录
    
    SELECT FTC.* FROM FORE_TICKET_CANCEL FTC;-- 主表(左表FTC)记录总数 3657
    
    SELECT
      FTC.FTC_TICKETCANCEL_NO,
      FTC.FTC_TA_NO AS TA_NO,
      FTS.FTCS_ARR_DATE AS ARR_DATE,
      FTS.FTCS_DEP_DATE AS DEP_DATE,
      FTC.FTC_CREATEDATATIME as createTm
    FROM FORE_TICKETCANCEL_SEGMENT FTS
      LEFT JOIN FORE_TICKET_CANCEL FTC
      ON FTS.FTCS_TICKETCANCEL_NO = FTC.FTC_TICKETCANCEL_NO;--查询结果 4669条记录
    
    SELECT FTS.* FROM FORE_TICKETCANCEL_SEGMENT FTS;-- 主表(左表FTS)记录总数 4669
    

    执行SQL片段1的时候,所产生的结果大家可能没什么异议,左连接查询以主表数据为主,所以连接查询的结果与主表记录条数一致容易理解,然后当我们去掉SQL片段1的AND条件后,发现SQL片段2中的第一段SQL执行结果与主表中的记录条数不一致。

    根据如上对左连接的定义左联接查询出的结果包括左表(出现在JOIN子句最左边)中的所有行,不包括右表中的不匹配行。SQL片段2中的第一段SQL查询出的结果与右表中的总记录条数一致,说明了右表中的数据全部匹配上了。为了证实这个结论,我们只需将右边中的数据修改一下,使其中一条数据与左表关联不上,那么最后的查询结果应该是比4669少一条的。

    首先,我们通过如下图所示的SQL查询出在右表中出现多次的FTCS_TICKETCANCEL_NO(因为联结是基于这个字段)。

    SQL与查询结果.png

    第二步,选取其中一条结果为条件去查询右表(FTS)中记录,并修改其中一条记录的FTCS_TICKETCANCEL_NO字段值,使其与左表关联不上。

    修改前.png
    修改后.png

    修改后的值我们要记住,因为要之后要还原进行后续的操作。然后再执行SQL片段2中的第一条SQL如果查询出的结果为4668条的话说明我们的猜测成立。

    查询结果.png
    • 问题2:

    接着我尝试修改了下如下SQL片段3中AND后的FTC_TA_NO参数值,又发现不一样的结果。在进行以下操作之前记得恢复问题1中的数据修改。

    SQL片段3

    SELECT
      FTC.FTC_TICKETCANCEL_NO,
      FTC.FTC_TA_NO AS TA_NO,
      FTS.FTCS_ARR_DATE AS ARR_DATE,
      FTS.FTCS_DEP_DATE AS DEP_DATE,
      FTC.FTC_CREATEDATATIME as createTm
    FROM FORE_TICKET_CANCEL FTC
      LEFT  JOIN  FORE_TICKETCANCEL_SEGMENT FTS
        ON FTC.FTC_TICKETCANCEL_NO =  FTS.FTCS_TICKETCANCEL_NO
        AND FTC.FTC_TA_NO='2019021900003';--查询结果 3657条记录
    
    SELECT FTC.* FROM FORE_TICKET_CANCEL FTC;-- 主表(左表FTC)记录总数 3657
    

    SQL片段4

    SELECT
      FTC.FTC_TICKETCANCEL_NO,
      FTC.FTC_TA_NO AS TA_NO,
      FTS.FTCS_ARR_DATE AS ARR_DATE,
      FTS.FTCS_DEP_DATE AS DEP_DATE,
      FTC.FTC_CREATEDATATIME as createTm
    FROM FORE_TICKET_CANCEL FTC
      LEFT  JOIN  FORE_TICKETCANCEL_SEGMENT FTS
        ON FTC.FTC_TICKETCANCEL_NO =  FTS.FTCS_TICKETCANCEL_NO
        AND FTC.FTC_TA_NO='2019021900004';--查询结果 3660条记录
    
    SELECT FTC.* FROM FORE_TICKET_CANCEL FTC;-- 主表(左表FTC)记录总数 3657
    

    SQL片段5

    SELECT
      FTC.FTC_TICKETCANCEL_NO,
      FTC.FTC_TA_NO AS TA_NO,
      FTS.FTCS_ARR_DATE AS ARR_DATE,
      FTS.FTCS_DEP_DATE AS DEP_DATE,
      FTC.FTC_CREATEDATATIME as createTm
    FROM FORE_TICKET_CANCEL FTC
      LEFT  JOIN  FORE_TICKETCANCEL_SEGMENT FTS
        ON FTC.FTC_TICKETCANCEL_NO =  FTS.FTCS_TICKETCANCEL_NO
        AND FTC.FTC_TA_NO='2019021900005';--查询结果 3658条记录
    
    SELECT FTC.* FROM FORE_TICKET_CANCEL FTC;-- 主表(左表FTC)记录总数 3657
    

    解释之前我们再重申以下左联接查询所产生的结果集 :包括左表(出现在JOIN子句最左边)中的所有行,加上右表中的匹配行。

    到这里我们应该明白了FORE_TICKET_CANCEL表中的数据与FORE_TICKETCANCEL_SEGMENT中的数据是 1 : N的关系。

    首先,我们来看SQL片段3中。SQL再执行查询的时候会根据FTC.FTC_TA_NO='2019021900003' 时 所对应的FTC.FTC_TICKETCANCEL_NO 在右表(FTS)中的记录条数来生成查询结果。


    image1.png

    接下来以image1的查询结果,为条件去查询右边(FTS)中符号条件的记录条数。


    image2.png

    最后可以得出以下结论,SQL片段三的最终结果 = 左表的记录条数 + (image1 与 image2 记录条数的差)

    • SQL片段4论证:
    image1.png image2.png

    所以执行SQL片段4的所得的记录条数 = 左表(FTC)总记录数 + (image2记录条数 - image1记录条数)= 3657 + (4-1)= 3660

    • SQL片段5论证:
      image1.png
    image2.png

    所以执行SQL片段5所得的记录条数 = 左表(FTC)总记录数 + (image2记录条数 - image1记录条数)= 3657 + (2-1)= 3658


    以上就是本人对Oracle中左联结查询所做的讲解,如示例中有错误的地方,请在评论中指正!

    相关文章

      网友评论

          本文标题:Oracle中的连接查询讲解

          本文链接:https://www.haomeiwen.com/subject/ltwhuqtx.html