【问题标题】:MySQL: How to query for a column and include information from related columns in the same table?MySQL:如何查询列并包含同一表中相关列的信息?
【发布时间】:2014-02-06 01:19:15
【问题描述】:

在 MySQL 中,我有一个这样的表:

+-----------------------+
|         Assets        |
+-----------------------+
| Id |   Name  | RootId |
+----+---------+--------+
|  1 | Asset A |    1   |
+----+---------+--------+
|  2 | Asset B |    2   |
+----+---------+--------+
|  3 | Asset C |    3   |
+----+---------+--------+
|  4 | Asset D |    2   |
+----+---------+--------+
|  5 | Asset E |    3   |
+----+---------+--------+
|  6 | Asset F |    3   |
+----+---------+--------+

我知道,这不是最棒的表结构……但我现在坚持使用它。

我正在尝试编写一个查询,给定 Id 值,仅当恰好有两 (2) 行具有相同的 RootId 时才会返回 RootIdRootName。否则这些列应该为 NULL。

因此,使用上面的表格,如果给定一个为 4 的 Id,查询应该返回:

+----------------------------------+
|              Assets              |
+----------------------------------+
| Id |   Name  | RootId | RootName |
+----+---------+--------+----------+
|  4 | Asset D |    2   |  AssetB  |
+----+---------+--------+----------+

但如果给定任何其他 Id 值,例如 5,它应该返回:

+----------------------------------+
|              Assets              |
+----------------------------------+
| Id |   Name  | RootId | RootName |
+----+---------+--------+----------+
|  5 | Asset E |  null  |   null   |
+----+---------+--------+----------+

对此的任何帮助将不胜感激。我认为它需要一个带有 COUNT 和可能是 GROUP BY 的子查询,但我真的不确定如何表达它......

提前致谢!

【问题讨论】:

    标签: mysql join count group-by


    【解决方案1】:

    下面应该实现这个逻辑:

    select id, name,
           (case when cnt = 2 then rootid end) as rootid,
           (case when cnt = 2 then ari.name end) as rootname
    from assets a join
         (select rootid, count(*) as cnt
          from assets a
          group by rootid
         ) ri
         on a.rootid = ri.rootid left join
         assets ari
         on a.rootid = ari.id
    where id = 4;
    

    你也可以这样做:

    select a.id, a.name,
           (case when a.cnt = 2 then a.rootid end) as rootid,
           (case when a.cnt = 2 then ari.name end) as rootname
    from (select a.*,
                 (select count(*) from assets a2 where a2.rootid = a.rootid) as cnt
          from assets a
          where id = 4
         ) a left join
         assets ari
         on a.rootid = ari.id;
    

    如果没有完全聚合,这会表现得更好。

    Here 是一个说明它们的 SQL Fiddle。

    【讨论】:

    • +1。第二个对于大型集合应该更有效,因为它避免了实现一个内联视图来获取每个可能的 RootId 值的计数。但是不需要 GROUP BY 吗?在 RootId 上加入 ari 会返回多行,不是吗?
    • @spencer7593 。 . .不,不需要group by。只是正确的加入。 ari 最多只能匹配一个。谢谢。
    • @ShaunScovil 。 . .第二个版本有一个错误,现已修复和测试。
    • 太棒了,谢谢戈登! (以为我在那里疯了一分钟......):-)
    【解决方案2】:

    这样的东西会返回指定的结果集:

    SELECT a.Id
         , a.Name
         , IF(q.cnt=2,q.RootId,NULL) AS RootId
         , IF(q.cnt=2,q.RootName,NULL) AS RootName
      FROM Assets a
      JOIN ( SELECT COUNT(1) AS cnt
                  , r.RootId
                  , r.RootName
               FROM Assets r
               JOIN Assets s
                 ON s.RootId = r.RootId
              WHERE r.Id = 4
              GROUP BY r.RootId, r.RootName
           ) q
        ON q.Id = a.Id
    

    如果 RootId 可能为 NULL,那么您需要使用 LEFT [OUTER] JOIN,并包含 .如果您想将 RootId 的 NULL 值视为与另一个 NULL 值匹配,则将相等比较器替换为 null 安全相等比较运算符 <=>

    添加这两个调整可以提供更强大的解决方案:

    SELECT a.Id
         , a.Name
         , IF(q.cnt=2,q.RootId,NULL) AS RootId
         , IF(q.cnt=2,q.RootName,NULL) AS RootName
      FROM Assets a
      JOIN ( SELECT COUNT(1) AS cnt
                  , r.RootId
                  , r.RootName
               FROM Assets r
               LEFT                                -- lef outer join
               JOIN Assets s
                 ON s.RootId <=> r.RootId          -- nullsafe equality
              WHERE r.Id = 4
              GROUP BY r.RootId, r.RootName
           ) q
        ON q.Id = a.Id
    

    【讨论】:

      猜你喜欢
      • 2019-12-19
      • 1970-01-01
      • 1970-01-01
      • 2017-09-13
      • 2019-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多