如何解决MySQL:将单行结果放在单独的列中
我使用的是MySQL 5.7.31版,但在需要时仅安装了MySQL服务器8版
我有一个表,其中包含有关实体的一系列信息,例如:
+------+-----+
| Name | Age |
+------+-----+
| Bob | 22 |
| Jack | 15 |
| Jane | 25 |
+------+-----+
在另一个表格中,我获得了有关哪些技能属于姓名和年龄的组合的信息,如下所示:
+-------------+------+-----+
| Skill | Name | Age |
+-------------+------+-----+
| programming | Bob | 22 |
| programming | Jane | 25 |
| marketing | Jane | 25 |
+-------------+------+-----+
这使我能够选择25岁的简的所有技能-返回2行。但是,我需要在如下所示的最终视图中将这些实体分别放入每个实体的列中,而我正在努力弄清楚如何做到这一点。当我在上面显示的表格中获得其他行时,该视图应继续工作
+------+-----+-------------+-----------+--------+
| Name | Age | skill1 | skill2 | skill3 |
+------+-----+-------------+-----------+--------+
| Bob | 22 | programming | Na | Na |
| Jack | 15 | Na | Na | Na |
| Jane | 25 | programming | marketing | Na |
+------+-----+-------------+-----------+--------+
解决方法
您可以使用row_number()
和条件聚合。假设这些表分别称为persons
和person_skills
:
select p.name,p.age,max(case when ps.rn = 1 then ps.skill end) skill1,max(case when ps.rn = 2 then ps.skill end) skill2,max(case when ps.rn = 3 then ps.skill end) skill3
from persons p
left join (
select ps.*,row_number() over(partition by name,age order by id) rn
from person_skills ps
) ps on ps.name = p.name and ps.age = p.age
group by p.name,p.age
目前尚不清楚您希望将哪种技能分布到各个列上。假设您有一个名为id
的排序列,可用于此目的。
如果要在MySQL 5.7的单独列中使用它们,则可能最简单的方法是关联子查询:
select p.*,(select ps.skill
from person_skills ps
where ps.name = p.name and ps.age = p.age
order by ps.skill
limit 1 offset 0
) as skill_1,(select ps.skill
from person_skills ps
where ps.name = p.name and ps.age = p.age
order by ps.skill
limit 1 offset 1
) as skill_2,(select ps.skill
from person_skills ps
where ps.name = p.name and ps.age = p.age
order by ps.skill
limit 1 offset 2
) as skill_3
from persons p;
这看起来很复杂,但是除了offset
之外,这三个子查询都是相同的。
注意:如果没有可用的技能,它将返回NULL
而不是'NA'
。这是表示不可用值的典型方法。
如果您确实需要'NA'
,则可以使用COALESCE()
:
coalesce( (select ps.skill
from person_skills ps
where ps.name = p.name and ps.age = p.age
order by ps.skill
limit 1 offset 0
),'NA') as skill_1,
较早版本中的另一种替代方法是使用group_concat()
进行黑客攻击:
select p.name,substring_index(group_concat(ps.skill order by ps.skill),',1) as skill_1,substring_index(substring_index(group_concat(ps.skill order by ps.skill),2),-1) as skill_2,3),-1) as skill_3
from persons p left join
person_skills ps
on ps.name = p.name and ps.age = p.age
group by p.name,p.age;
这会将所有技能聚合到一个字符串中,然后提取 nth 元素。
对于'NA'
,您将像上面一样使用COALESCE()
。
您可以使用GROUP_CONCAT聚合函数来获取逗号分隔的技能列表:
select
Users.Name,Users.Age,GROUP_CONCAT(Skill) AS Skills
from Users
left join Skills on Skills.Name = Users.Name
group by Users.Name,Users.Age
;
这里是小提琴SQLize.online
结果
Name Age Skills
Bob 22 programming
Jack 15 NULL
Jane 25 programming,marketing
如果技能计数有限,可以使用下一个查询:
select
Users.Name,GROUP_CONCAT(if(Skill='programming','programming',NULL)) AS Skill1,GROUP_CONCAT(if(Skill='marketing','marketing',NULL)) AS Skill2
from Users
left join Skills on Skills.Name = Users.Name
group by Users.Name,Users.Age
;
提琴here
,好的,您在这里做的基本上是错误的,这不是您应该如何对待关系数据库的方法,这是一种边缘性的滥用。
关系数据库第101课,始终使用索引自动递增的主键。总是! (很抱歉,但要使用许多不了解此基础知识的人设计的系统,这会使性能变得疯狂)。
这是您的用户表的外观。
+----+------+-----+
| id | Name | Age |
+----+------+-----+
| 1 | Bob | 22 |
| 2 | Jack | 15 |
| 3 | Jane | 25 |
+----+------+-----+
技能表
+----+--------------+
| id | skill |
+----+--------------+
| 1 | programming |
| 2 | Marketing |
+----+--------------+
链接表
+----+---------+--------+
| id | skillId | userId |
+----+---------+--------+
| 1 | 1 | 3 |
| 2 | 2 | 3 |
| 3 | 1 | 1 |
+----+---------+--------+
现在对SQL本身来说,从您的示例中看来,您似乎总是希望将技能1和市场营销编程为技能2,在这种情况下(我们使用max和group by来使每个用户仅获得一行)。 / p>
SELECT
u.name Name,u.age Age,MAX(CASE WHEN s.id = 1 THEN s.skill ELSE NULL END) Skill1,-- Programmer
MAX(CASE WHEN s.id = 2 THEN s.skill ELSE NULL END) Skill2 -- Marketing
FROM
users u
LEFT JOIN
linktable l ON l.userId = u.id
LEFT JOIN
skills s ON s.id = l.skillsId
GROUP BY
u.name,u.age
显然,最好的办法是使用group_concat
,就像其他人建议的那样,但是您必须在一栏中处理所有结果,但是可以处理不限数量的技能。
SELECT
u.name Name,GROUP_CONCAT(s.skill) Skills
FROM
users u
LEFT JOIN
linktable l ON l.userId = u.id
LEFT JOIN
skills s ON s.id = l.skillsId
GROUP BY
u.name,u.age
,
首先以一种可以使用确定条件的方式创建表结构...在数据透视选项
中进行更多搜索这里是这种情况的一个例子
Create table Person (FName varchar(20),LName varchar(20),Age Int);
Insert into Person values
('Jacke','W',29),('Prince','P',30),('Rush','B',29);
Create table Speciality (FName varchar(20),Skill varchar(20),Technology varchar(30));
Insert into Speciality values
('Jacke','Skill1','Java'),('Jacke','Skill2','Unix'),'Skill3','PHP'),'.Net'),'Python'),'Notepad++'),'Office 365'),'.Net');
select P.FName,p.LName,p.Age,MAX(IF(Skill = 'Skill1',Technology,MAX(IF(Skill = 'Skill2',NULL)) AS Skill2,MAX(IF(Skill = 'Skill3',NULL)) AS Skill3
from Person P,Speciality S
where P.FName=S.Fname
group by P.FName,p.Age;
+--------+-------+------+------------+--------+-----------+
| FName | LName | Age | Skill1 | Skill2 | Skill3 |
+--------+-------+------+------------+--------+-----------+
| Jacke | W | 29 | Java | Unix | PHP |
| Prince | P | 30 | .Net | Python | Notepad++ |
| Rush | B | 29 | Office 365 | .Net | NULL |
+--------+-------+------+------------+--------+-----------+
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。