2011-03-30 71 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不是创造一个更大的数据集来测试:)

相关问题