SQL:包含&;排除在同一个字段上,而不是同时存在,在何处和不存在?

SQL:包含&;排除在同一个字段上,而不是同时存在,在何处和不存在?,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,我在同一个role\u id字段中有需要包含和排除的内容,因此我为NOT EXISTS()子查询和内部联接调用同一个表 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.rol

我在同一个
role\u id
字段中有需要包含和排除的内容,因此我为
NOT EXISTS()
子查询和
内部联接调用同一个表

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

这种方法很有效,但似乎有点笨重,所以我想知道是否有一种更标准(性能)的方法我不知道?

我建议对两个查询都运行性能分析,但您也可以使用左外部联接来执行此操作

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
,它将排除任何匹配项。

您可以只加入
用户角色一次,这可能会对性能有所帮助。我现在无法决定我更喜欢哪一个问题

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
这可能会稍微快一点,因为对
用户角色
进行单个索引搜索,其范围
角色id在3到4之间
就足以检索角色。在您的查询中,有两个搜索。另一方面,此查询执行一些聚合和计算。你需要测量一下


我不认为这是一个更好的问题。它比你的更复杂。不管怎样,我还是会提出的。您自己决定。

这一个只进行一次连接,它使用分组、对角色ID求和并检查聚合结果,SQLFIDLE上的执行时间是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

它避免了子查询。根据数据和数据库软件(SQL Server/MySQL/Oracle/Postgres/etc),此查询可能会收到比基于子查询的方案更有效的计划。一般来说,
JOIN
比子查询快。SQL Server不具备这种通用性。SQL Server将
EXISTS
谓词转换为半联接。可能是这样,但请注意,我建议问题的作者对这两个查询进行分析,并且我以书面形式回答问题(即是否有其他方式编写查询)。