验证 table 中是否存在所有组合

Verify existance of all combinations in table

我想为 oracle 编写一个查询,以验证 table 中是否存在所有组合。 我的问题是 table 的 "key-columns" 是链接到其他 table 的 FK,这意味着组合基于其他 table 的行。

ERD 示例:
所以,如果 table A 中有 3 行(1-3),table B 中有 4 行,table C 中有 2 行,MyTable 必须有这些行(3x4x2,总共 24 个):

id, a_fk, b_fk, c_fk, someValue
x, 1, 1 ,1, ..
x, 1, 1, 2, ..
x, 1, 2, 1, ..
x, 1, 2, 2, ..
x, 1, 3, 1, ..
x, 1, 3, 2, ..
..............

我不知道怎么写,因为组合的可用数据可能会改变。

感谢您的帮助!

因此,MyTable 中的总行数应该等于其他表中总行数的乘积,您可以这样尝试:

select
case when (select count(*) from MyTable) =
((select count(*) from TableA) * (select count(*) from TableB)... )
then 'Everything is fine'
else 'Some rows are missing' end
from dual

仅当您对 (fk_a、fk_b、fc_...)

具有唯一约束时,此方法才有效

如果你没有,你可以使用 distinct

select
case when (select count(distinct concat(fk_a, fk_b,....)) from MyTable) =
((select count(*) from TableA) * (select count(*) from TableB)... )
then 'Everything is fine'
else 'Some rows are missing' end
from dual

要获得可能的组合,交叉连接有效。

因此您可以通过以下方式获得 24 行:

with a as (
    select 1 id1 from dual union all
    select 2 id1 from dual union all
    select 3 id1 from dual )
  , b as (
    select 1 id2 from dual union all
    select 2 id2 from dual union all
    select 3 id2 from dual union all
    select 4 id2 from dual )   
  , c as (
    select 1 id3 from dual union all
    select 2 id3 from dual )
select id1, id2, id3 
from a cross join b cross join c;   

从那里可以很容易地找到 table 中存在或不存在的组合。要获得不在目标 table 中的组合,您可以:

with a as (
    select 1 id1 from dual union all
    select 2 id1 from dual union all
    select 3 id1 from dual )
  , b as (
    select 1 id2 from dual union all
    select 2 id2 from dual union all
    select 3 id2 from dual union all
    select 4 id2 from dual )   
  , c as (
    select 1 id3 from dual union all
    select 2 id3 from dual )
  , t as ( 
     select 1 id1, 1 id2, 1 id3 from dual union all
     select 1 id1, 1 id2, 2 id3 from dual union all
     select 1 id1, 2 id2, 1 id3 from dual union all
     select 1 id1, 2 id2, 2 id3 from dual union all
     select 1 id1, 3 id2, 1 id3 from dual union all
     select 1 id1, 4 id2, 2 id3 from dual )
select lst.id1, lst.id2, lst.id3
from (  
    select id1, id2, id3 
    from a cross join b cross join c ) lst
where not exists (select 1 from t
                  where t.id1 = lst.id1 
                    and t.id2 = lst.id2
                    and t.id3 = lst.id3)        

或者,使用 NOT IN 测试:

select lst.id1, lst.id2, lst.id3
from (  
    select id1, id2, id3 
    from a cross join b cross join c ) lst
where (id1, id2, id3) not IN (select distinct id1, id2, id3  from t)

Alex 的 minus 做同样的事情,都得到相同的结果集 - 哪个选项最有效可能取决于组合中的记录数 table、可用索引,以及 - 最重要的- 正是你想要的。

如果你只是想知道有一个或多个缺失的组合,那么使用一个可以尽快短路的选项。例如,EXISTS 将在遇到计算结果为 TRUE

的情况时停止检查

您可以使用 cross joins 识别所有可能的组合,这些组合生成行的笛卡尔积:

select a.id, b.id, c.id
from tablea a
cross join tableb b
cross join tablec c

根据您想要的确切结果,您可以通过各种方式使用它来查看您拥有或不拥有的东西。要列出不存在的组合,请使用 the minus set operator:

select a.id, b.id, c.id
from tablea a
cross join tableb b
cross join tablec c
minus
select fk_a, fk_b, fk_c
from my_table mt;

或者您可以使用 not exists 而不是减号,如其他答案所示。

如果你想用主 table 的列(如果存在)列出它们,否则为 null,你可以使用左外连接:

select a.id, b.id, c.id, mt.id
from tablea a
cross join tableb b
cross join tablec c
left join my_table mt
on mt.fk_a = a.id and mt.fk_b = b.id and mt.fk_c = c.id

您还可以计算第一个查询的结果,然后在 case 语句中使用它来获得简单的 yes/no 答案以显示是否所有组合都存在。等等 - 这真的取决于你想看什么。

使用 CROSS JOIN 从您的三个(或更多)表中获取记录集的笛卡尔积,并应用 NOT EXISTS 子句为您提供那些不存在的行(在输出中)在 mytable.

select a.id, b.id, c.id
from tbla a cross join tblb b cross join tblc c
where not exists (
  select 1
  from mytable t
  where t.fk_a = a.id
    and t.fk_b = b.id
    and t.fk_c = c.id
  )