Oracle SQL—消除联接上不相等的值

Oracle SQL—消除联接上不相等的值,sql,oracle,Sql,Oracle,下面是我的表的外观:两个表在所有3列上都有一个复合主键。第二个ID不会在这两个表中重复。这显然不是由DB约束强制执行的,而是由前端的业务规则强制执行的 Table1: PrimaryID|SecondaryID|Email 1 9999 ABC@GMAIL.COM 1 9999 DEF@GMAIL.COM 2 8888 CCC@GMAIL.COM 3 7777 CBA@GMAIL.COM Table2: PrimaryID|SecondaryID|Ema

下面是我的表的外观:两个表在所有3列上都有一个复合主键。第二个ID不会在这两个表中重复。这显然不是由DB约束强制执行的,而是由前端的业务规则强制执行的

Table1:
PrimaryID|SecondaryID|Email
1   9999    ABC@GMAIL.COM
1   9999    DEF@GMAIL.COM
2   8888    CCC@GMAIL.COM
3   7777    CBA@GMAIL.COM

Table2:
PrimaryID|SecondaryID|Email
1   1111    ABC@GMAIL.COM
2   2222    XYZ@GMAIL.COM
3   3333    CBA@GMAIL.COM
我希望返回两个表中的secondaryid,在相同的primaryid上连接,其中电子邮件在所有出现的primaryid上都不同

对于PrimaryID=1: 表1有两行,表2有一行。但表2中的一封邮件和表1中的一封邮件是一致的,所以我不想把它退回。这是我的问题,但这并不能消除上面的重复,这是我需要的

 SELECT DISTINCT T1.SECONDARYID, T2.SECONDARYID 
    FROM TABLE1 T1 INNER JOIN TABLE2 T2 ON T1.PRIMARYID = T2.PRIMARYID
    AND T1.EMAIL <> T2.EMAIL;

因此,您希望从一个表中获取所有记录,并从ID字段相等的另一个表中查找所有此类记录,但第二个表中不存在具有相同电子邮件的记录

我会尝试以下几点:

select one.*, another.*
from one, another
where
  one.id = another.id and
  not exists (
    select 1 
    from another as another_again
    where 
      another_again.id = one.id and
      another_again.email = one.email
  )

严格来说,这可能不是最快的查询(希望Oracle能拿出一个好的查询计划)。不过,这应该很容易理解。

因此,您希望从一个表中获取所有记录,并从另一个表中查找ID字段相等的所有此类记录,但第二个表中没有具有相同电子邮件的记录

我会尝试以下几点:

select one.*, another.*
from one, another
where
  one.id = another.id and
  not exists (
    select 1 
    from another as another_again
    where 
      another_again.id = one.id and
      another_again.email = one.email
  )

严格来说,这可能不是最快的查询(希望Oracle能拿出一个好的查询计划)。不过,这应该很容易理解。

您需要识别两个表中至少有一封相同电子邮件的id。一种方法是在子查询中加入primaryid和email。下面的解决方案可能不是最有效的,但它会起作用

select t1.primaryid,
       t1.secondaryid as secondaryid_in_t1,
       t2.secondaryid as secondaryid_in_t2
from   table1 t1 join table2 t2 
                 on t1.primaryid = t2.primaryid
where  t1.primaryid not in (
         select a.primaryid 
         from   table1 a join table2 b
                          on a.primaryid = b.primaryid and a.email = b.email
       )
;

您需要标识两个表中至少有一个相同电子邮件的id。一种方法是在子查询中加入primaryid和email。下面的解决方案可能不是最有效的,但它会起作用

select t1.primaryid,
       t1.secondaryid as secondaryid_in_t1,
       t2.secondaryid as secondaryid_in_t2
from   table1 t1 join table2 t2 
                 on t1.primaryid = t2.primaryid
where  t1.primaryid not in (
         select a.primaryid 
         from   table1 a join table2 b
                          on a.primaryid = b.primaryid and a.email = b.email
       )
;

下面是另一种不需要两次查询两个表的方法:

