【问题标题】:Choosing the correct join in SQL Oracle在 SQL Oracle 中选择正确的连接
【发布时间】:2015-05-28 17:44:35
【问题描述】:

给定以下表格:

CREATE TABLE TrainInfo
  (
    Trainnumber       INTEGER NOT NULL ,
    nbSits1st         INTEGER NOT NULL ,
    nbAvail1st        INTEGER NOT NULL ,
    nbSits2e          INTEGER NOT NULL ,
    nbAvail2e         INTEGER NOT NULL ,
    Journey_journeyID INTEGER NOT NULL
  ) ;
ALTER TABLE TrainInfo ADD CONSTRAINT TrainInfo_PK PRIMARY KEY ( Trainnumber) ;


CREATE TABLE Journey
  (
    journeyID     INTEGER NOT NULL ,
    departure     VARCHAR2 (45) NOT NULL ,
    arrival       VARCHAR2 (45) NOT NULL ,
    departuretime DATE NOT NULL ,
    arrivaltime   DATE NOT NULL ,
    distance      INTEGER NOT NULL ,
    period        VARCHAR2 (45)
  ) ;
  ALTER TABLE Journey ADD CONSTRAINT Journey_PK PRIMARY KEY ( journeyID) ;


ALTER TABLE TrainInfo ADD CONSTRAINT TrainInfo_FK FOREIGN KEY ( Journey_journeyID)
REFERENCES Journey ( journeyID) ON DELETE CASCADE ;

我想在此找到“列车号、出发、到达、出发时间、到达时间”。我试过了:

CREATE VIEW TrainsPossibles AS 
      SELECT trainnumber, departure, arrival, departuretime, arrivaltime 
        FROM TrainInfo 
      NATURAL JOIN Journey 
       ORDER BY departure;

我的问题是,它选择了 112 (14*8) 行,而我的数据库中目前只有 14 个 trainsInfo 和 8 个旅程。

首先,为什么它会创建这么多行?我认为它会在外键匹配主键时加入,所以最多 14 次。

第二:什么是正确的查询或加入这里? (完全加入 FK = PK ?)

尝试一个条件:

 SELECT trainnumber, departure, arrival, departuretime, arrivaltime
 FROM TrainInfo JOIN
      Journey
      ON TrainInfo.journey_journeyid = Journey.journeyid AND nbAvail1st != 0 AND nbAvail2e != 0;
 ORDER BY departure;

【问题讨论】:

  • blog.codinghorror.com/a-visual-explanation-of-sql-joins 哦,在这种情况下,你最好说“选择正确的加入”。 right join 太混乱了 - 只有一个 right join
  • 你们提出的两种解决方案(加入和左加入)都非常有效。但是他们两者之间的具体区别是什么?
  • 阅读我链接到的页面。它显示(视觉上)各种连接之间的差异
  • @Marc B. 太好了,谢谢。最后一个问题:我用查询编辑了原始帖子。这是正确的(相同但还有两个条件)?
  • 从技术上讲,join 应该只包含与决定是否加入相关的条件。 nb... != 的东西应该进入 where 子句。但这更像是一个风格上的决定,有时你必须做join这样的条件,而这在where中是行不通的。

标签: sql oracle join


【解决方案1】:

首先,不要使用NATURAL JOIN。它取决于表中为连接键定义的列。不幸的是,它严格按照名称进行,而不是声明的外键引用。如果没有匹配的键,则得到笛卡尔积。

您的查询是:

 SELECT trainnumber, departure, arrival, departuretime, arrivaltime
 FROM TrainInfo NATURAL JOIN
      Journey
 ORDER BY departure;

所有列都没有相同的名称,因此JOIN 最终成为笛卡尔积。我想你想要:

 SELECT trainnumber, departure, arrival, departuretime, arrivaltime
 FROM TrainInfo JOIN
      Journey
      ON TrainInfo.journey_journeyid = Journey.journeyid
 ORDER BY departure;

【讨论】:

    【解决方案2】:

    自然连接返回一个表的对应字段与另一个表的记录组合。这就是你获得如此多记录的原因。

    要获得您需要的内容,您应该执行“左连接”而不是“自然连接”,“on”条件为“on TrainInfo.Journey_journeyID = Journey.JourneyID”。左连接返回查询“左侧”的所有记录以及“右侧”与您的“连接条件”匹配的所有记录如果没有来自“右表”(旅程)存在,您将在这些列中获得“空值”。要仅获取两个表中都存在记录的结果,请使用 LEFT INNER JOIN。

    SELECT trainnumber, departure, arrival, departuretime, arrivaltime 
      FROM TrainInfo 
      LEFT JOIN Journey 
      on TrainInfo.Journey_journeyID = JourneyID
    ORDER BY departure
    

    【讨论】:

    • 你们提出的两种解决方案(加入和左加入)都非常有效。但是他们两者之间的具体区别是什么?
    • 左连接返回“左侧”表中的所有记录,右侧表中不匹配的记录返回空值。单独连接仅返回在连接条件中匹配的那些记录。普通的“join”也通常与“inner join”同义。
    猜你喜欢
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 2018-12-12
    • 2020-05-29
    • 2012-06-23
    • 2017-11-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多