【问题标题】:How to get single row of values based on value of another column?如何根据另一列的值获取单行值?
【发布时间】:2018-06-10 13:30:20
【问题描述】:

我正在尝试根据name 列中的值从value 列中选择值。

例如:

mysql> select name, value from rss_feed_property_value where rss_feed_id = 31;
+-------------+---------------+
| name        | value         |
+-------------+---------------+
| High        | 45            |
| Description | Rain And Snow |
| Low         | 25            |
| Day         | Fri           |
| Date        | 29 Dec 2017   |
+-------------+---------------+
5 rows in set (0.00 sec)

我几乎通过以下查询实现了这一点:

select

  if (rfpv.name = 'Date', rfpv.value, null) as `Date`,
  if (rfpv.name = 'High', rfpv.value, null) as `High`,
  if (rfpv.name = 'Low', rfpv.value, null) as `Low`,
  if (rfpv.name = 'Description', rfpv.value, null) as `Description`

from rss_feed rf
join rss_feed_definition rfd on rf.rss_feed_definition_id = rfd.id
join rss_feed_property_value rfpv on rfpv.rss_feed_id = rf.id

where rfd.type = 'weather'
and rf.id = 31
order by rf.id;

产生以下输出:

+-------------+------+------+---------------+
| Date        | High | Low  | Description   |
+-------------+------+------+---------------+
| NULL        | 45   | NULL | NULL          |
| NULL        | NULL | NULL | Rain And Snow |
| NULL        | NULL | 25   | NULL          |
| NULL        | NULL | NULL | NULL          |
| 29 Dec 2017 | NULL | NULL | NULL          |
+-------------+------+------+---------------+
5 rows in set (0.00 sec)

我现在如何通过忽略 null 值以仅保留一行来展平上述内容,如下所示:

+-------------+------+------+---------------+
| Date        | High | Low  | Description   |
+-------------+------+------+---------------+
| 29 Dec 2017 | 45   | 25   | Rain and Snow |
+-------------+------+------+---------------+

【问题讨论】:

    标签: mysql sql aggregation


    【解决方案1】:

    rf.id 聚合并使用条件聚合。我会在这里使用CASE 表达式,因为与MySQL 的IF 相比,这种语法在数据库中得到更广泛的支持。

    SELECT
        rf.id,
        MAX(CASE WHEN rfpv.name = 'Date'        THEN rfpv.value END) AS Date,
        MAX(CASE WHEN rfpv.name = 'High'        THEN rfpv.value END) AS High,
        MAX(CASE WHEN rfpv.name = 'Low'         THEN rfpv.value END) AS Low,
        MAX(CASE WHEN rfpv.name = 'Description' THEN rfpv.value END) AS Description
    FROM rss_feed rf
    INNER JOIN rss_feed_definition rfd
        ON rf.rss_feed_definition_id = rfd.id
    INNER JOIN rss_feed_property_value rfpv
        ON rfpv.rss_feed_id = rf.id
    WHERE
       rfd.type = 'weather' AND
       rf.id = 31
    GROUP BY
        rf.id
    ORDER BY
        rf.id;
    

    【讨论】:

      【解决方案2】:

      只需将MAX() 放在您想要折叠在一起的所有内容周围MAX() 忽略NULL 值),然后将GROUP BY 放在您尝试将所有内容折叠到其中的 id 上。 ..

      SELECT
        rf.id,
        MAX(if (rfpv.name = 'Date',        rfpv.value, null))  AS `Date`,
        MAX(if (rfpv.name = 'High',        rfpv.value, null))  AS `High`,
        MAX(if (rfpv.name = 'Low',         rfpv.value, null))  AS `Low`,
        MAX(if (rfpv.name = 'Description', rfpv.value, null))  AS `Description`
      FROM
        rss_feed                   AS rf
      INNER JOIN
        rss_feed_definition        AS rfd
          ON rf.rss_feed_definition_id = rfd.id
      INNER JOIN
        rss_feed_property_value    AS rfpv
          ON rfpv.rss_feed_id = rf.id
      WHERE
            rfd.type = 'weather'
        AND rf.id = 31
      GROUP BY
        rf.id
      ORDER BY
        rf.id
      ;
      

      我将rf.id 字段添加到SELECT 只是为了更清楚地说明正在做什么。 (因此还添加了关联的GROUP BY rf.id

      【讨论】:

        【解决方案3】:

        我通过以下查询实现了这一点:

        select
        
          rf.id as rssFeedId,
        
          (select value
           from rss_feed_property_value
           where name = 'Date'
           and rss_feed_id = rssFeedId) as `Date`,
        
           (select value
           from rss_feed_property_value
           where name = 'High'
           and rss_feed_id = rssFeedId) as `High`,
        
           (select value
           from rss_feed_property_value
           where name = 'Low'
           and rss_feed_id = rssFeedId) as `Low`,
        
           (select value
           from rss_feed_property_value
           where name = 'Description'
           and rss_feed_id = rssFeedId) as `Description`
        
        
        from rss_feed rf
        join rss_feed_definition rfd on rf.rss_feed_definition_id = rfd.id
        join rss_feed_property_value rfpv on rfpv.rss_feed_id = rf.id
        
        where rfd.type = 'weather'
        and rf.id = 31
        
        group by rf.id
        
        order by rf.id;
        

        我不确定这是否是最有效的方法。

        【讨论】:

        • 如果你走这样的路线,你不需要最后一个 JOINrfpv 因为你的相关子查询正在为你做这件事,这反过来意味着你赢了不需要GROUP BY。也就是说,单个 JOINGROUP BY 将比 4 个相关子查询快得多。
        猜你喜欢
        • 2021-12-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-02
        • 2013-05-26
        • 1970-01-01
        • 2021-09-22
        相关资源
        最近更新 更多