【问题标题】:Joining two tables, customers and orders to get list of all customers and the order number IF they have an order加入两个表,客户和订单以获取所有客户的列表和订单号(如果他们有订单)
【发布时间】:2016-06-02 22:16:23
【问题描述】:
    SELECT a.org, 
           a.id, 
           a.Name, 
           b.ordNum 
      FROM customers A, 
           orders B 
     WHERE a.org  = 'JJJ' 
       AND a.org  = b.org (+)
       AND b.addr_type (+) = 'ST' -- <<<<<<<<<<<<<<<<< why do i need to add (+) here
       AND a.cust_id = b.cust_id (+)
  ORDER BY 2

我有一个包含客户列表 (A) 的表格和一个名为 orders (B) 的表格,其中包含客户可能下的订单。 我上面的查询应该给我所有客户的姓名和订单号,如果有一个订单链接到该客户。

我的问题是.. 为什么我需要在 b.addr_type 之后添加 (+) 以获取所有客户,即使他们还没有下订单。

【问题讨论】:

标签: sql oracle


【解决方案1】:

这是旧式JOIN 语法,其中(+) 表示OUTER JOIN。这意味着左表中的每一行都将被返回,无论右表是否匹配。要仅获取有订单的客户,请使用INNER JOIN。此外,您应该使用明确的 JOIN 而不是旧式语法:

SELECT
    c.ORG, c.ID, c.NAME, o.ordNum 
FROM customers c -- Use meaningful aliases to improve readability
LEFT JOIN orders o
    ON c.org = o.org
    AND c.cust_id = o.cust_id
    AND o.addr_type = 'ST'
WHERE
    c.org = 'JJJ'
ORDER BY c.ID

【讨论】:

  • 当他说“旧式”时,它是非常旧的。 “新式”语法来自 1992 年,比我的一些同事还要老。没有人应该再使用隐式连接了。它们更难阅读、维护等,而且在某些情况下它们实际上无法正常工作并且已被弃用。
【解决方案2】:

(+) 是旧式语法中的“外连接”。这意味着如果没有匹配,则连接左侧的每一行都将在右侧表的列中返回一个“null”。

如果右侧没有匹配项,则 INNER 联接(旧式 SQL 中的正则等于)不会返回记录。

现代语法是

SELECT A.ORG, A.ID, A.NAME, b.ordNum FROM 
customers A
LEFT OUTER JOIN customers b on a.id = b.id 
              AND a.cust_id = b.cust_id 
              AND b.addr_type = 'ST'
WHERE a.org = 'JJJ'
ORDER BY 2

“OUTER”部分是可选的,如果您使用“LEFT”一词,则确实是隐含的。对于外部连接,您的其他选项是 RIGHT 和 FULL。

为什么要使用这种新语法?因为它符合 ANSI SQL,所以 (+) 已被弃用,并且不会移植到某些现代 RDBMS 实现。另外,根据这篇文章的评论,它像罪恶一样丑陋且难以维护。

【讨论】:

  • 这不是 Oracle 特定的,其他 RDBMS 确实支持它。也就是说,在某些情况下它不能正常工作,因此它已被弃用,编写、读取、维护、调试等都是一场噩梦。
【解决方案3】:

(+) 语法告诉 Oracle 执行左连接而不是内连接。

结果是一个记录列表,其中包含来自 customers 的所有 valorized 列和来自 orders 表的一些空列。

如果orders 表中的列是NULL,则这些记录的where 条件b.addr_type = 'ST' 将始终为FALSE,因此您将无法获得所需的结果。

相反,如果您编写 b.addr_type(+) = 'ST',您将获得与条件匹配的所有列以及由于左连接而具有 NULL 值的列,这就是您想要获得的。

【讨论】:

  • 那么用 and (b.addr_type = 'ST' or b.addr_type is null) 替换那一行,也能解决问题吗?
  • 谢谢。这正是我正在寻找的解释。 !
  • 是的,替换为 and (b.addr_type = 'ST' or b.addr_type is null) 也可以解决问题
【解决方案4】:

为了避免此类问题, 切换到更易读的LEFT JOIN语法

    SELECT a.org, 
           a.id, 
           a.Name, 
           b.ordNum 
      FROM customers a LEFT JOIN 
           orders b ON (a.org = b.org) 
                   AND (b.addr_type = 'ST') 
                   AND (a.cust_id = b.cust_id)
     WHERE a.org = 'JJJ' 
  ORDER BY a.id -- better put it direct, not field's index

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-29
    • 2018-07-16
    • 2021-12-21
    • 2022-01-14
    相关资源
    最近更新 更多