【问题标题】:Count for all values of enum in PostgreSQL计算 PostgreSQL 中枚举的所有值
【发布时间】:2018-12-27 11:23:19
【问题描述】:

我有一个名为users 的表,其中包含以下列:

id: INT NOT NULL
face: face_type

face_type 是一个 ENUM 类型,具有以下值:'square''round''triangle'

我还有另一个名为houses 的表,其中包含以下列:

id: INT NOT NULL
user_id: INT NOT NULL

现在,我想按不同类型的面孔类型对所有房屋进行分组。所以,我到目前为止是这样的:

SELECT users.face_type, COUNT(*)
FROM users
LEFT JOIN houses ON houses.user_id = users.id
GROUP BY users.face_type

问题是我还想获取face_type 的行,这些行没有用户拥有,以及 NULL face_type 的结果。因此,例如,如果我有以下数据:

users (id, face_type)

1, 'round'
2, 'triangle'

houses (id, user_id)
1, 1
2, 1
3, 2

我希望结果是:

face_type, count
'round'          2
'triangle'       1
'square'         0
null             0

我知道如何获得face_type ENUM 的所有潜在值,方法是:

SELECT unnest(enum_range(NULL::face_type)) AS face_types;

但我不知道如何使用它来计算聚合中的所有潜在人脸类型,以及计算 NULL 人脸类型。

【问题讨论】:

    标签: sql postgresql enums group-by count


    【解决方案1】:

    你可以使用LEFT JOIN:

    SELECT ft.face_type, COUNT(h.user_id)
    FROM (SELECT unnest(enum_range(NULL::face_type)) AS face_types
         ) ft LEFT JOIN
         users u
         ON u.face_type = ft.face_type LEFT JOIN
         houses h
         ON h.user_id = u.id
    GROUP BY ft.face_type;
    

    要获取NULL,只需使用UNION ALL

    SELECT ft.face_type, COUNT(h.user_id)
    FROM (SELECT unnest(enum_range(NULL::face_type)) AS face_types
          UNION ALL
          SELECT NULL
         ) ft LEFT JOIN
         users u
         ON u.face_type = ft.face_type LEFT JOIN
         houses h
         ON h.user_id = u.id
    GROUP BY ft.face_type;
    

    当然,= 不会每次都匹配。如果可能的话,那么您想将JOIN 条件更改为u.face_type is not distinct from ft.face_type

    【讨论】:

    • 这不会包括'null' face_type 的行。如中,NULL 不是 ENUM 的一部分,但我希望有一个对没有 face_type 的用户计数的行(如果所有用户都有 face_type 我仍然希望 NULL 行存在,说明用户有no face_type 没有房子)。
    • 有没有办法在enum_range(NULL::face_type)中添加/附加NULL?
    • 'the = will not every match'是什么意思?
    • 这没有按预期工作。不计算 face_type 为 NULL 的用户。
    【解决方案2】:

    到 COUNT(houses.*)

    SELECT face_type.type, COUNT(houses.*)
    FROM (SELECT unnest(enum_range(NULL::face_type))) AS face_type(type)
    FULL JOIN users ON users.face_type=face_type.type
    LEFT JOIN houses ON houses.user_id = users.id
    GROUP BY face_type.type
    

    【讨论】:

    • 为什么是 COALESCE?
    【解决方案3】:

    ENUM 开始并转到usershousesLEFT JOIN 将允许您恢复每个枚举值的总计。要同时显示NULL 面类型,您可以使用UNION 查询。

    SELECT 
        ft.face_type,
        COUNT(ho.user_id) as cnt
    FROM 
        (SELECT unnest(enum_range(NULL::face_type)) AS face_types) ft
        LEFT JOIN users us ON us.face_type = ft.fact_type
        LEFT JOIN houses ho ON ho.user_id = us.id
    GROUP BY ft.face_type
    UNION
    SELECT
        null,
        COUNT(ho.user_id)
    FROM houses ho
    INNER JOIN users us ON ho.user_id = us.id AND us.face_type IS NULL
    ORDER BY cnt desc
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-02
      • 2010-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多