【问题标题】:PostgreSQL - How to find the row with a record that matches it with a value higher than given value?PostgreSQL - 如何找到记录与它匹配的值高于给定值的行?
【发布时间】:2020-12-02 22:11:04
【问题描述】:

假设我有两个具有一对多关系的表。

表 A(用户): 标识 INT, 名称文本

表 B(技能): 标识 INT, user_id INT, 技能名称文本, 技能等级INT

每个用户可能拥有多种技能。而现在我想把有一定技能的用户聚集到一定的水平,也许是所有技能都符合条件的用户。

例如,假设我的数据库中有以下数据:

用户:

id | name 
1  | Merlin
2  | Morgan

技能:

id | user_id | skill_name    | skill_level 
1  | 1       | Fireball      | 2 
2  | 1       | Thunderbolt   | 3 
2  | 2       | Thunderbolt   | 2 
2  | 2       | Firestorm     | 1 
2  | 2       | Curse         | 3 

如果我搜索雷电2级或以上的用户,我应该得到梅林和摩根;如果我搜索既懂雷电1级以上又懂诅咒2级以上的用户,那么应该只有摩根出现。

另外,我希望结果还可以包含用户拥有的所有技能的内容。现在我正在使用 ARRAY_AGG(JSON_BUILD_OBJECT('skill_name', skill_name, 'skill_level', skill_level') 按用户 id 收集所有技能。但我不知道如何根据我掌握的技能过滤数据。

【问题讨论】:

    标签: sql json postgresql inner-join having-clause


    【解决方案1】:

    一种方法使用聚合和having 子句来过滤技能名称和级别。布尔聚合函数在这里派上用场:

    select u.*, 
        jsonb_agg(jsonb_build_object('skill_name', skill_name, 'skill_level', skill_level)) as skills
    from users u
    inner join skills s on s.user_id = u.id
    group by u.id
    having bool_or(s.skill_name = 'Thunderbolt' and s.skill_level >= 1)
       and bool_or(s.skill_name = 'Curse'       and s.skill_level >= 2)
    

    这还会在结果集中添加一个名为skills 的列,这是一个 JSONB 数组,其中包含每个技能名称和级别的一个对象,如您的问题中所要求的:请注意,生成 JSON(B ) 数组而不是 JSON 对象的数组,正如您最初的意图。

    【讨论】:

      【解决方案2】:

      一种方法使用聚合。对于一项技能:

      select user_id
      from skills
      group by user_id
      having count(*) filter (where skill_name = 'thunderbold' and skill_level >= 2) > 0;
      

      而对于多个技能,只需添加更多子句:

      select user_id
      from skills
      group by user_id
      having count(*) filter (where skill_name = 'thunderbold' and skill_level >= 1) > 0 and
             count(*) filter (where skill_name = 'curse' and skill_level >= 2) > 0 ;
      

      这将返回user_id。您可以加入回用户表以获取名称。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-02-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-03
        • 1970-01-01
        • 2015-03-17
        相关资源
        最近更新 更多