让我们从以下两个表开始:

CREATE TABLE people AS (
    SELECT * FROM VALUES
    ('david', 10), 
    ('george', 20)
    AS tmp(name, age)
);

CREATE TABLE position AS (
    SELECT * FROM VALUES
    ('george', 'c++'), 
    ('george', 'frontend')
    AS tmp(name, job)
);

以下两种方法是写SEMI JOINANTI JOIN模式的等效方法吗?如果没有,缺少什么?

[SEMI-JOIN == WHERE EXISTS]
SELECT * FROM people SEMI JOIN position ON (people.name=position.name)
SELECT * FROM people WHERE EXISTS (SELECT * FROM position WHERE people.name=position.name)
// or like this?
SELECT * FROM people WHERE name IN (SELECT name FROM position)

[ANTI-JOIN == WHERE NOT EXISTS]
SELECT * FROM people ANTI JOIN position ON (people.name=position.name)
SELECT * FROM people WHERE NOT EXISTS (SELECT * FROM position WHERE people.name=position.name)
// or like this?
SELECT * FROM people WHERE name NOT IN (SELECT name FROM position)

推荐答案

在每个示例中(semi—joins和anti—joins),下面的两个选项都不一样,因为开始时的SELECT *—这将获取所有连接表中的所有列.

如果你用SELECT people.*作为开始,他们在功能上是一样的,据我所见.

至少在SQL Server中,在我try 的一个示例中,每个选项的底部两个都有相同的计划(SQL Server将它们分别称为Left semi joinLeft anti semi join).

编辑:ANTI JOIN 请注意,一种更类似的方法可能是使用LEFT OUTER JOIN,然后使用where连接表没有任何行,例如,

SELECT * 
FROM people LEFT OUTER JOIN position ON (people.name=position.name)
WHERE position.name IS NULL

所有的结果都是相同的,但EXISTS个版本往往更接近理论方法.

Sql相关问答推荐

查询将查找将标记设置为user2的用户

Trino/Presto sq:仅当空值位于组中第一个非空值之后时,才用值替换空值

如何连接第二个表并将其内容输入到第一个表的单个字段中?

重新组合已排序的日期范围

了解放置时的连接

如何在SQL Server中拆分包含字符和数字的列?

数据库SQL-CTE命名空间(错误?)使用临时视图

如何为该查询编写正确分区依据

仅在日期相隔时递增(Oracle SQL)

查找滑动窗口框架中的最大和最小列值

聚合内部的条件在哪里?

仅当 SQL Server 中的表为开时,才在存储过程中使用更改跟踪

Postgresql 生成器列导致语法错误

SQL for Smarties 类型问题:从表中 Select 记录,并对某些值进行分组

如何为给定的股票数据集计算利润/亏损,确保先卖出先买入的股票

Clob 问题 - 将 clob 列拆分为多行

从 varchar 列中删除特殊字符后的前面的零和字符时遇到问题

如何获得上个月和下个月之间的销售额差异

如何仅在满足条件时才按顺序在 SQL 中计数?

在 Microsoft SQL Server 中,如何只为特定值保留不同的行?