2011-03-30 56 views
1

鑑於這種表結構和示例數據(T3不應在查詢中使用,這是隻有在這裏顯示T1和T2之間的關係):有沒有辦法在這種類型的SQL SELECT中刪除嵌套查詢?

 t1     t2       t3 
-------------- ----------------- -------------------------------- 
| id | value | | t1key | t3key | | id | value     | 
| 1 | 2008 | |  3 |  1 | | 1 | "New intel cpu in 2010" | 
| 2 | 2009 | |  4 |  1 | | 2 | "New amd cpu in 2008" | 
| 3 | 2010 | |  6 |  1 | | |      ... | 
| 4 | intel | |  1 |  2 | -------------------------------- 
| 5 | amd | |  5 |  2 | 
| 6 | cpu | |  6 |  2 | 
| | ... | |  | ... | 
-------------- ----------------- 

你將如何構建一個SQL查詢,將滿足以下內容:

Given the input for t1.id is the set {6} returns t1.id set {3,4,6,1,5} 
Given the input for t1.id is the set {6,4} returns t1.id set {3,4,6} 
Given the input for t1.id is the set {5,4} returns t1.id set {} 

並且在表更大時不會導致性能下降...?

+3

我不明白的規格。 「指定t1.id是否是...」是什麼意思? – 2011-03-30 06:46:08

+0

可以調用表t1'單詞',調用表t3'短語'和調用表t2'單詞是短語'。我想你想找到與特定的一組words.ids相同的詞組中的所有words.id。那是對的嗎? – 2011-03-30 06:56:19

+0

@Stefan:「指定t1.id是集合{6}」的意思是「WHERE t1.id = 6」..隨着集合的增長,它變得棘手。 @ypercube:非常多,但所有重要的單詞都已從短語中刪除並放入t2 :) – 2011-03-30 07:38:16

回答

1

這不是很清楚自己想要什麼。

我會打電話表t1 word,通話表t3 phrase和通話表t2 word is in phrase

然後,我想你想找到所有word.ids ar e與一組特定的word.ids相同的短語。那是對的嗎?

SELECT DISTINCT t1.id 
FROM t1 
    JOIN t2 
    ON t1.id = t2.t1key 
    JOIN t2 copyt2 
    ON copyt2.t3key = t2.t3key 
WHERE copyt2.t1key IN 
    (6,4)  --what you want to check here 

修正

讀喬的評論,並重新讀取問題的細節,我想你想找到與您指定的列表中的所有單詞出現在同一短語中所有單詞。

這看起來像一個關係劃分的問題:

SELECT DISTINCT t2a.t1key 
FROM t2 AS t2a 
WHERE NOT EXISTS 
    (SELECT * 
    FROM t2 AS t2b 
    WHERE t2b.t1key IN (6,4) 
     AND NOT EXISTS 
     (SELECT * 
     FROM t2 AS t2c 
     WHERE t2a.t3key = t2c.t3key 
      AND t2c.t1key = t2b.t1key 
    ) 
) 

第二個解決方案:

SELECT a.t1key 
FROM t2 AS a 
    JOIN t2 as b 
    ON a.t3key = b.t3key 
WHERE b.t1key IN (6,4)  --list you want to check 
GROUP BY a.t1key, a.t3key 
HAVING COUNT(*) = 2   --size of list 
; 

第三方案:

SELECT DISTINCT t1key 
FROM t2 
WHERE t3key IN 
    (SELECT t3key 
    FROM t2 
    WHERE t1key IN (6,4) 
    GROUP BY t3key 
    HAVING COUNT(*) = 2 
) 
; 

注:第一(與NON EXISTS)解決方案有很大的不同與另外兩個:

如果您嘗試列出其成員沒有出現在表t2中,比如說(2)(2,7),它將顯示來自t2的所有t1key。

第二個和第三個解決方案在這種情況下將顯示NO鍵。

+0

