[英]Select count field of rows that are related to another table
我很长一段时间都在努力解决这个问题,不知道如何解决它。 我很难描述,所以请耐心等待。 有两个表:
表“用户”
UserId PK
Gender
表“表格”
FormId PK
UserId1 FK
UserId2 FK
Type
表单始终与两个用户相关,但并非所有用户都有相关表单。 现在我想只计算具有相关表单的用户的指定性别。
所以结果,我想要...... 像这样:
# | Gender | GenderCount
1 | male | 43
2 | female | 12
3 | trans | 2
我尝试了以下SQL脚本,但结果并不明显(所有GenderCount的总和大于实际用户数)
SELECT u.Gender AS 'Gender', COUNT(u.Gender) AS 'GenderCount'
FROM Users u, Forms f
WHERE ((f.UserId1 = u.UserId)
OR (f.UserId2 = u.UserId))
AND (Type = 'Foo')
GROUP BY Gender
ORDER BY GenderCount
DESC
解决这个问题的任何提示?
我们来看看你想要的东西:
像这样的短语,答案变得相当明显,至少在伪代码中:
SELECT
u.Gender,
COUNT(u.Gender)
FROM
Users u
WHERE
[User has answered a form]
GROUP BY
u.Gender
确定用户是否已回答表单的最简单方法取决于所使用的SQL的特定风格。 您需要使用子查询。 如何访问它有几个选项。
IN
是最常用的方法:
SELECT
u.Gender Gender,
COUNT(u.Gender) GenderCount
FROM
Users u
WHERE
u.id IN (
SELECT f.UserId1 user_id FROM Forms f WHERE Type = 'Foo'
UNION
SELECT f.UserId2 user_id FROM Forms f WHERE Type = 'Foo'
)
GROUP BY
Gender
ORDER BY
GenderCount DESC
在可用的情况下, EXISTS
阅读更自然,有时更快:
SELECT
u.Gender Gender,
COUNT(u.Gender) GenderCount
FROM
Users u
WHERE
EXISTS(
SELECT '1'
FROM Forms f
WHERE
(f.UserId1 = u.id OR f.UserId2 = u.id)
AND Type = 'Foo'
)
GROUP BY
Gender
ORDER BY
GenderCount DESC
关于速度:查询优化器通常会在可能的情况下将IN
转换为EXISTS
,以避免不必要地选择额外的行。 但是,使用多列需要使用OR
或UNION
,因此在这种情况下它可能非常均匀。 即:既不是OR
也不是UNION
与索引很好地配合。
跳过为每个用户生成多行的联接:
SELECT Gender, COUNT(Gender) AS 'GenderCount'
FROM Users
WHERE UserId IN (SELECT UserId1 FROM Forms WHERE Type = 'Foo'
UNION
SELECT UserId2 FROM Forms WHERE Type = 'Foo')
GROUP BY Gender
ORDER BY GenderCount DESC
或者如果你想避免使用UNION(在这种情况下BTW完全有效),你可以像这样使用OR:
SELECT Gender, COUNT(Gender) AS 'GenderCount'
FROM Users
WHERE UserId IN (SELECT UserId1 FROM Forms WHERE Type = 'Foo')
OR UserId IN (SELECT UserId2 FROM Forms WHERE Type = 'Foo')
GROUP BY Gender
ORDER BY GenderCount DESC
正如其他人所指出的那样,有很多方法可以使用JOIN来实现。 但是,JOIN会为DBMS引擎增加不必要的复杂性,因为它首先需要匹配行,然后减少到DISTINCT值。
SELECT u1.Gender AS 'Gender', COUNT(*) AS 'GenderCount'
FROM
Users u1
INNER JOIN
(SELECT DISTINCT u.UserId
FROM
Users u
INNER JOIN Forms f ON ((f.UserId1 = u.UserId)
OR (f.UserId2 = u.UserId))
AND (f.Type = 'Foo')) T ON T.UserId = u1.UserId
GROUP BY Gender
ORDER BY GenderCount DESC
你应该用
count(distinct u.UserId)
这样,用户只会被计算一次:count(distinct field_name)计算field_name中包含的唯一值的数量,因此在主键上计算distinct将为您提供唯一用户的数量,这正是您要查找的内容。
另外,使用像这样的in子句可能会更好,而不是加入
select Gender, count(distinct UserId) as GenderCount
from Users
where u.UserId in (select UserId1 from Forms) or u.UserId in (select UserId2 from Forms)
它可能也会稍快一些。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.