LEFT JOIN WHERE IS NULL for same table in Teradata SQL

LEFT JOIN WHERE RIGHT IS NULL for same table in Teradata SQL

我有一个 table 有 51 条记录。 table 结构如下所示:

ack_extract_id query_id cnst_giftran_key 字段 1 值 1

现在 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 条记录。理想情况下,右侧为空的左连接应该返回右侧 table 中不存在 cnst_giftran_key 的记录,对吗?

我在这里错过了什么?

当您在 where 子句中测试来自 left-joined table 的列时(在您的情况下为 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

这不是答案,只是解释

根据您对 Joe Stefanelli 的回答的评论,我了解到您没有完全理解外部联接中 WHERE 和 ON 的问题。那么让我们看一个例子。

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

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

这是straight-forward;该查询与我们刚刚输入的内容相匹配:查找不存在同一供应商的新订单的订单。

具有 anti-join 模式的相同查询:

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 为空的记录。好吧,ID 显然是 table 的主键,永远不能为空,所以我们在这里保留的只是 outer-joined 结果,其中较新的数据只是包含空值的虚拟记录。因此,我们准确地得到了不存在新订单的订单。

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

现在关于 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。这意味着外部连接获得不同的条件。这是发生了什么:对于每个订单,找到所有更新的订单 ‐无论哪个供应商!因此,最后订单日期的所有订单都会获得 outer-join 虚拟记录。但随后在 WHERE 子句中,我们删除了供应商不匹配的所有对。请注意,outer-joined 记录包含 newer.supplier 的 NULL,因此 newer.supplier = order.supplier 对它们永远不会为真;他们被删除。但是,如果我们删除所有 outer-joined 记录,我们会得到与普通内连接完全相同的结果。当我们在 WHERE 子句中放置外连接条件时,我们将外连接变成了内连接。所以查询可以是re-written as

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 中使用 tables,条件是在 ON 还是 WHERE 中并不重要;这更像是一个可读性问题,因为这两个标准将同样得到应用。

现在我们看到 newer.id is null 永远不可能是真的。最终结果将是空的 ‐这正是您的查询所发生的情况。

您可以尝试使用此查询:

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;