SQL计算联接表上的唯一真值
我有一个SQL计算联接表上的唯一真值,sql,postgresql,join,count,aggregate-functions,Sql,Postgresql,Join,Count,Aggregate Functions,我有一个users表 Table "public.users" Column | Type | Modifiers --------+---------+----------- user_id | integer | style | boolean | id | integer | Table "public.access_rights" Column | Type | Modifiers --------+---------+----------- u
users
表
Table "public.users"
Column | Type | Modifiers
--------+---------+-----------
user_id | integer |
style | boolean |
id | integer |
Table "public.access_rights"
Column | Type | Modifiers
--------+---------+-----------
user_id | integer |
id | integer |
和一个访问权限
表
Table "public.users"
Column | Type | Modifiers
--------+---------+-----------
user_id | integer |
style | boolean |
id | integer |
Table "public.access_rights"
Column | Type | Modifiers
--------+---------+-----------
user_id | integer |
id | integer |
我有一个连接访问权限上的用户的查询,我想计算样式列中为true的值的数量
从这个答案:,我试着做
SELECT COUNT( CASE WHEN style THEN 1 ELSE null END )
from users
join access_rights on access_rights.user_id = users.user_id
;
但当一个用户有多行访问权限时,这会计算重复值。使用联接时,如何仅计算一次值?如果您对在
access\u rights
中至少有一行(style IS TRUE
)的用户数感兴趣,请在联接之前聚合access\u rights
:
SELECT count(style OR NULL) AS style_ct
FROM users
JOIN (
SELECT user_id, bool_or(style) AS style
FROM access_rights
GROUP BY 1
) u USING (user_id);
使用加入
,因为在访问权限
中没有任何条目的用户在此情况下不计算在内。使用聚合函数 或更简单:
SELECT count(*) AS style_ct
FROM (
SELECT user_id
FROM access_rights
GROUP BY 1
HAVING bool_or(style)
);
这是假设外键强制引用完整性,因此没有访问权限。用户id
在用户
中没有相应的行还假设
access\u rights.user\u id
中没有NULL
值,这将使计数增加1-并且可以使用count(user\u id)
而不是count(*)
进行计数
或(如果该假设不成立)使用一个存在的
半联接:
SELECT count( EXISTS (
SELECT 1
FROM access_rights
WHERE user_id = u.user_id
AND style -- boolean value evaluates on its own
) OR NULL
)
FROM users u;
我正在使用trueboolean
值的功能来简化计数和WHERE
子句。详细信息:您可以这样做:
select count(*) as style_count
from public.users u
join public.access_rights ar on ar.user_id = u.user_id
where u.style = TRUE
试试这样的(per)
或者,考虑到您的问题陈述,“我想计算样式列中为真的值的数量”,您可以这样做:
select count(*) as style_count
from public.users u
join public.access_rights ar on ar.user_id = u.user_id
where u.style = TRUE
编辑为注释:
在重读您的问题时,听起来您真正想要的是一个不同的用户计数,这些用户的style
属性为true
,并且具有访问权限。您可以通过以下方式实现:
select count(distinct u.user_id)
from public.users u
join public.access_rights ar on ar.user_id = u.user_id
where u.style = TRUE
;
另一种方法是:
select count(*)
from public.users u
where u.style = TRUE
and exists ( select *
from public.access_rights ar
where ar.user_id = u.user_id
)
我会投后者的票,因为这更清楚地表明了你的意图。似乎每个人对这个问题都有不同的理解。这是我的
select
count(case when style then 1 end) as classic_case,
count(style or null) as boolean_count
from users u
where exists (
select 1
from access_rights
where user_id = u.user_id
)
它将计算具有访问权限的用户的True总数。为什么不先按值筛选,然后计算行数?您需要将where子句添加到查询
中,其中style=1或NULL
,该子句将只返回style值等于true的行,然后您可以计算行数。如果您在用户中有两条记录的user\u id=1,style=true,在访问权限中有三条记录的user\u id=1,你希望返回什么?1、2、3或6?这是一个精心设计的示例,但用户id列可以被视为主键,因此不会发生这种情况。Hanks Erwin,您总能给出一些好的答案,我很感激@杰文斯:很高兴听到。:)考虑我添加的更简单的变体。