【问题标题】:SQL Sub Query with outer LEFT JOIN带有外部 LEFT JOIN 的 SQL 子查询
【发布时间】:2015-11-23 17:15:55
【问题描述】:

如果table B 行与table B select where 子句匹配,我需要从table A 中选择所有行并从table B 中选择匹配行。这是我带有子查询的外部LEFT JOIN,但它失败了。有人可以帮忙吗?

SELECT A.WRDWHSE,
       A.WRDRTID,
       A.WRDRPTLIN
FROM CWDDEV.WRTEMSTDP AS A 
LEFT JOIN (SELECT B.RHRTID,
                  B.RHRTE, 
                  B.RHSTAT, 
                  B.RHPRTT 
           FROM PIRF3.RTEHED
           WHERE B.RHWHSE=003 and 
                 ((B.RHSTSD =20151111 and B.RHSTST >=060000 ) or (B.RHSTSD=20151112 and B.RHSTST <=055959 )) and
                 B.RHTYPE NOT IN ('W') and 
                 (B.RHRTE NOT LIKE 'EMP%') and
                 B.RHSTAT IN (1, 3, 4, 5, 6)) AS B                                                     
ON A.WRDWHSE=B.RHWHSE and A.WRDRTID=B.RHRTE
WHERE A.WRDWHSE=003     
ORDER BY A.WRDRPTLIN               

【问题讨论】:

  • 请编辑您的问题并努力格式化您的查询。提示:行首的四个空格用于格式化代码。
  • 看起来不错,尽管您甚至没有在输出中从 B 中选择列。它是如何失败的?
  • B 是外部选择已知的别名。 B 对于内部选择是未知的,因为它不在范围内;因此 B.RHRTID 无效 RHRTID 将是有效的。或者您需要将PIRF3.RTEHED 更改为PIRF3.RTEHED as B 但是,我们不知道出了什么问题(以什么方式失败?有错误,没有数据什么?)所以我怀疑这真的是问题所在。
  • 另外B.RHWHSE 不在子查询的选定值中;所以它不能加入它。这很可能是问题所在。将RHWHSE 添加到内部选择中。另外我不知道为什么你需要 b.RHWHSE=003 因为外部选择会在加入时消除它们。 003 也是数字数据。如果是字符串,则需要将其用单引号 ' 括起来,否则为什么要使用前导 00?
  • 实际上我最初有“PIRF3.RTEHED as B”,但我更改了代码,因为我在 QA 板上看到了一些东西。 SQL 现在回到“PIRF3.RTEHED as B”。我得到的错误是 A 不是有效的令牌,并且消息指向语句的 ON 部分中的 A.WRDWHSE。

标签: sql


【解决方案1】:

以下是我对您的查询的初步想法:

SELECT *
FROM
    CWDDEV.WRTEMSTDP A LEFT OUTER JOIN
    (
    SELECT
        B.RHWHSE, B.RHRTE,
        B.RHRTID, B.RHSTAT, B.RHPRTT /* are these going to be used? */
    FROM PIRF3.RTEHED B
    WHERE
            B.RHWHSE = 003 /* why all the leading zeros? are these numeric or a char? */
        AND (
               /* if these are really dates then these won't work */
               (B.RHSTSD = 20151111 AND B.RHSTST >= 060000)
            OR (B.RHSTSD = 20151112 AND B.RHSTST <= 055959)
        )
        AND B.RHTYPE NOT IN ('W')
        AND B.RHRTE NOT LIKE 'EMP%'
        AND B.RHSTAT IN (1, 3, 4, 5, 6)
    ) B_outer /* inside and outside have different names */
        ON A.WRDWHSE = B_outer.RHWHSE AND A.WRDRTID = B_outer.RHRTE
WHERE A.WRDWHSE = 003
ORDER BY A.WRDRPTLIN      

编辑:根据下面的对话,我愿意考虑一个 DB2/AS400 错误。您使用左连接的场景非常常见。但这里有一些可能有效或有助于解决问题的查询变体。

消除冗余条件:

SELECT *
FROM
    CWDDEV.WRTEMSTDP A LEFT OUTER JOIN
    (
    SELECT B.RHWHSE, B.RHRTE, B.RHRTID, B.RHSTAT, B.RHPRTT
    FROM PIRF3.RTEHED B
    WHERE
        (
               B.RHSTSD = 20151111 AND B.RHSTST >= 060000
            OR B.RHSTSD = 20151112 AND B.RHSTST <= 055959
        )
        AND B.RHTYPE <> 'W'
        AND B.RHRTE NOT LIKE 'EMP%'
        AND B.RHSTAT IN (1, 3, 4, 5, 6)
    ) B_outer
        ON A.WRDWHSE = B_outer.RHWHSE AND A.WRDRTID = B_outer.RHRTE
