验证 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
)
我想为 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
)