对于Teradata SQL中的同一个表,LEFT JOIN WHERE RIGHT为NULL

时间:2016-01-21 14:50:21

标签: sql left-join teradata

我有一张包含51条记录的表格。表结构如下所示:

ack_extract_id query_id cnst_giftran_key field1 value1

现在ack_extract_ids可以是8,9。 我想检查一下extract_id 9中的giftran键,而不是8中的那个。

我试过的是

            SELECT *
            FROM ddcoe_tbls.ack_flextable ack_flextable1
            INNER JOIN ddcoe_tbls.ack_main_config config
                ON ack_flextable1.ack_extract_id = config.ack_extract_id
            LEFT JOIN ddcoe_tbls.ack_flextable ack_flextable2
                ON ack_flextable1.cnst_giftran_key = ack_flextable2.cnst_giftran_key
            WHERE  ack_flextable2.cnst_giftran_key IS NULL
            AND  config.ack_extract_file_nm LIKE '%Dtl%'
                AND ack_flextable2.ack_extract_id = 8
                AND ack_flextable1.ack_extract_id = 9

但它正在给我0条记录。理想情况下,right为null的左连接应该返回右侧表中不存在cnst_giftran_key的记录,对吗?

我在这里缺少什么?

3 个答案:

答案 0 :(得分:3)

在where子句(在您的情况下为ack_flextable2.ack_extract_id)中测试左连接表中的列时,强制该连接的行为就像它是内连接一样。相反,将该测试移动到连接条件的一部分。

然后要查找缺少该值的记录,请在where子句中测试NULL键。

        SELECT *
        FROM ddcoe_tbls.ack_flextable ack_flextable1
        INNER JOIN ddcoe_tbls.ack_main_config config
            ON ack_flextable1.ack_extract_id = config.ack_extract_id
        LEFT JOIN ddcoe_tbls.ack_flextable ack_flextable2
            ON ack_flextable1.cnst_giftran_key = ack_flextable2.cnst_giftran_key
                AND ack_flextable2.ack_extract_id = 8
        WHERE  ack_flextable2.cnst_giftran_key IS NULL
        AND  config.ack_extract_file_nm LIKE '%Dtl%'
            AND ack_flextable1.ack_extract_id = 9
            AND ack_flextable2.cnst_giftran_key IS NULL

答案 1 :(得分:1)

这不是答案,只是一个解释

从你的评论到Joe Stefanelli的回答我收集到你并不完全理解外连接中WHERE和ON的问题。那么让我们来看一个例子。

我们正在寻找所有供应商的最后订单,即订单记录,其中没有供应商的新订单。

select *
from order
where not exists
(
  select *
  from order newer 
  where newer.supplier = order.supplier 
    and newer.orderdate > order.orderdate
);

这是直截了当的;查询与我们刚刚放入单词的内容相匹配:查找不为同一供应商提供新订单的订单。

使用反连接模式的相同查询:

select order.*
from order
left join order newer on  newer.supplier = order.supplier 
                      and newer.orderdate > order.orderdate
where newer.id is null;

在这里,我们将所有新订单加入每个订单,因此可能会产生巨大的中间结果。通过左外连接,我们确保在没有供应商的新订单时附加虚拟记录。然后,我们最后使用WHERE子句扫描中间结果,仅保留附加记录的ID为null的记录。好吧,ID显然是表的主键,永远不能为空,所以我们保留的只是外连接结果,其中较新的数据只是一个包含空值的虚拟记录。因此,我们得到了没有新订单的订单。

谈论一个巨大的中间结果:这怎么能比第一个查询更快?好吧,它不应该。实际上,第一个查询应该同样快速或更快地运行。一个好的DBMS将看到这一点并为两个查询制定相同的执行计划。然而,一个相当年轻的DBMS可能真的更快地执行反连接。这是因为开发人员在连接技术方面投入了大量精力,因为在每个查询中都需要这些技术,而且还没有那么关心IN和EXISTS。在这种情况下,可能会遇到NOT IN或NOT EXISTS的性能问题,而是使用反连接模式。

现在关于WHERE / ON问题:

select order.*
from order
left join order newer on newer.orderdate > order.orderdate
where newer.supplier = order.supplier
and newer.id is null;

这与以前几乎相同,但有些标准已从ON移至WHERE。这意味着外连接获得不同的标准。以下是发生的事情:每个订单都能找到所有新订单 - 无论哪个供应商!因此,最后一个订单日期的所有订单都获得了外连接虚拟记录。但是在WHERE子句中,我们删除了供应商不匹配的所有对。请注意,外连接记录对于newer.supplier包含NULL,因此newer.supplier = order.supplier对它们来说永远不会成立;他们被删除了。但是,如果我们删除所有外连接记录,我们得到的结果与香草内连接完全相同。当我们在WHERE子句中放入外连接标准时,我们将外连接转换为内连接。因此查询可以重写为

select order.*
from order
inner join order newer on newer.orderdate > order.orderdate
where newer.supplier = order.supplier
and newer.id is null;

对于FROM和INNER JOIN中的表,标准是ON还是WHERE并不重要;它取决于可读性,因为这两个标准同样适用。

现在我们看到newer.id is null永远不会成真。最终结果将为空 - 这正是您的查询所发生的事情。

答案 2 :(得分:0)

您可以尝试使用此查询:

select * from ddcoe_tbls.ack_main_config
where cnst_giftran_key not in 
  (
   select cnst_giftran_key from ddcoe_tbls.ack_main_config 
   where ack_extract_id = 8
  )  
and ack_extract_id = 9;