在 MySQL 中加入表的转置
Posted
技术标签:
【中文标题】在 MySQL 中加入表的转置【英文标题】:Join with a transpose of a table in MySQL 【发布时间】:2020-09-23 18:15:21 【问题描述】:标题不太公平,但这是我的表结构
users table
+---------+
| user_id |
+---------+
| 1 |
| 2 |
| 3 |
+---------+
kids table
+----------+---------+------------+
| child_id | user_id | child_name |
+----------+---------+------------+
| 1 | 1 | child_a |
| 2 | 1 | child_b |
| 3 | 2 | child_c |
| 4 | 3 | child_x |
| 5 | 3 | child_y |
| 6 | 3 | child_z |
+----------+---------+------------+
现在我想转置kids
表并将其与users
表连接。
预期输出。
+---------+---------+---------+---------+
| user_id | child_1 | child_2 | child_3 |
+---------+---------+---------+---------+
| 1 | child_a | child_b | |
| 2 | child_c | | |
| 3 | child_x | child_y | child_z |
+---------+---------+---------+---------+
如您所见,有 3 列子信息,因为用户的最大子数为 3。
到目前为止,我能做的如下,但我将不得不使用其他一些语言来重新格式化这些数据。
select user_id, group_concat(child_name) from kids group by user_id;
知道我可以在 mysql 中获取预期结果吗?
编辑:我知道每个用户最多有 3 个孩子。
【问题讨论】:
主要是您不知道需要创建多少列来容纳所有子项。而不是这个使用group_concat
和 GROUP BY
子句。
如您所见,我的问题完全一样。
请看meta.***.com/questions/333952/…
【参考方案1】:
您的意思是旋转,不需要users
表,可以尝试以下方法,其中包括GROUP_CONCAT()
函数,通过使用诸如ROW_NUMBER()
之类的解析函数来动态执行:
SET @sql = NULL;
SELECT GROUP_CONCAT(
DISTINCT
CONCAT(
'MAX(CASE WHEN rn =', rn,
' THEN child_name END) AS child_',rn
)
)
INTO @sql
FROM
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY child_id) AS rn
FROM kids
) k;
SET @sql = CONCAT('SELECT user_id,',@sql,
' FROM
(
SELECT *,
ROW_NUMBER() OVER
(PARTITION BY user_id ORDER BY child_id) AS rn
FROM kids
) k
GROUP BY user_id');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Demo
【讨论】:
【参考方案2】:@Shobi 我相信你可以通过多次加入kids
到users
来做到这一点,这应该会给你孩子的名字,就像这样:
SELECT `u`.`user_id`,
`k`.`child_name` AS `child_1`,
`k2`.`child_name` AS `child_2`,
`k3`.`child_name` AS `child_3`
FROM `users` AS `u`
LEFT JOIN `kids` AS `k` ON `k`.`user_id` = `u`.`user_id`
LEFT JOIN `kids` AS `k2` ON `k2`.`user_id` = `u`.`user_id`
AND `k2`.`child_id` <> `k`.`child_id`
LEFT JOIN `kids` AS `k3` ON `k3`.`user_id` = `u`.`user_id`
AND `k3`.`child_id` <> `k2`.`child_id`
AND `k3`.`child_id` <> `k`.`child_id`
GROUP BY `u`.`user_id`
Here is a working example on sqlfiddle.
注意:上述查询适用于 MySQL = 5.7 中获得相同的结果,您可以使用包含 ANY_VALUE()
的查询版本,它被列为适当的使用 here in the MySQL documentation.
SELECT `u`.`user_id`,
ANY_VALUE(`k`.`child_name`) AS `child_1`,
ANY_VALUE(`k2`.`child_name`) AS `child_2`,
ANY_VALUE(`k3`.`child_name`) AS `child_3`
FROM `users` AS `u`
LEFT JOIN `kids` AS `k` ON `k`.`user_id` = `u`.`user_id`
LEFT JOIN `kids` AS `k2` ON `k2`.`user_id` = `u`.`user_id`
AND `k2`.`child_id` <> `k`.`child_id`
LEFT JOIN `kids` AS `k3` ON `k3`.`user_id` = `u`.`user_id`
AND `k3`.`child_id` <> `k2`.`child_id`
AND `k3`.`child_id` <> `k`.`child_id`
GROUP BY `u`.`user_id`
ORDER BY `u`.`user_id`
Here is a working example of this other version of the query in db-fiddle.
【讨论】:
这在没有 group by 的情况下确实有效,我使用的是 mysql 8 以上是合适的解决方案的sql没有问题:-( @Strawberry 您能否详细说明为什么您说我的解决方案不起作用?我愿意接受我的查询不起作用的可能性,但是查看 OP 的预期结果集和我的查询返回的结果集,它们是相同的。此外,OP 表示我的查询做了他想要的。我只是对为什么我的查询返回 OP 请求的结果集感到困惑,但你说它没有。 在没有任何聚合函数的情况下,GROUP BY 子句永远不合适以上是关于在 MySQL 中加入表的转置的主要内容,如果未能解决你的问题,请参考以下文章