我尝试做两个查询,在我看来它应该给我相同的结果,但没有
SELECT count(1)
FROM users
WHERE users.id NOT IN (
SELECT user_id as id
FROM users_roles as ur
WHERE
ur.role_id = 10
OR ur.role_id = 12
)
我有结果:
count
-------
0
(1 row)
第二次将NOT IN
更改为IN
并将其换行到外NOT IN
SELECT count(1)
FROM users
WHERE id NOT IN (
SELECT users.id
FROM users
WHERE users.id IN (
SELECT user_id as id
FROM users_roles as ur
WHERE
ur.role_id = 10
OR ur.role_id = 12
)
)
结果
count
---------
3150136
(1 row)
第一次查询有什么问题?
第二次查询的更多细节:
SELECT count(1)
FROM users
WHERE users.id IN (
SELECT user_id as id
FROM users_roles as ur
WHERE
ur.role_id = 10
OR ur.role_id = 12
)
count
-------
40320
(1 row)
和
select count(1) from users;
count
---------
3190466
按用户查询编辑:
database=# \d users_roles
Table "public.users_roles"
Column | Type | Modifiers
----------+---------+----------------------------------------------------------
user_id | integer |
role_id | integer |
track_id | integer |
id | integer | not null default nextval('users_roles_id_seq'::regclass)
Indexes:
"users_roles_pkey" PRIMARY KEY, btree (id)
"uniq_users_roles" UNIQUE CONSTRAINT, btree (user_id, role_id)
"uq_users_roles_role_track" UNIQUE CONSTRAINT, btree (role_id, track_id)
Foreign-key constraints:
"fk_roles_track_id" FOREIGN KEY (track_id) REFERENCES tracks(id)
"fk_users_roles_roles" FOREIGN KEY (role_id) REFERENCES roles(id)
"fk_users_roles_users" FOREIGN KEY (user_id) REFERENCES users(id)
并选择
SELECT Count(user_id) as totalusers FROM users_roles as ur WHERE ur.role_id = 10 OR ur.role_id = 12;
totalusers
------------
40320
P.S。
database=# select version();
version
--------------------------------------------------------------------------------------------------------------
PostgreSQL 9.4.14 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4, 64-bit
答案 0 :(得分:4)
这可能是因为user_roles
= user_id
或role_id
= 10
时,表格role_id
可能为12
。
第一个查询变为:
SELECT COUNT(1)
FROM users
WHERE users.id NOT IN (id1, id2, id3, NULL, id4, NULL, id5,...)
这里给定的users.id
将与列表中的所有值进行比较,并且只有当它不等于上面列表中的任何id值时,它才有资格显示在输出中。
如果列表中存在NULL值,NOT IN
会将给定users.id
的条件评估为[users.id
<> id1
和users.id
<> id2
AND ... users.id
<> NULL
和users.id
<> id5
]你期望的是真的但是SQL将其视为FALSE,因为它将users.id
<> NULL
评估为FALSE,因此将整个表达式评估为FALSE并从结果中排除users.id
。这发生在users.id
表中的所有其他users
,这就是输出中有0个条目的原因。
仅供参考:id
= NULL
=> UNKNOWN以及id
<> NULL
=> UNKNOWN其中UNKNOWN既不是TRUE也不是FALSE(但是在你的问题的背景下,你仍然可以说not TRUE
当你期望它是TRUE
)因为NULL
实际上是“未知”没有任何价值。
为避免这种情况,您可以从内部列表中删除NULL,如下所示:
SELECT count(1)
FROM users
WHERE users.id NOT IN (
SELECT user_id as id
FROM users_roles as ur
WHERE
(ur.role_id = 10 OR ur.role_id = 12) AND ur.user_id IS NOT NULL
)
这是NOT IN
。
但是,使用IN
时不会遇到此问题,因为如果列表中存在匹配的非NULL users.id
,则它将包含在输出中这就是为什么你在另一个查询中得到40,320条记录的原因。