加入两个表,客户和订单以获取所有客户的清单以及订单编号

时间:2016-06-02 13:48:10

标签: sql oracle

    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)和一张名为订单(B)的表,其中包含客户可能已下达的订单。 我上面的查询应该给我所有客户的名字和订单号,如果有订单链接到该客户。

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

4 个答案:

答案 0 :(得分:4)

这是旧式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

答案 1 :(得分:3)

(+)是旧式语法中的“外连接”。这意味着如果没有匹配,则返回连接左侧的每一行,并在右侧表的列中返回“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”这个词,则确实是隐含的。对于外连接,您的其他选项是正确的和完全的。

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

答案 2 :(得分:2)

为了避免这样的问题, 切换到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

答案 3 :(得分:2)

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

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

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

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