MYSQL 如果父字段不为空则分组

MYSQL Group if parent field is not empty

如果父级不为空,是否可以将行分组在一起

我先解释一下数据库:

-----------------------------------------------------
ID    |    NAME    |       date       |    PARENT ID
-----------------------------------------------------
1    | John Doe   |    2018-01-12    |
2    | Doe John   |    2018-01-12    |    
3    | Doe John   |    2018-02-12    |        2
4    | Doe John   |    2018-03-22    |        2

现在我想要的是得到这样的列表:

--------------------------------------------------------------
ID    |    NAME    |           date          |    PARENT ID
-------------------------------------------------------------
1    | John Doe    |       2018-01-12        |
2    | Doe John    | 2018-01-12 / 2018-03-22 |    

我尝试过类似的东西:

SELECT *, CONCAT(parentID)
FROM names
GROUP BY parentID;

但是结果只有那些有 parentID 的,我想显示那些没有 parentID 的,并将那些有 parentID 的分组到 ID

当 parentID 为空时,您可以使用基于 ifnull 的分组依据使用 ID

SELECT *, CONCAT(parentID)
FROM names
GROUP BY ifnull(parentID, ID);

试试这个:

SELECT MAX(dates.id), MAX(dates.name), MAX(dates.date), MAX(a.date)
FROM dates
LEFT JOIN dates a ON a.parentID = dates.id
WHERE dates.parentID IS NULL GROUP BY a.parentID;

您遇到的问题是您需要一种方法来连接具有与行 ID 对应的 parentID 的行中的数据。使用此查询,我们过滤行以仅显示没有 parentID 的行,然后获取 parentID 等于当前行 ID 的所有行。使用 max 可确保正确使用 group by 并显示您的示例中似乎要求的内容。

诀窍是使用 LEFT JOIN 加入到 table 本身,使用初始 table 作为 parents 和加入的 table 作为child仁.

SELECT
    *
FROM
  users as parents
  LEFT JOIN users as children ON parents.id = children.parent_id

A LEFT JOIN 将保留初始 table 中的所有行(在本例中为 parents)并仅添加行加入 table (children 在这种情况下)到它,如果加入是可能的。否则只会添加 NULL 个值。

| id |   name     |    date    | parent_id |   id   |    name     |    date    | parent_id |
|  2 |  Doe John  | 2018-01-12 |   (null)  |    3   |   Bill John | 2018-02-12 |     2     |
|  2 |  Doe John  | 2018-01-12 |   (null)  |    4   |   Elmo John | 2018-03-22 |     2     |
|  1 |  John Doe  | 2018-01-12 |   (null)  | (null) |    (null)   |   (null)   |   (null)  |
|  3 |  Bill John | 2018-02-12 |     2     | (null) |    (null)   |   (null)   |   (null)  |
|  4 |  Elmo John | 2018-03-22 |     2     | (null) |    (null)   |   (null)   |   (null)  |

如果这样做了,每个 parent 没有 children 就只有一行每个 parentchild 的行数与 children 一样多 因为 parent 存在。

因此,可以使用 parents.id 列上的 GROUP BY,因为 parent 对每个 child 具有相同的 parent 并且每个 parent[=66 存在一行=] 没有 children。要从 parents 中筛选那些 children 而不是 parents 的人,WHERE 子句 parents.parent_id IS NULL 可以加。

SELECT
    parents.id
FROM
  users as parents
  LEFT JOIN users as children ON parents.id = children.parent_id
WHERE
  parents.parent_id IS NULL
GROUP BY
  parents.id

要获得所需的 date,您必须使用聚合函数 MIN() and MAX() 来计算日期间隔的开始和结束日期。

函数COALESCE() is necessary, because you might have NULL values due to the LEFT JOIN. It will output the first provided parameter, that is not NULL. In this example, the result of CONCAT is NULL, if children.date and therefore MIN(children.date) and therefore LEAST(...)returnsNULL。在这种情况下,将使用第二个值 paprents.id

SELECT
  parents.id,
  parents.name,
  COALESCE(
    CONCAT(
      LEAST(parents.date, MIN(children.date)), 
      ' / ', 
      GREATEST(parents.date, MAX(children.date))
    ), 
    parents.date
  ) as 'date'
FROM
  users as parents
  LEFT JOIN users as children ON parents.id = children.parent_id
WHERE
  parents.parent_id IS NULL
GROUP BY
  parents.id,
  parents.name, -- Just added for output without aggregation
  parents.date -- Just added for output without aggregation

Running example on sqlfiddle.com