不使用相交运算符重写 SQL 查询

Rewriting an SQL Query Without Using Intersect Operator

我要查询这条语句:

Bars that are frequented by both Mike and John

[table 常客由 2 列组成:饮酒者和他们去的酒吧]

我最初想使用这个 SQL 查询,使用相交运算符:

SELECT  bar
FROM frequents
WHERE drinker ='Mike'
INTERSECT
SELECT bar
FROM frequents
WHERE drinker ='John'

但 MySQL 不支持使用相交运算符。我虽然可能会使用 Join 运算符,但我很难重写此查询。

这是你想要的inner join

SELECT a.bar
FROM frequents a
JOIN frequents b ON a.bar = b.bar 
WHERE a.drinker = 'Mike'
  AND b.drinker = 'John';

请注意,交集比较 select 列表中的所有列,因此等效连接需要执行相同的操作。在你的情况下,它只是一列。

intersect 运算符并没有真正直接转换为 inner join,因为 intersect returns 行对于比较的集合是常见的,而连接过滤器在给定条件下生成一组新的行,这些行由连接集中的行组成。 null 值的处理方式(和重复值)也存在差异。

另一种选择是将 exists 谓词与相关子查询一起使用:

SELECT a.bar
FROM frequents a
WHERE a.drinker ='Mike'
  AND EXISTS (
    SELECT 1 FROM frequents b 
    WHERE a.bar = b.bar
      AND b.drinker ='John'
    );

in 谓词:

SELECT bar
FROM frequents
WHERE drinker ='Mike'
AND bar IN (SELECT bar FROM frequents WHERE drinker ='John')

还有许多其他方法可以做到这一点,但我想我会在这里停下来:)

一个简单的方法是使用聚合:

select f.bar
from frequents f
group by f.bar
having max(drinker = 'John') > 0 and
       max(drinker = 'Mike) > 0;

或者:

select f.bar
from frequents f
where f.drinker in ('John', 'Mike')
group by f.bar
having count(*) = 2;

我喜欢 having 子句,因为我发现它对各种情况都很灵活,例如 John 和 Mike,但 Sara 则不然。或者 John、Mike、Sara 和 Abigail 中的三个。