有人可以解释一下sql查询是如何工作的吗?



下面的SQL查询获取具有不同姓氏的所有first_names。

select a.first_name
from names a
WHERE a.first_name in (
select b.first_name 
from names b
WHERE a.last_name<>b.last_name
)

我无法弄清楚这究竟是如何工作的。我认为会发生的情况是,对于表中的每一行,子查询将检查是否存在具有不同姓氏的行。但是检查仅在相同的名字值之间进行。有人可以解释一下这实际上是如何工作的。

首先,正如我在评论中提到的,我建议为此使用HAVING。它不需要对表进行 2 次扫描,只需要一次,它不会返回相同first_name的重复项,并且您可能更容易理解:

SELECT first_name
FROM dbo.names
GROUP BY first_name
HAVING COUNT(DISTINCT last_name) > 1;

应该是相当不言自明的;它返回的行中,每个值last_namefirst_name都有超过 1 个不同的值。


对于您的查询,让我们看看WHERE

WHERE a.first_name IN (SELECT b.first_name 
FROM names b
WHERE a.last_name<>b.last_name

首先,我们"连接"names的 2 个实例(别名aadb),其中last_name的值在 2 个实例中不同。这很可能是一项昂贵的操作;如果你有一个表将有 1,000 行,并且它有 900 个不同的值last_name那么你最终会得到联接每行数百个匹配项。

之后,它检查在联接的行集中别名为a的实例中的行first_namenames;然后有 2 个(或更多)具有不同last_name值的相同first_name实例。

在上下文中,将IN与使用值的文本列表没有什么不同。 如果表中ISomeTable具有值123457,则WHERE SomeColumn IN (1,2,3,4,5,7)WHERE SomeColumn IN (SELECT I FROM SomeTable)相同。

你可以像这样将其解读为内部连接,或者 EXISTS :

SQL 小提琴

查询 2

select a.first_name
from names a
inner join names b
on a.first_name = b.first_name 
and a.last_name <> b.last_name
Group by a.first_name, a.last_name 

结果

| first_name |
|------------|
|       john |
|       john |
|       john |

查询 3

select a.first_name
from names a
where exists( 
select 1 from names b
WHERE a.first_name = b.first_name 
and a.last_name <> b.last_name
)

结果

| first_name |
|------------|
|       john |
|       john |
|       john |
  1. 首先进行语法检查,然后创建表达式树(此时您可以另外检查项目和"排列")(即表中确实存在字段)。这是初始阶段;如果有错误,你只是建议提交者认真对待。
  2. 然后是分析。SQL 查询与程序的不同之处在于它不指定如何执行任务;相反,它指定结果是什么。基于集合的逻辑。因此,您引入了一个查询分析器(根据产品的不同,从糟糕到好 - Oracle 长期以来一直使用糟糕的查询分析器,DB2 具有最敏感的查询分析器,包括监视磁盘速度)来找出如何最好地处理此结果。这是一个非常复杂的野兽,它可能会尝试数十种或数百种技术,然后才能确定他认为最快的一种(基于成本,基本上是一些统计数据)。
  3. 然后执行。

最新更新