2014-04-17 77 views
1

我在另一個表中有一個表和一個關聯的屬性列表。它看起來像這樣:查找SQL中項目的匹配列表

單位

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 140, 40, 45
  • Unit 2:無
  • Unit 310

到目前爲止好。當獲取/更新給定Unit -ID的全套形狀時,此工作正常。

但我有要求選擇所有Units其中有一個相關聯的Shapes的特定列表。例如,我想查找具有Shapes40, 40, 45(應返回Unit_ID 1)的所有Units

我已經發現了一些類似的問題和使用關係劃分的文章,但我不確定這是否可行,因爲大多數解決方案都無法處理出現多次的值。如果我搜索40, 45我希望查詢在我的示例中不返回任何結果,因此我想要完全匹配,因爲沒有Unit與這些匹配完全匹配Shapes(我還需要一個查詢來處理這種情況 - 請選擇UnitsShapes,其中包含一個子集 - 但這可能會很容易,一旦我知道如何搜索完全匹配)。

我使用SQL Server 2012的

回答

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小提琴證明了它的工作原理。但是,上面的代碼不會查找完全匹配,因爲其他形狀可能在記錄中。下面的修改僅適用於完全匹配:

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 joinhaving子句中的附加條件。

+0

聽起來很合理,但是子查詢失敗,因爲'tofind.cnt'不是聚合或GROUP BY的一部分。我嘗試將它添加到GROUP BY內部,但它不會產生正確的結果 - 如果我嘗試在(40,40,45)中搜索(45),它會返回一個ID。 – Excelcius

+0

非常感謝,您的第二個示例似乎可行,我會在我的服務器上嘗試一下。 – Excelcius