WHERE A.WRDWHSE = 3 AND A.WRDRTID = 73
ORDER BY A.WRDRPTLIN

公用表表达式(CTE):

WITH ROUTES AS ( /* this might not be valid if your platform is old */
    SELECT
        B.RHWHSE, B.RHRTE, B.RHRTID, B.RHSTAT, B.RHPRTT
    FROM PIRF3.RTEHED B
    WHERE
        (
               B.RHSTSD = 20151111 AND B.RHSTST >= 060000
            OR B.RHSTSD = 20151112 AND B.RHSTST <= 055959
        )
        AND B.RHTYPE <> 'W'
        AND B.RHRTE NOT LIKE 'EMP%'
        AND B.RHSTAT IN (1, 3, 4, 5, 6)
)
SELECT *
FROM CWDDEV.WRTEMSTDP A LEFT OUTER JOIN ROUTES B
    ON A.WRDWHSE = B.RHWHSE AND A.WRDRTID = B.RHRTE
WHERE A.WRDWHSE = 3 AND A.WRDRTID = 73
ORDER BY A.WRDRPTLIN

联合:

SELECT
    A.WRDWHSE, A.WRDRTID, A.WRDRPTLIN,
    B.RHRTE, B.RHSTAT, B.RHPRTT
FROM
    CWDDEV.WRTEMSTDP A INNER JOIN PIRF3.RTEHED B
        ON A.WRDWHSE = B_outer.RHWHSE AND A.WRDRTID = B_outer.RHRTE
WHERE
        A.WRDWHSE = 3 AND A.WRDRTID = 73
    (
           B.RHSTSD = 20151111 AND B.RHSTST >= 060000
        OR B.RHSTSD = 20151112 AND B.RHSTST <= 055959
    )
    AND B.RHTYPE <> 'W'
    AND B.RHRTE NOT LIKE 'EMP%'
    AND B.RHSTAT IN (1, 3, 4, 5, 6)
UNION ALL
SELECT
    A.WRDWHSE, A.WRDRTID, A.WRDRPTLIN,
    NULL AS RHRTE, NULL AS RHSTAT, NULL AS RHPRTT
FROM CWDDEV.WRTEMSTDP A
WHERE A.WRDWHSE = 3 AND A.WRDRTID = 73 AND NOT EXISTS (
    SELECT 1
    FROM PIRF3.RTEHED B
    WHERE
            A.WRDWHSE = B.RHWHSE AND A.WRDRTID = B.RHRTE
        AND (
               B.RHSTSD = 20151111 AND B.RHSTST >= 060000
            OR B.RHSTSD = 20151112 AND B.RHSTST <= 055959
        )
        AND B.RHTYPE <> 'W'
        AND B.RHRTE NOT LIKE 'EMP%'
        AND B.RHSTAT IN (1, 3, 4, 5, 6)
    )
ORDER BY A.WRDRPTLIN

如果您确实需要使用视图或临时表,也可以尝试使用它。听起来您提到的嵌套循环可能是您的最佳解决方法。

【讨论】:

  • 谢谢 shawnt00。我不知道 OUTER 规范,我将不得不阅读更多内容。您的建议产生的结果与我在没有子查询的情况下直接执行 LEFT JOIN 的结果相同。问题是我从 A.WRTEMSTDP 表中获取所有行,除了一行。缺少的行是 A.WRDRTID = 73 的行。B.RTEHED 表中有 A.WRDRTID=B.RHRTE 的行,问题是它们是日期范围之外的行。 JOIN 满足并找到匹配项,但未包含该行,因为 WHERE 子句将其丢弃在日期范围内的不匹配项上。
  • B.RTEHED 表中有 A.WRDRTID=73 和 B.RHRTE=73 的行,问题是它们是日期范围之外的行。我想要的结果是包括将 A.WRDRTID=73 行作为 LEFT OUTER JOIN,就好像它在 B.RTEHED 中没有找到匹配项一样。我很想用两个循环创建分隔查询,即 while table A { while table B {.............}}
  • OUTER 通常是可选的,它的含义完全相同。 WRDRTID 73 所在行的 WRDWHSE 是什么?您对外部查询也有一个过滤器。
  • 再次感谢 shawnt00。匹配,003。我知道查询有些复杂,当我尝试解释时,它似乎有点麻烦,我希望您能够理解我的目标和期望的结果。我认为你这样做,但请让我知道是否有任何不合理的地方。谢谢
  • 其实你的查询一点都不复杂。排除 A 中的行的唯一方法是 WRDWHSE 不等于 3。
猜你喜欢
  • 2013-05-13
  • 1970-01-01
  • 2013-05-22
  • 2014-07-14
  • 1970-01-01
  • 2019-01-24
  • 1970-01-01
  • 2015-01-10
  • 1970-01-01
相关资源
最近更新 更多