I have a users
table
Table "public.users"
Column | Type | Modifiers
--------+---------+-----------
user_id | integer |
style | boolean |
id | integer |
and an access_rights
table
Table "public.access_rights"
Column | Type | Modifiers
--------+---------+-----------
user_id | integer |
id | integer |
I have a query joining users on access right and I want to count the number of values in the style column that are true.
From this answer: postgresql - sql - count of `true` values , I tried doing
SELECT COUNT( CASE WHEN style THEN 1 ELSE null END )
from users
join access_rights on access_rights.user_id = users.user_id
;
But that counts duplicate values when a user has multiple rows for access_rights. How can I count values only once when using a join?
If you are interested in the number of users that have at least 1 row with ( style IS TRUE
) in access_rights
, aggregate access_rights
before you join:
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);
Using JOIN
, since users without any entries in access_rights
don't count in this case.
Using the aggregate function bool_or()
.
Or even simpler:
SELECT count(*) AS style_ct
FROM (
SELECT user_id
FROM access_rights
GROUP BY 1
HAVING bool_or(style)
);
This is assuming a foreign key enforcing referential integrity, so there is no access_rights.user_id
without a corresponding row in users
.
Also assuming no NULL
values in access_rights.user_id
, which would increase the count by 1 - and can be countered by using count(user_id)
instead of count(*)
.
Or (if that assumption is not true) use an EXISTS
semi-join:
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;
I am using the capabilities of true boolean
values to simplify the count and the WHERE
clause. Details:
Compute percents from SUM() in the same SELECT sql query
You could do this:
Try something like this (per the documentation )
select sum( case style when TRUE then 1 else 0 end ) as style_count
from public.users u
join public.access_rights ar on ar.user_id = u.user_id
Or, considering your problem statement, " I want to count the number of values in the style column that are true ", you could do this:
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
Edited To Note:
On re-reading your question, it sounds like what you really want is a count of distinct users whose style
attribute is true
, and who have an access right. You can get to that by this:
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
;
Another way to get there would be like this:
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
)
I would vote for the latter as it more clearly shows your intent.
It seems each one has a different understanding of the question. Here is mine
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
)
It will count the total number of trues for users which have access_rights.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.