t3僅用於幫助您理解t1和t2之間的關係 – 2011-03-30 07:10:25

+0

使用您的查詢,您的值{6,4}的結果返回{3,4 ,6,1,5}而不是{3,4,6}。我不知道如何使它更清晰,我有一組輸入,我希望在給定的表結構的問題中指定的輸出。 – 2011-03-30 07:25:37

+0

@Tony:編輯我的答案。 – 2011-03-30 07:36:27

0

他在那裏, 您確定您已選擇正確的表格結構嗎? 它似乎沒有被標準化 - 雖然我不確切知道每個表可以表示什麼實體。

它重要的是保持你的數據庫設計,至少在第三範式(見Wikipedia article

你的查詢會更自然,也容易制定

+0

它看起來很正常。 (對於t1和t3之間的多對多關係) – 2011-03-30 06:54:00

1
select distinct t1key 
from t2 
where t3key in 
(
    select t3key from t2 where t1key = 6 
    intersect 
    select t3key from t2 where t1key = 4 
) 

==> 3, 4, 6 

根據輸入集中有多少項目,您需要添加更多的「相交」子句。

在SQL Server上測試。

+0

啊,可惜我忘了提到mysql ...但是,是的,解決方案的工作原理...有沒有辦法繞過嵌套?如果輸入是{3,4,6,7,8},你會怎麼寫? – 2011-03-30 07:22:10

+0

如果您的輸入是{3,4,6,7,8},則需要添加更多「相交選擇...」行。換句話說,您的程序將需要根據輸入集中的項目數來動態生成查詢文本。至於嵌套,你可以通過將子查詢分解爲內部連接和相交來擺脫這種情況,但是在我的測試中,這會降低效率。 – 2011-03-30 11:40:13

+0

我只是看了一下SQL Server在這裏所有答案的執行計劃的估計成本,使用t2中的300,000行測試數據。 Stefan的正確答案和我的答案並列第一,然後是vbence,然後是ypercube的正確答案。這可能不會證明什麼,但:)你應該使用自己的數據測試所有的答案。 – 2011-03-30 11:48:38

1
select distinct t2b.t1key 
from 
    t2 t2a 
    inner join t2 t2b on t2a.t3key = t2b.t3key 
where t2a.t1key in (6, 5) /* or whatever */ 

開始對T1(關鍵字),你會得到所有的T3(表情),它包含 「CPU」(或其他)。你不需要直接加入t3,你不需要從那裏獲取任何數據。第二次加入t2會得到找到的表達式中包含的所有其他關鍵字。你只需要返回它們的t1key。


更正:如果你不想子查詢,你可以創建一個參與爲每個關鍵字搜索:

select distinct t2b.t1key 
from 
    t2 t2a 
    inner join t2 t2b on t2a.t3key = t2b.t3key and t2a.t1key = 6 
    inner join t2 t2c on t2a.t3key = t2c.t3key and t2a.t1key = 5 
+0

對於輸入{6,4},返回{1,3,4,5,6},而不是{3,4,6}。我想他想找到包含所有單詞的短語,而不是任何單詞,如果你明白我的意思。 – 2011-03-30 07:03:15

+0

@Joe:你說得對。我也在我的回答中錯過了這一點。 – 2011-03-30 07:05:28

2

這裏是我的傑出貢獻(至少讓我們假設它的輝煌現在:)

SELECT DISTINCT a2.t1key, COUNT(*) AS cnt 
FROM t2 AS a1 
    LEFT JOIN t2 AS a2 ON a2.t3key = a1.t3key 
WHERE a1.t1key IN (6, 4) 
GROUP BY a2.t3key, a2.t1key 
HAVING cnt >=2 

IN (6,4)部分是真正自我解釋。在cnt >=2中,2是IN子句中的id-s的數目。例如:您正在使用IN (6),那麼您應該使用cnt >=1

我不知道需要在所有>,但我懶enogh不是創造一個更大的數據集來測試:)

相關問題