仅为sql中的条件选择唯一记录

时间:2015-11-28 20:05:48

标签: sql sql-server distinct

我怎样才能选择仅具有ACCESS_COLUMN_ID值1的不同用户ID,即使它们也可能具有ACCESS_COLUMN_ID值2。

这是我的查询返回1和2:

SELECT DISTINCT(USER_ID) FROM USER_ACCESS WHERE ACCESS_COLUMN_ID = 1

返回的结果包含同时拥有ACCESS_COLUMN_ID = 2的用户ID。

Here is my table data

USERID ACCESS_COLUMN_ID 
1          1
1          2
2          1

我期待USERID 2仅作为我的查询结果

3 个答案:

答案 0 :(得分:5)

您可以使用HAVING

SELECT    USER_ID
FROM      USER_ACCESS 
GROUP  BY USER_ID
HAVING    MIN(ACCESS_COLUMN_ID) = 1
AND       MAX(ACCESS_COLUMN_ID) = 1

此查询将获取所有user_id,但由于group by子句,只会获得唯一的access_column_id。然后,它将为每个值找到它找到的最小值和最大值user_id,如果这两个值都是1,则SELECT DISTINCT USER_ID FROM USER_ACCESS UA1 WHERE UA1.ACCESS_COLUMN_ID = 1 AND NOT EXISTS ( SELECT 1 FROM USER_ACCESS UA2 WHERE UA1.USER_ID = UA2.USER_ID AND UA2.ACCESS_COLUMN_ID <> 1) 将保留在最终结果集中。

上面会有很好的表现,因为它只引用一次表。

为了您的兴趣,还有其他几种方法可以获得相同的结果。但是他们都需要将表引用两次。您可能希望自己比较它们的可读性和性能:

NOT EXISTS

SELECT    DISTINCT USER_ID
FROM      USER_ACCESS
WHERE     ACCESS_COLUMN_ID = 1
AND       USER_ID NOT IN (
              SELECT USER_ID
              FROM   USER_ACCESS
              WHERE  ACCESS_COLUMN_ID <> 1)

不在

这与前一个非常相似,但根据我的经验,表现并不好:

SELECT    DISTINCT USER_ID
FROM      USER_ACCESS UA1
LEFT JOIN USER_ACCESS UA2
       ON UA1.USER_ID = UA2.USER_ID
      AND UA2.ACCESS_COLUMN_ID <> 1
WHERE     UA1.ACCESS_COLUMN_ID = 1
AND       UA2.USER_ID IS NULL

外部自我加入

这通常比前两个解决方案具有更好的性能:

NULL

最后一个ACCESS_COMUN_ID <> 1条件检查外部联接是否产生任何匹配(使用MINUS)。

<强>除非

这是SQL Server特有的语法,但很容易理解(Oracle有类似的SELECT DISTINCT USER_ID FROM USER_ACCESS WHERE ACCESS_COLUMN_ID = 1 EXCEPT SELECT USER_ID FROM USER_ACCESS WHERE ACCESS_COLUMN_ID <> 1 );

DISTINCT

备注DISTINCT

GROUP BY关键字很容易理解,但通过使用USER_ID子句,通常可以获得更好的性能。这可以应用于上述所有解决方案。

如果确定ACCESS_COLUMN_IDDISTINCT的两个记录不能有相同的值,那么function myFunction(array) { var largest = array.replace(/\D/g, ''); for (var i = 0; i < array.length; i++) { if (largest < array[i]) { largest = array[i]; } } console.log(largest); } myFunction([509 - 111 - 1111, 509 - 222 - 2222, 509 - 333 - 3333]); 关键字可以在上述查询中省略。

答案 1 :(得分:0)

您可以使用NOT IN过滤掉ACCESS_COLUMN_ID = 2

的内容
SELECT DISTINCT(USER_ID) FROM USER_ACCESS WHERE ACCESS_COLUMN_ID = 1 and 
USER_ID NOT IN (
  SELECT DISCTINCT (USER_ID) FROM USER_ACCESS WHERE ACCESS_COLUMN_ID = 2
)

答案 2 :(得分:0)

您可以通过多种方式完成此任务。这可能是最灵活的。

获取具有所需访问ID的所有用户的列表,并将其反对具有不需要的访问ID的用户列表。这具有可扩展性的好处。

SELECT * FROM USER_ACCESS u1
LEFT OUTER JOIN 
    (SELECT USER_ID FROM USER_ACCESS 
     WHERE ACCESS_COLUMN_ID NOT IN ($IDsGoHere$)) u2
ON u1.USER_ID = u2.USER_ID
WHERE u1.ACCESS_COLUMN_ID IN ($IDsGoHere$) AND
u2.USER_ID IS NULL;

几个关键点:

  • 查询可能会受益于子选择表u2可能DISTINCT。这取决于返回的结果数量。
  • 如果您想查看有权访问A但没有访问权限B的所有用户,则可以相应地替换子选择的WHERE NOT IN子句。

我不知道SQLServer如何处理优化,但我看到系统发现性能增益取代了IN (X)NOT IN (X) = X!= X分别

编辑1 - 围绕WHERE子句的一般思考

作为一般经验法则,在计算响应时,考虑是否需要查询不在生成行范围内的其他行总是好的。如果你这样做(在这种情况下,行必须存在,并且同一USER_ID不存在其他行),通常需要引入某种类型的连接以消除结果不想要。