【问题标题】:Joining Multiple Tables - Oracle连接多个表 - Oracle
【发布时间】:2014-06-07 18:37:01
【问题描述】:

本周我正在研究多个表连接,并返回了一些奇怪的结果。这是场景...

使用正确的表,使用传统的连接操作创建一个查询,该操作将列出客户的名字和姓氏、书名和订单日期(格式为 MM/DD/YYYY,别名为“Order Date” ”) 为所有购买了 'PRINTING IS US' 出版书籍的客户。

对于我查询的数据库,此查询的正确表是 BOOK_CUSTOMER、BOOKS、BOOK_ORDER 和 PUBLISHER。我写的语句返回了我需要的信息,但它返回了将近 5900 条记录。我不明白这怎么可能是正确的。出版商 Printing is Us 仅在数据库中列出了 14 本书,并且只有 20 条客户记录,因此即使每个客户购买了每本 Printing is Us 书,也只会返回 280 条记录。但是我无法弄清楚我有什么问题。我的陈述如下。

SELECT bc.firstname, bc.lastname, b.title, TO_CHAR(bo.orderdate, 'MM/DD/YYYY') "Order Date", p.publishername
FROM book_customer bc, books b, book_order bo, publisher p
WHERE(publishername = 'PRINTING IS US');

有人对我在这里缺少什么有任何想法吗??

谢谢。

【问题讨论】:

  • 您缺少JOINclause。或者说是三个。
  • 关闭 - 他错过了比较。实际上,他 JOIN 子句,但没有ON 子句。当然,最好避免使用隐式连接语法(逗号分隔的 FROM 子句),但至少该类似乎将其称为“传统”连接。

标签: sql oracle


【解决方案1】:

我建议您现在就养成使用 ANSI 样式连接的习惯,这意味着您应该在您的SQL 语句而不是使用“旧式”连接,其中所有表在FROM 子句中一起命名,所有连接条件都放在WHERE 子句中。与“旧式”连接相比,ANSI 样式的连接更容易理解,并且不太可能被误写和/或误解。

我会将您的查询改写为:

SELECT bc.firstname,
       bc.lastname,
       b.title,
       TO_CHAR(bo.orderdate, 'MM/DD/YYYY') "Order Date",
       p.publishername
FROM BOOK_CUSTOMER bc
INNER JOIN books b
  ON b.BOOK_ID = bc.BOOK_ID
INNER JOIN  book_order bo
  ON bo.BOOK_ID = b.BOOK_ID
INNER JOIN publisher p
  ON p.PUBLISHER_ID = b.PUBLISHER_ID
WHERE p.publishername = 'PRINTING IS US';

分享和享受。

【讨论】:

  • 鉴于他的课程材料将其称为“传统”样式连接,我觉得他需要使用隐式语法。诚然,我同意应该避免它(OP 现在有一个很好的例子说明原因),但新学生必须以某种方式了解语法的含义。
  • 你们解释说,比教科书和讲座做得更好。谢谢你。是的,Clockwork-Muse,你是对的,我们被指示使用查询问题中要求的确切方法,但我确实理解需要养成使用 ANSI 语法的习惯。再次感谢大家。
【解决方案2】:

虽然前一个答案是绝对正确的,但我更喜欢使用JOIN ON 语法,所以我确定如何加入以及在哪些字段上加入。它看起来像这样:

SELECT bc.firstname, bc.lastname, b.title, TO_CHAR(bo.orderdate, 'MM/DD/YYYY') "Order         Date", p.publishername
FROM books b
JOIN book_customer bc ON bc.costumer_id = b.book_id
LEFT JOIN book_order bo ON bo.book_id = b.book_id
(etc.)
WHERE b.publishername = 'PRINTING IS US';

此语法将WHERE 子句与JOIN 子句完全分开,使语句更具可读性和更易于调试。

【讨论】:

  • 嗯,你为什么使用 both 隐式语法和显式列出连接?我假设这是一个错字,因为您重用了表别名(因此会出现错误)。我认为所述查询不需要LEFT JOIN,只需常规(INNER) JOINs。
  • @Clockwork-Muse 我不需要LEFT JOIN,我只是想展示一下。至于表别名 - 我正在纠正它。无需重复两次。
  • @Clockwork-Muse 的想法是FROM 子句只包含一个表,其余的都在JOIN 子句中。
  • 这个很有用!
【解决方案3】:

您正在进行笛卡尔连接。这意味着,如果您甚至没有单个 where 子句,那么您获得的结果数量将是 book_customer size 乘以 books size 乘以 book_order size 乘以 publisher size。

换句话说,结果集被炸毁了,因为您没有添加有意义的连接子句。您的正确查询应如下所示:

SELECT bc.firstname, bc.lastname, b.title, TO_CHAR(bo.orderdate, 'MM/DD/YYYY') "Order Date", p.publishername
FROM book_customer bc, books b, book_order bo, publisher p
WHERE bc.book_id = b.book_id
AND bo.book_id = b.book_id
(etc.)
AND publishername = 'PRINTING IS US';

注意:通常建议不要像在这个查询中那样使用隐式连接,而是使用INNER JOIN 语法。但是,我假设您的学习材料中使用了此语法,因此我将其保留了。

【讨论】:

    猜你喜欢
    • 2011-11-03
    • 1970-01-01
    • 2017-05-02
    • 2021-05-29
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 2015-06-02
    • 1970-01-01
    相关资源
    最近更新 更多