I want to count distinct from one column but with 2 different criteria.
I want filter all email does not contain yopmail on count_1
and filter all email does not contain gmail on count_2
.
I've tried this SQL but I have no idea how to filter for count_2
. My code is filtering both count_1
and count_2
.
SELECT "School"."name" AS "School", count(distinct "public"."users"."id") AS "count_1", count(distinct "public"."users"."id") AS "count_2"
FROM "public"."users"
LEFT JOIN "public"."user_roles" "User Roles" ON "public"."users"."id" = "User Roles"."user_id"
LEFT JOIN "public"."roles" "Role" ON "User Roles"."role_id" = "Role"."id"
LEFT JOIN "public"."schools" "School" ON "User Roles"."school_id" = "School"."id"
WHERE ("Role"."name" = 'Student'
AND "public"."users"."deleted_at" IS NULL
AND "public"."users"."activated_at" IS NOT NULL
AND NOT (lower("public"."users"."email") like '%yopmail%'))
GROUP BY "School"."name"
ORDER BY "School"."name" ASC
The result is like this: It's filtering both count
but I want to have different values from count_1
and count_2
.
School | Count_1 | Count_2 |
+------------+-----------+-----------+
| A | 11 | 11 |
| B | 20 | 20 |
| C | 34 | 34 |
+------------+-----------+-----------+
You can achieve that with a filtered aggregation:
SELECT "School"."name" AS "School",
count(distinct "public"."users"."id") AS "count_1",
-- the following only counts users where the email column does not contain the value gmail
count(distinct users.id) filter (where email not like '%gmail%') AS "count_2"
FROM "public"."users"
LEFT JOIN "public"."user_roles" "User Roles" ON "public"."users"."id" = "User Roles"."user_id"
LEFT JOIN "public"."roles" "Role" ON "User Roles"."role_id" = "Role"."id"
LEFT JOIN "public"."schools" "School" ON "User Roles"."school_id" = "School"."id"
WHERE ("Role"."name" = 'Student'
AND "public"."users"."deleted_at" IS NULL
AND "public"."users"."activated_at" IS NOT NULL
AND NOT (lower("public"."users"."email") like '%yopmail%'))
GROUP BY "School"."name"
ORDER BY "School"."name" ASC
The classic method is to use the CASE expression.
SELECT "School"."name" AS "School",
count(distinct CASE WHEN NOT (lower("public"."users"."email") like '%yopmail%') THEN "public"."users"."id" else NULL END) AS "count_1",
count(distinct CASE WHEN NOT (lower("public"."users"."email") like '%gmail%') THEN "public"."users"."id" else NULL END) AS "count_2"
FROM "public"."users"
LEFT JOIN "public"."user_roles" "User Roles" ON "public"."users"."id" = "User Roles"."user_id"
LEFT JOIN "public"."roles" "Role" ON "User Roles"."role_id" = "Role"."id"
LEFT JOIN "public"."schools" "School" ON "User Roles"."school_id" = "School"."id"
WHERE ("Role"."name" = 'Student'
AND "public"."users"."deleted_at" IS NULL
AND "public"."users"."activated_at" IS NOT NULL)
GROUP BY "School"."name"
ORDER BY "School"."name" ASC
If you use filter clause, apply it to count_1 and count_2, and delete the email condition from the WHERE clause.
SELECT "School"."name" AS "School",
count(distinct "public"."users"."id") filter (where NOT (lower("public"."users"."email") like '%yopmail%')) AS "count_1",
count(distinct "public"."users"."id") filter (where NOT (lower("public"."users"."email") like '%gmail%')) AS "count_2"
FROM "public"."users"
LEFT JOIN "public"."user_roles" "User Roles" ON "public"."users"."id" = "User Roles"."user_id"
LEFT JOIN "public"."roles" "Role" ON "User Roles"."role_id" = "Role"."id"
LEFT JOIN "public"."schools" "School" ON "User Roles"."school_id" = "School"."id"
WHERE ("Role"."name" = 'Student'
AND "public"."users"."deleted_at" IS NULL
AND "public"."users"."activated_at" IS NOT NULL)
GROUP BY "School"."name"
ORDER BY "School"."name" ASC
See below: SQL Fiddle
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.