验证表中所有组合的存在性

时间:2016-03-07 19:15:39

标签: sql database oracle combinations

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

ERD示例: enter image description here
因此,如果表A中有3行(1-3),表B中有4行,表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, ..
..............

我不知道如何写这个,因为组合的可用数据可能会改变。

感谢您的帮助!

4 个答案:

答案 0 :(得分:2)

您可以使用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代替减号,正如其他答案所示。

如果要将它们全部列在主表的列中(如果存在),否则为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语句中使用该结果来获得简单的是/否答案,以显示是否存在所有组合。等等 - 这真的取决于你想要看到的东西。

答案 1 :(得分:1)

为了获得可能的组合,交叉连接起作用。

所以你可以获得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;   

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

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的减号做了同样的事情,都提出了相同的结果集 - 哪个选项效果最好可能取决于复合表中的记录数,可用索引,以及 - 最重要的是 - 确切地说你想要的是什么。

如果您只是想知道有一个或多个缺失的组合,那么请使用尽可能快地短路的选项。例如,EXISTS将停止检查它何时达到评估为TRUE的案例

答案 2 :(得分:1)

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

mytable

答案 3 :(得分:0)

因此,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 _...)

上有唯一约束时,这才有效

如果您没有,可以使用不同的

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