WITH table1 AS (SELECT 1 PrimaryID, 9999 SecondaryID, 'ABC@GMAIL.COM' Email FROM dual UNION ALL
                SELECT 1 PrimaryID, 9999 SecondaryID, 'DEF@GMAIL.COM' Email FROM dual UNION ALL
                SELECT 2 PrimaryID, 8888 SecondaryID, 'CCC@GMAIL.COM' Email FROM dual UNION ALL
                SELECT 3 PrimaryID, 7777 SecondaryID, 'CBA@GMAIL.COM' Email FROM dual),
     table2 AS (SELECT 1 PrimaryID, 1111 SecondaryID, 'ABC@GMAIL.COM' Email FROM dual UNION ALL
                SELECT 2 PrimaryID, 2222 SecondaryID, 'XYZ@GMAIL.COM' Email FROM dual UNION ALL
                SELECT 3 PrimaryID, 3333 SecondaryID, 'CBA@GMAIL.COM' Email FROM dual)
SELECT primaryid,
       t1_secondaryid,
       t2_secondaryid
FROM   (SELECT coalesce(t1.primaryid, t2.primaryid) primaryid,
               t1.secondaryid t1_secondaryid,
               t2.secondaryid t2_secondaryid,
               MAX(CASE WHEN t1.email = t2.email THEN 'Y' ELSE 'N' END) OVER (PARTITION BY coalesce(t1.primaryid, t2.primaryid)) same_email_present
        FROM   table1 t1
               FULL OUTER JOIN table2 t2 ON t1.primaryid = t2.primaryid AND t1.email = t2.email)
WHERE  same_email_present != 'Y';

 PRIMARYID T1_SECONDARYID T2_SECONDARYID
---------- -------------- --------------
         2                          2222
         2           8888 
这将使用完全外部联接将所有行向后拉,而不管它们是否匹配。然后,我们可以使用一个分析函数(我选择了
MAX()
,但如果您愿意,您可以轻松地切换到
COUNT()
SUM()
——您必须更改最终过滤器以反映这一点)为所有行输出“Y”,如果其中至少有一行具有匹配的电子邮件地址


然后,只需过滤掉存在“Y”的行。

还有另一种方法,无需两次查询两个表:

WITH table1 AS (SELECT 1 PrimaryID, 9999 SecondaryID, 'ABC@GMAIL.COM' Email FROM dual UNION ALL
                SELECT 1 PrimaryID, 9999 SecondaryID, 'DEF@GMAIL.COM' Email FROM dual UNION ALL
                SELECT 2 PrimaryID, 8888 SecondaryID, 'CCC@GMAIL.COM' Email FROM dual UNION ALL
                SELECT 3 PrimaryID, 7777 SecondaryID, 'CBA@GMAIL.COM' Email FROM dual),
     table2 AS (SELECT 1 PrimaryID, 1111 SecondaryID, 'ABC@GMAIL.COM' Email FROM dual UNION ALL
                SELECT 2 PrimaryID, 2222 SecondaryID, 'XYZ@GMAIL.COM' Email FROM dual UNION ALL
                SELECT 3 PrimaryID, 3333 SecondaryID, 'CBA@GMAIL.COM' Email FROM dual)
SELECT primaryid,
       t1_secondaryid,
       t2_secondaryid
FROM   (SELECT coalesce(t1.primaryid, t2.primaryid) primaryid,
               t1.secondaryid t1_secondaryid,
               t2.secondaryid t2_secondaryid,
               MAX(CASE WHEN t1.email = t2.email THEN 'Y' ELSE 'N' END) OVER (PARTITION BY coalesce(t1.primaryid, t2.primaryid)) same_email_present
        FROM   table1 t1
               FULL OUTER JOIN table2 t2 ON t1.primaryid = t2.primaryid AND t1.email = t2.email)
WHERE  same_email_present != 'Y';

 PRIMARYID T1_SECONDARYID T2_SECONDARYID
---------- -------------- --------------
         2                          2222
         2           8888 
这将使用完全外部联接将所有行向后拉,而不管它们是否匹配。然后,我们可以使用一个分析函数(我选择了
MAX()
,但如果您愿意,您可以轻松地切换到
COUNT()
SUM()
——您必须更改最终过滤器以反映这一点)为所有行输出“Y”,如果其中至少有一行具有匹配的电子邮件地址


然后,只需过滤掉存在“Y”的行。

两个表中的PrimaryID集是否相同?如果不是,您希望如何处理仅显示在第一个表中而不显示在第二个表中的主ID?是。也一样。如果不是,因为我加入的primaryid相同,我将忽略它。两个表中的primaryid集是否相同?如果不是,您希望如何处理仅显示在第一个表中而不显示在第二个表中的主ID?是。也一样。如果不是,因为我加入的primaryid是一样的,我会忽略它。