ORACLE左连接的正确使用

6yoyoihd  于 2022-12-18  发布在  Oracle
关注(0)|答案(2)|浏览(139)

我有以下疑问:

SELECT eps.PROPOSAL_NUMBER,
       pers.PROP_PERSON_ROLE_ID,
       pers.FULL_NAME,       
       pers.HOME_UNIT
       FROM EPS_PROPOSAL eps
       FULL OUTER JOIN EPS_PROP_PERSON pers USING (PROPOSAL_NUMBER)
       WHERE (pers.PROP_PERSON_ROLE_ID = 'PI' OR 
              pers.PROP_PERSON_ROLE_ID = 'PD' OR 
              pers.PROP_PERSON_ROLE_ID IS NULL); -- 4483

但是,如果我运行以下命令:

SELECT COUNT (*) PROPOSAL_NUMBER FROM EPS_PROPOSAL; -- 4504

差了21分。
我去查看了差异的原因,果然,EPS_PROPOSAL表中的21个建议中没有任何人在EPS_PROP_PERSON表中担任PIPD角色。
每个提案只能指定一个人作为PIPD(例如,每个PROPOSAL_NUMBER绝不会有一个以上的PI/PD);然而,您可以在那里有多个其他角色(我可以在这里列出它们,但与手头的问题无关)。
如何修改查询,使其从EPS_PROPOSAL返回PROPOSAL_NUMBER,并在提案具有PIPD的提案的pers列中插入NULL值?
我原以为这会与JOIN有关,但使用LEFT JOIN在这里没有帮助。
我的LEFT JOIN尝试:

SELECT eps.PROPOSAL_NUMBER,
       pers.PROP_PERSON_ROLE_ID,
       pers.FULL_NAME,       
       pers.HOME_UNIT
       FROM EPS_PROPOSAL eps
       LEFT JOIN EPS_PROP_PERSON pers USING (PROPOSAL_NUMBER)
       WHERE (pers.PROP_PERSON_ROLE_ID = 'PI' OR 
              pers.PROP_PERSON_ROLE_ID = 'PD' OR 
              pers.PROP_PERSON_ROLE_ID IS NULL); -- 4483

x6h2sr28

x6h2sr281#

从你在评论中的解释来看,我相信这就是你要找的。我将使用union操作符把两个相似的数据集组合在一起。一个是你对PI和PD的原始查询,另一个是你的 predicate 的逆。在下面的查询中,我将把NULL赋为pers的值,作为默认值。

SELECT DISTINCT
  PROPOSAL_NUMBER, 
  FIRST_VALUE(PROP_PERSON_ROLE_ID) OVER (PARTITION BY PROPOSAL_NUMBER ORDER BY PROPOSAL_NUMBER), 
  FIRST_VALUE(FULL_NAME) OVER (PARTITION BY PROPOSAL_NUMBER ORDER BY PROPOSAL_NUMBER), 
  FIRST_VALUE(HOME_UNIT) OVER (PARTITION BY PROPOSAL_NUMBER ORDER BY PROPOSAL_NUMBER)
FROM
((
SELECT eps.PROPOSAL_NUMBER,
       pers.PROP_PERSON_ROLE_ID,
       pers.FULL_NAME,       
       pers.HOME_UNIT
       FROM EPS_PROPOSAL eps
       LEFT JOIN EPS_PROP_PERSON pers ON eps.PROPOSAL_NUMBER = pers.PROPOSAL_NUMBER
       WHERE (pers.PROP_PERSON_ROLE_ID = 'PI' OR 
              pers.PROP_PERSON_ROLE_ID = 'PD' OR 
              pers.PROP_PERSON_ROLE_ID IS NULL)
)
UNION
(
SELECT eps.PROPOSAL_NUMBER,
       NULL as PROP_PERSON_ROLE_ID,
       NULL as FULL_NAME,       
       NULL as HOME_UNIT
       FROM EPS_PROPOSAL eps
       LEFT JOIN EPS_PROP_PERSON pers ON eps.PROPOSAL_NUMBER = pers.PROPOSAL_NUMBER
       WHERE (pers.PROP_PERSON_ROLE_ID != 'PI' AND
              pers.PROP_PERSON_ROLE_ID != 'PD' AND
              pers.PROP_PERSON_ROLE_ID IS NOT NULL)
))
nsc4cvqm

nsc4cvqm2#

WHERE过滤器移至JOIN条件:

SELECT eps.PROPOSAL_NUMBER,
       pers.PROP_PERSON_ROLE_ID,
       pers.FULL_NAME,       
       pers.HOME_UNIT
FROM   EPS_PROPOSAL eps
       FULL OUTER JOIN EPS_PROP_PERSON pers
       ON (   eps.PROPOSAL_NUMBER = pers.PROPOSAL_NUMBER
          AND (  pers.PROP_PERSON_ROLE_ID IN ( 'PI', 'PD' )
              OR pers.PROP_PERSON_ROLE_ID IS NULL)
          );

或者,对于LEFT JOIN

SELECT eps.PROPOSAL_NUMBER,
       pers.PROP_PERSON_ROLE_ID,
       pers.FULL_NAME,       
       pers.HOME_UNIT
FROM   EPS_PROPOSAL eps
       LEFT JOIN EPS_PROP_PERSON pers
       ON (   eps.PROPOSAL_NUMBER = pers.PROPOSAL_NUMBER
          AND (  pers.PROP_PERSON_ROLE_ID IN ( 'PI', 'PD' )
              OR pers.PROP_PERSON_ROLE_ID IS NULL)
          );

如果使用WHERE过滤器,则将执行JOIN,然后将过滤掉不匹配的行,这将同时排除perseps中的行(因为您已经连接了表)。如果在连接中应用过滤器,则pers表将在连接之前被过滤,并且eps中的所有行都将被返回。

相关问题