SQL:包含&的更好方法排除在同一个字段上,两者,WHERE和NOT EXISTS?

时间:2014-04-11 22:09:43

标签: sql sql-server sql-server-2008

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

这种方法有效,但看起来有点笨重,所以我想知道是否有一种我不了解的更标准(高效)的方法?

3 个答案:

答案 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的单个索引搜索足以检索角色。在您的查询中,有两个搜索。另一方面,此查询执行一些聚合和计算。你需要衡量。

我不相信这是一个更好的查询。它比你的更复杂。无论如何,我会提出它。你决定了。