繁体   English   中英

选择与另一个表相关的行的计数字段

[英]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 ,以避免不必要地选择额外的行。 但是,使用多列需要使用ORUNION ,因此在这种情况下它可能非常均匀。 即:既不是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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM