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;
我正在使用true
boolean
值的功能来简化计数和
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,您总能给出一些好的答案,我很感激@杰文斯:很高兴听到。:)考虑我添加的更简单的变体。