我在另一个表中有一个表和一个相关的属性列表。它看起来像这样:
表单位:
ID | State | ...
----------------
1 | 10 | ...
2 | 15 | ...
3 | 10 | ...
(状态在这里没有意义,我只是添加它以显示此表包含其他列)
表形状:
ID | Unit_ID (FK) | Shape
-------------------------
1 | 1 | 40
2 | 1 | 40
3 | 1 | 45
4 | 3 | 10
基本上Unit
中的每一行都可以有各种相关的形状。形状的顺序并不重要,但形状可以多次关联。
在我的示例中,Units
具有以下形状:
Unit 1
:40, 40, 45
Unit 2
:无Unit 3
:10
到目前为止一切顺利。这在获取/更新给定Unit
- ID的完整形状集时工作正常。
但我要求选择具有相关Units
列表的所有Shapes
。例如,我想查找具有Units
Shapes
的所有40, 40, 45
(应返回Unit_ID
1)。
我已经找到了一些使用关系划分的类似问题和文章,但我不确定这是否有效,因为大多数解决方案都无法处理多次出现的值。我希望得到完全匹配,如果我搜索40, 45
我希望查询在我的示例中没有返回任何结果,因为没有Unit
正好匹配Shapes
(我会还需要一个查询来处理这种情况 - 选择包含子集的Units
Shapes
- 但是一旦我知道如何搜索完全匹配,这可能很容易。
我正在使用SQL Server 2012.
答案 0 :(得分:2)
以下方法首先将列表放入表格(井,CTE)中,每个形状和计数次数。然后,它会进行各种检查。
首先,shapes
中的每个形状都显示正确的次数。这就是内部聚合的来源。
然后,它会计算匹配的形状数,并验证这是tofind
中不同形状的总数:
with tofind as (
select 40 as shape, 2 as cnt union all
select 45 as shape, 1 as cnt
)
select s.unit_id
from (select s.unit_id, tofind.cnt as tf_cnt, count(s.id) as s_cnt
from shapes s join
tofind
on s.shape = tofind.shape
group by s.unit_id, tofind.shape, tofind.cnt
) s
group by s.unit_id
having sum(case when s_cnt = tf_cnt then 1 else 0 end) = (select count(*) from tofind);
编辑:
Here是一个SQL Fiddle,证明它有效。但是,上面的代码并不寻找完全匹配,因为其他形状可能在记录中。以下修改仅适用于完全匹配:
with tofind as (
select 40 as shape, 2 as cnt union all
select 45 as shape, 1 as cnt
)
select s.unit_id
from (select s.unit_id, tofind.cnt as tf_cnt, count(s.id) as s_cnt
from shapes s left outer join
tofind
on s.shape = tofind.shape
group by s.unit_id, tofind.shape, tofind.cnt
) s
group by s.unit_id
having sum(case when s_cnt = tf_cnt then 1 else 0 end) = (select count(*) from tofind) and
count(*) = sum(case when s_cnt = tf_cnt then 1 else 0 end);
区别在于left outer join
和having
子句中的附加条件。