2009-09-10 57 views
12

是常見的我有一個交叉引用表,看起來像這樣:SQL選擇行,其中一列的值跨越另一個標準列

id document_id subject_id 
1 8   21 
2 5   17 
3 5   76 
4 7   88 
5 9   17 
6 9   76 
7 2   76 

它匹配文檔對象。文件可以是多個主題的成員。我想從表中返回給定文檔匹配全部給定集合中的主題的行。例如,給定的一組主題:

(17,76)

我要爲匹配所有受試者在組(至少)在某處交叉引用表,文件只返回行。鑑於上述設定所需的輸出設定爲:

id document_id subject_id 
2 5   17 
3 5   76 
5 9   17 
6 9   76 

注意,不返回該表的最後一排,因爲該文件只匹配所需的科目之一。

什麼是最簡單和最有效的方式來查詢這在SQL中?

+0

很高興知道您是如何爲查詢提供參數的。我看到一個答案,雖然非常好,但它只能在參數集中精確地使用2個值。如果你可以限制參數的數量,例如,最多10個,那麼這是一個對話。如果你需要該應用程序是靈活的,那麼建議將會不同。 – Eugene 2009-09-10 23:08:33

+0

謝謝,輸入基本上是「選擇任意數量的主題」,因此主題ID的集合可以像主題數量一樣增長(理論上)。 – Maciek 2009-09-10 23:35:20

回答

27

我假設這個表的天生關鍵是document_id + subject_id,而且id是一個代理; IOW,document_id和subject_id是唯一的。因此,我只是假裝它不存在,而且一個獨特的約束是關鍵。

讓我們從顯而易見的開始。

SELECT document_id, subject_id 
    FROM document_subjects 
WHERE subject_id IN (17,76) 

,讓你你想要的一切加你不想東西。所以我們需要做的就是過濾出其他的東西。 「其他東西」是具有不等於期望主題的計數的計數的行的組。

SELECT document_id 
    FROM document_subjects 
WHERE subject_id IN (17,76) 
GROUP BY document_id 
HAVING COUNT(*) = 2 

請注意,因爲它不參與分組,所以刪除了subject_id。更進一步,我將添加一個名爲subjects_i_want的假想表,其中包含N行您想要的主題。

SELECT document_id 
    FROM document_subjects 
WHERE subject_id IN (SELECT subject_id FROM subjects_i_want) 
GROUP BY document_id 
HAVING COUNT(*) = (SELECT COUNT(*) FROM subjects_i_want) 

顯然subjects_i_want可以換成另一個子查詢,臨時表或其他。但是,一旦擁有了document_id的這個列表,就可以在更大查詢的子查詢中使用它。

SELECT document_id, subject_id, ... 
    FROM document_subjects 
WHERE document_id IN(
     SELECT document_id 
      FROM document_subjects 
      WHERE subject_id IN (SELECT subject_id FROM subjects_i_want) 
      GROUP BY document_id 
     HAVING COUNT(*) = (SELECT COUNT(*) FROM subjects_i_want)) 

或其他。

+0

太棒了,謝謝。 – Maciek 2009-09-10 23:30:09

+1

+1非常好,亞歷克斯。最近我注意到了這個問題的一些變化,這是迄今爲止我看到的最清晰的通用解決方案。 – Matt 2009-09-10 23:37:25

+0

+1,非常nce並且幫助了我,如果count(*)執行的話會更好i擁有不同的條目,因爲它可以消除重複數據被考慮的可能性;最好是COUNT(DISTINCT subject_id)而不是COUNT(*) – 2016-03-29 05:48:58

1

這是一個非常有趣的問題。

我假設你想更廣義的查詢,但這次是我會在你總是有相同數量的對象的情況下做(說二):

SELECT T.id, T.document_id, T.subject_id 
    FROM table T 
     INNER JOIN table T1 ON T.document_id = T1.document_id AND T1.subject_ID = 17 
     INNER JOIN table T2 ON T.document_id = T2.document_id AND T2.subject_ID = 76    

當然,你可以添加另一個INNER JOIN來添加另一個主題ID ..但我承認這不是一個很好的通用解決方案。

+0

噢,我確實在尋找一個可以匹配任意數量主題的解決方案。 – Maciek 2009-09-10 23:07:16

0
select document_id from table1 
where subject_id in (17, 76) 
group by document_id 
having count(distinct subject_id) = 2 
2

使用Oracle(或任何允許with子句的數據庫)。這允許一次定義subject_id值。

with t as (select distinct document_id from table1 where subject_id in (17,76)) 
select document_id from table1 where subject_id in (select subject_id from t) 
group by document_id 
having count(*) = (select count (*) from t); 
+0

我發現這個答案是最有用的,因爲它也適用於PostgreSQL。 – ramhiser 2016-07-31 19:08:40

相關問題