我this query需要在同一role_id
字段中包含和排除,因此我为NOT EXISTS()
子查询调用同一个表, INNER JOIN
。
SELECT
u.fname
,u.lname
,c.country
,c.postal
FROM [user] u
INNER JOIN company c
ON (u.company_id = c.id)
INNER JOIN users_roles ur
ON (u.id = ur.user_id)
WHERE ur.role_id = 3
AND NOT EXISTS (SELECT 1
FROM users_roles
WHERE role_id = 4
AND user_id= u.id)
ORDER BY c.country, c.postal
这种方法有效,但看起来有点笨重,所以我想知道是否有一种我不了解的更标准(高效)的方法?
答案 0 :(得分:1)
我建议对两个查询运行性能分析,但您也可以使用左外连接执行此操作。
SELECT
u.fname
,u.lname
,c.country
,c.postal
FROM [user] u
INNER JOIN company c
ON (u.company_id = c.id)
INNER JOIN users_roles ur
ON (u.id = ur.user_id)
LEFT OUTER JOIN users_roles ur2
ON (u.id = ur2.user_id)
AND role_id = 4
WHERE ur.role_id = 3
AND ur2.user_id IS NULL
ORDER BY c.country, c.postal
如果找不到表中匹配的行,最终会以NULL
代替ur2
表的值;如果您在WHERE
子句中断言该值为NULL
,则会排除所做的匹配的内容。
答案 1 :(得分:1)
这个只使用一个连接,它使用分组,对role_ids求和并检查聚合结果,sqlfiddle上的执行时间是6ms vs 24ms
SELECT
u.fname
,u.lname
,c.country
,c.postal
,sum(ur.role_id)
FROM [user] u
INNER JOIN company c
ON (u.company_id = c.id)
INNER JOIN users_roles ur
ON (u.id = ur.user_id)
and role_id in(3,4)
group BY u.fname, u.lname, c.country, c.postal
having sum(ur.role_id) = 3
go
答案 2 :(得分:0)
你可以加入user_roles
一次,这可能会对性能有所帮助。我现在无法决定哪个查询我更喜欢。
SELECT
u.fname
,u.lname
,c.country
,c.postal
FROM [user] u
INNER JOIN company c
ON (u.company_id = c.id)
CROSS APPLY (
SELECT SUM (IIF(role_id = 3, 1, 0)) AS role3Count, SUM (IIF(role_id = 4, 1, 0)) AS role4Count
FROM users_roles ur
WHERE role_id BETWEEN 3 AND 4 AND u.id = ur.user_id
) ur
WHERE role3Count > 0 AND role4Count = 0
ORDER BY c.country, c.postal
这有可能稍快一些,因为users_roles
上范围为role_id BETWEEN 3 AND 4
的单个索引搜索足以检索角色。在您的查询中,有两个搜索。另一方面,此查询执行一些聚合和计算。你需要衡量。
我不相信这是一个更好的查询。它比你的更复杂。无论如何,我会提出它。你决定了。