在 sql 中只有 select 个条件的唯一记录
Only select unique record for a condition in sql
我如何才能 select 只有不同的用户 ID 仅具有 ACCESS_COLUMN_ID 值 1,即使它们也可能具有 ACCESS_COLUMN_ID 值 2。
这是我的查询 returns 1 和 2:
SELECT DISTINCT(USER_ID) FROM USER_ACCESS WHERE ACCESS_COLUMN_ID = 1
返回的结果中也包含有ACCESS_COLUMN_ID = 2
的userid。
Here is my table data
USERID ACCESS_COLUMN_ID
1 1
1 2
2 1
我只希望 USERID 2 作为我的查询结果
你可以使用 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
,如果这两个值都是1,那么user_id
会保留在最终结果集中。
上面的代码会有很好的性能,因为它只引用了一次table。
为了您的兴趣,还有其他几种方法可以获得相同的结果。但是,它们都需要 table 被引用两次。您可能想自己比较它们的可读性和性能:
不存在
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)
不在
这与上一个非常相似,但根据我的经验,性能不如上一个:
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
)。
除外
这是SQL服务器特有的语法,但是很容易理解(Oracle有类似的MINUS
);
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_ID
不可能有两条记录具有相同的值,则可以在上述查询中省略DISTINCT
关键字。
可以用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
)
您可以通过多种方式完成此任务。这可能是最灵活的。
获取具有所需访问 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;
几个要点:
- 查询可能受益于子select table
u2
可能是 DISTINCT
。这取决于返回结果的数量。
- 如果您想查看所有有权访问 A 但无权访问 B 的用户,您可以相应地替换子 select 的
WHERE NOT IN
子句。
我不知道 SQLServer 是如何处理优化的,但我看到系统发现用 = X
和 [=17 替换 IN (X)
和 NOT IN (X)
可以获得性能提升=]分别。
编辑 1 - 关于 WHERE 子句的一般思考
根据一般经验,在计算响应时考虑是否需要参考不在生成行范围内的其他行总是好的。如果你这样做了(在这种情况下,该行必须存在,而其他行不存在相同的 USER_ID
),这通常表明你需要引入某种连接来消除你的结果不想。
我如何才能 select 只有不同的用户 ID 仅具有 ACCESS_COLUMN_ID 值 1,即使它们也可能具有 ACCESS_COLUMN_ID 值 2。
这是我的查询 returns 1 和 2:
SELECT DISTINCT(USER_ID) FROM USER_ACCESS WHERE ACCESS_COLUMN_ID = 1
返回的结果中也包含有ACCESS_COLUMN_ID = 2
的userid。
Here is my table data
USERID ACCESS_COLUMN_ID
1 1
1 2
2 1
我只希望 USERID 2 作为我的查询结果
你可以使用 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
,如果这两个值都是1,那么user_id
会保留在最终结果集中。
上面的代码会有很好的性能,因为它只引用了一次table。
为了您的兴趣,还有其他几种方法可以获得相同的结果。但是,它们都需要 table 被引用两次。您可能想自己比较它们的可读性和性能:
不存在
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)
不在
这与上一个非常相似,但根据我的经验,性能不如上一个:
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
)。
除外
这是SQL服务器特有的语法,但是很容易理解(Oracle有类似的MINUS
);
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_ID
不可能有两条记录具有相同的值,则可以在上述查询中省略DISTINCT
关键字。
可以用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
)
您可以通过多种方式完成此任务。这可能是最灵活的。
获取具有所需访问 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;
几个要点:
- 查询可能受益于子select table
u2
可能是DISTINCT
。这取决于返回结果的数量。 - 如果您想查看所有有权访问 A 但无权访问 B 的用户,您可以相应地替换子 select 的
WHERE NOT IN
子句。
我不知道 SQLServer 是如何处理优化的,但我看到系统发现用 = X
和 [=17 替换 IN (X)
和 NOT IN (X)
可以获得性能提升=]分别。
编辑 1 - 关于 WHERE 子句的一般思考
根据一般经验,在计算响应时考虑是否需要参考不在生成行范围内的其他行总是好的。如果你这样做了(在这种情况下,该行必须存在,而其他行不存在相同的 USER_ID
),这通常表明你需要引入某种连接来消除你的结果不想。