0

抱歉这个可能很简单的问题 - 但我对 sql 很陌生。

基本上 - 我有一个表,我需要检查下一组中不存在某些值的位置。

我有 3 列 - 让我们称它们为不相关的年份、名称和 col3。现在我需要查看 2009 年存在哪些名称,但 2010 年和随后的所有年份中都没有?我完全不知道这是如何工作的。

我所拥有的是:

select *
from table1
where year > 2008 and year < 2012

然后我不确定如何在其中放置另一个查询?我在想类似的事情:

select * 
table1

哪里的名字不等于上一年的名字?

我该怎么做?

4

3 回答 3

3

这是“set-within-sets”查询。“set”是名称的所有行。“组内”是存在“2009”年,而其他年则不存在。

我首选的解决方法是使用group byand having,因为这是最通用的表述。以下是它对您的查询的工作方式:

select name
from t
group by name
having sum(case when year = 2009 then 1 else 0 end) > 0 and
       sum(case when year > 2009 then 1 else 0 end) = 0;

该表达式sum(case when year = 2009 then 1 else 0 end)计算给定名称的 2009 行数。仅当至少有一行 ( > 0) 时,名称才会“通过”。第二个条件计算年份大于 2009 的行数。当没有这些时,名称通过= 0

编辑:

我喜欢这种方法的原因是因为灵活性。例如,如果您想要 2009 年和 2010 年,查询将是:

having sum(case when year = 2009 then 1 else 0 end) > 0 and
       sum(case when year = 2010 then 1 else 0 end) > 0;

如果你想要 2009 年、2010 年而不是 2011 年:

having sum(case when year = 2009 then 1 else 0 end) > 0 and
       sum(case when year = 2010 then 1 else 0 end) > 0 and
       sum(case when year = 2011 then 1 else 0 end) = 0;

所有这些都具有基本相同的运行时间。

于 2013-09-18T19:34:08.120 回答
2

至少有两种方法,可能还有许多其他选择。

首先使用 MINUS 运算符

SELECT name
  FROM table1
 WHERE year = 2009
MINUS
SELECT name
  FROM table1
 WHERE year = 2010

你也可以使用 NOT IN 来做同样的事情

SELECT name
  FROM table1
 WHERE year = 2009
       AND name NOT IN (SELECT name
                          FROM table1
                         WHERE year = 2010)
于 2013-09-18T19:36:39.460 回答
0

我喜欢其他两个答案(除了NOT IN替代方案,它往往很慢)。另一种方法是将“2009”名称左连接到“2009 年后”名称并检查“2009 年后”名称是否为空:

SELECT table1.name
FROM table1
LEFT JOIN (
  SELECT DISTINCT name
  FROM table1
  WHERE year > 2009
) After2009 ON table1.name = After2009.name
WHERE table1.year = 2009
  AND After2009.name IS NULL

当连接两个表时,这种方法往往非常快。我不确定在自我加入时这是否成立。

这个答案也是“一般的”,我的意思是它会像戈登那样在大多数其他数据库中工作。

于 2013-09-18T19:58:04.987 回答