我听说有人说表连接可以在任何地方用来替换子查询。我在查询中测试了它,但发现只有在我使用子查询时才会检索到相应的数据集。我无法使用连接获得相同的数据集。我不确定我发现的是对的,因为我是RDBMS的新手,因此没有那么多经验。我将尝试绘制我正在试验的数据库的模式(用文字表示):
数据库有两个表:
Users
( ID ,姓名,城市)和友谊( ID , Friend_ID )
Goal
:用户表用于存储简单的用户数据,友谊表用于表示用户之间的友谊。友谊表将列作为外键,引用Users.ID。表之间有多对多的关系。
问题:我必须检索所有用户的Users.ID和Users.Name,这些用户不是特定用户x的朋友,而是来自同一个城市(很像fb&#39的朋友建议系统)。 / p>
通过使用子查询,我能够实现这一目标。查询看起来像:
SELECT ID, NAME
FROM USERS AS U
WHERE U.ID NOT IN (SELECT FRIENDS_ID
FROM FRIENDSHIP,
USERS
WHERE USERS.ID = FRIENDSHIP.ID AND USERS.ID = x)
AND U.ID != x AND CITY LIKE '% A_CITY%';
示例条目:
Users
Id = 1姓名= Jon City =孟买
Id = 2 Name = Doe City = Mumbai
Id = 3姓名= Arun City =孟买
Id = 4姓名= Prakash City =德里
Friendship
Id = 1 Friends_Id = 2
Id = 2 Friends_Id = 1
Id = 2 Friends_Id = 3
Id = 3 Friends_Id = 2
我是否可以通过执行连接在单个查询中获取相同的数据集。怎么样?如果我的问题不明确,请告诉我。感谢。
注意:我通过指定两个表在子查询中使用了内连接:友谊,用户。省略Users表并从外部使用U会产生错误(但如果不使用表Users的别名,查询在语法上会变得正常,但此查询的结果包括具有多个用户的ID和用户名朋友,包括ID为x的用户。有趣,但不是问题的主题)。
答案 0 :(得分:4)
对于not in
,您可以使用left join
并检查is null
:
select u.id, u.name
from Users u
left join Friends f on u.id = f.id and f.friend_id = @person
where u.city like '%city%' and f.friend_id is null and u.id <> @person;
在某些情况下,您只能通过内部/左/右连接来解决问题,但您的情况不是其中之一。
请检查sql fiddle:http://sqlfiddle.com/#!9/1c5b1/14
另外还有关于您的注意事项:根据您使用的引擎,lateral
加入或cross apply
可以实现您尝试做的事情。
答案 1 :(得分:2)
您只能使用连接重写查询。诀窍是使用内部联接加入User表一次,以识别同一城市内的用户,并使用左联接和空检查引用友谊表以识别非朋友。
SELECT
U1.ID,
U1.Name
FROM
USERS U1
INNER JOIN
USERS U2
ON
U1.CITY = U2.CITY
LEFT JOIN
FRIENDSHIP F
ON
U2.ID = F.ID AND
U1.ID = F.FRIEND_ID
WHERE
U2.id = X AND
U1.ID <> U2.id AND
F.id IS NULL
上述查询无法处理USER x的主键位于FRIENDSHIP表的FRIEND_ID列中的情况。我假设因为你的子查询版本没有处理这种情况,也许你为每个友谊创建了2行,或者友谊不是双向的。
答案 2 :(得分:-2)
在某些情况下,联接和子查询可用于实现类似的结果,但肯定不是全部。例如,带有子查询的查询无法实现与连接的对比:
SELECT ID, COLUMN1, COUNT(*) FROM MYTABLE
WHERE ID IN (
SELECT DISTINCT ID FROM MYTABLE
WHERE COLUMN2 NOT IN (VALUES1, VALUES2)
)
GROUP BY ID;
这只是一个例子,但有很多。
相反,如果不加入子查询,则无法从其他表中获取信息。
关于你的例子
SELECT ID, NAME FROM USERS AS U
WHERE U.ID NOT IN (
SELECT FRIENDS_ID FROM FRIENDSHIP, USERS
WHERE USERS.ID = FRIENDSHIP.ID AND USERS.ID = x)
AND U.ID != x AND CITY LIKE '% A_CITY%';
这可以构造为:
select ID, NAME from users u
join FRIENDSHIP f on f.ID = u.ID
where u.ID = x
and u.ID != y
and CITY like '%A_CITY';
我将你的第二个x改为y,所以不会引起混淆。
当然,如果FRIENDSHIP表中可能有多个结果,您可能还想要LEFT JOIN,即LEFT OUTER JOIN。