“不在”这个SQL的可接受的子句,还是有更优雅的方法?

时间:2018-03-26 20:40:36

标签: sql sql-server tsql

在下面的SQL中,@UserExtendedSecurity是一个表变量,根据用户是否具有扩展安全性,它只提供1或0指示符:

INSERT INTO @UserExtendedSecurity (UserId, UserName, HasExtendedSecurity)
    SELECT
        ue.Id,
        adu.FirstName + ' ' + adu.LastName,
        0
    FROM 
        UserExtension ue
    JOIN 
        ADUser adu ON ue.ADUserId = adu.Id
    WHERE 
        ue.Id NOT IN (SELECT UserId FROM @UserExtendedSecurity)

在上面的SQL示例中,@UserExtendedSecurity已经拥有HasExtendedSecurity = 1的所有用户,因此我只是将剩余的用户选择到表变量中,HasExtendedSecurity值为0。最后NOT IN条款做了它需要做的事情,但有没有更合适/优雅/有效的方法来完成我正在做的事情? SQL专家是否考虑以这种方式使用NOT IN作为红旗?

2 个答案:

答案 0 :(得分:0)

令人惊讶的是,NOT EXISTS实际上可以获得更好的性能。请注意,行为略有不同 - 使用空值可以更好地工作(有关详细信息,请参阅this question)。

INSERT INTO @UserExtendedSecurity
(
    UserId,
    UserName,
    HasExtendedSecurity
)
SELECT
ue.Id,
adu.FirstName + ' ' + adu.LastName,
0
FROM 
UserExtension ue
JOIN ADUser adu ON ue.ADUserId = adu.Id
WHERE NOT EXISTS
( SELECT 0 FROM @UserExtendedSecurity WHERE UserId = ue.Id)

答案 1 :(得分:0)

基本上你有3个选择:
(是;博士; - 所有选项都是有效的,并且所有选项都有正确的用法 - 但总的来说,我宁愿大多数时间都使用not exists。)

NOT IN

SELECT
    ue.Id,
    adu.FirstName + ' ' + adu.LastName,
    0
FROM 
    UserExtension AS ue
JOIN 
    ADUser AS adu ON ue.ADUserId = adu.Id
WHERE 
    ue.Id NOT IN (SELECT UserId FROM @UserExtendedSecurity)

优点:

  1. 表变量中的select语句与主选择无关。
  2. 简单易读的语法。
  3. 缺点:

    1. null处理。当null内有NOT IN时,除非将ansi_nulls设置为关闭(由于它已被弃用,您真的应该避免),否则您将无法获得任何结果x NOT IN(y,NULL)相当于x <> y and x <> null - 与null的任何值相比,包括另一个null,将返回unknown
    2. 如果在IN内部设置较大,则与其他选项相比,性能可能会较慢。
    3. NOT EXISTS

      SELECT
          ue.Id,
          adu.FirstName + ' ' + adu.LastName,
          0
      FROM 
          UserExtension AS ue
      JOIN 
          ADUser AS adu ON ue.ADUserId = adu.Id
      WHERE 
          NOT EXISTS (SELECT 1 FROM @UserExtendedSecurity WHERE UserId = ue.Id)
      

      优点:

      1. Null不再是问题。
      2. not in替代方案更好的性能。
      3. 缺点:

        1. 语法有点麻烦。
        2. 需要相关的子查询。
        3. LEFT JOIN

          SELECT
              ue.Id,
              adu.FirstName + ' ' + adu.LastName,
              0
          FROM 
              UserExtension AS ue
          JOIN 
              ADUser AS adu ON ue.ADUserId = adu.Id
          LEFT JOIN  @UserExtendedSecurity AS ues ON ues.UserId = ue.Id
          WHERE ues.UserId IS NULL
          

          优点:

          1. 不需要子查询,相关与否。
          2. Null值是&#34;自然&#34;处理。
          3. not in替代方案更好的性能。
          4. 缺点:

            1. 可能导致重复结果。
            2. 其他替代方案更好地传达了查询的意图,使得此替代方案的可读性降低。