MySQL 从列中选择使用 ^ 作为分隔符

Posted

技术标签:

【中文标题】MySQL 从列中选择使用 ^ 作为分隔符【英文标题】:MySQL Select from column use ^ as delimiter 【发布时间】:2015-07-24 12:53:13 【问题描述】:

我的问题类似于mysql Split String and Select with results。目前我有 2 张桌子:

student

uid | subject_id | name
1   | 1^2^3^4    | a
2   | 2^3^       | b
3   | 1          | c

subject

uid | subject_name
1   | math
2   | science
3   | languange
4   | sport

我预期的结果是:

uid | name    | subject_passed
1   | a       | math, science, languange, sport
2   | b       | science, languange
3   | c       | sport

我试过这个查询:

SELECT
student.uid,
student.name, 
group_concat(subject.subject_name) as subjects_passed 
from student 
join subject on find_in_set(subject.uid,student.subject_id ) > 0
group by student.uid

返回错误:

#1064 - 您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册以获取正确的语法使用 near '在 find_in_set(subject.uid,student.subject_id) > 0 上加入主题 组'在第 7 行

我相信是因为FIND_IN_SET。根据文档,此函数需要 , 作为分隔符。有没有我可以使用的替代查询?

【问题讨论】:

嗯,最好的 做法是不要将多个值存储在单个列中,而是使用联结[uid|single_subject_id] patrick,您确实需要将此模式更改为连接模式。想看它 ?您的违反了第三范式 (3NF) 设计模式。然后你又在其他 cmets 中说你有很多数据,所以我怀疑你甚至会根据惯性来做:> 是的,目前我想做的是增强它,可以试试 Abhik 的推荐,桌子设计不是我设计的 >_<..> 【参考方案1】:

为什么不用REPLACE分隔符:

SELECT
    student.uid,
    student.name,
    GROUP_CONCAT(subject.subject_name) AS subjects_passed
FROM student
JOIN subject ON FIND_IN_SET(subject.uid, REPLACE(student.subject_id, '^', ',')) > 0
GROUP BY student.uid

SQLFiddle


如果您决定对表进行非规范化,那么创建联结表并生成数据是相当简单的:

-- Sample table structure
CREATE TABLE student_subject (
    student_id int NOT NULL,
    subject_id int NOT NULL,
    PRIMARY KEY (student_id, subject_id)
);

-- Sample query to denormalize student <-> subject relationship
SELECT
    student.uid AS student_id,
    subject.uid AS subject_id
FROM student
JOIN subject ON FIND_IN_SET(subject.uid, REPLACE(student.subject_id, '^', ',')) > 0
+------------+------------+
| student_id | subject_id |
+------------+------------+
|          1 |          1 |
|          1 |          2 |
|          1 |          3 |
|          1 |          4 |
|          2 |          2 |
|          2 |          3 |
|          3 |          1 |
+------------+------------+

【讨论】:

哇,感谢您的更新。所以我将查询结果导出为 csv 格式,并存储回新表..太棒了.. 否,仅导出到 CSV 以查看数据是否正常。然后使用INSERT...SELECT 查询。 您好,我再次尝试运行此查询,“select st.uid, st.name, group_concat(sb.subject_name) aspassed_subject from student st join student_subject ss on ss.stid = st.uid join sb.uid 上的主题 sb = ss.subid 其中 st = studentID --(来自存储过程的 IN 参数)按 st.uid 分组;"但与“替换”解决方案相比,它需要更长的时间,知道吗? student_subject(3.5M 行), subject(1.5K 行), student(700k) 350万行太多,必须在student_subject表上定义索引。如果可能,请创建一个复合主键 (stid, subid),以便没有学生可以两次加入同一学科。如果这是不可能的,那么就在上面创建一个索引。还要反向创建相同的索引,即(subid, stid)。让 MySQL 选择最好的。顺便说一句,我觉得 1.5k 主题看起来太多了。 可以说是从几所学校合并而来的,每个学校都有自己的学科代码和名称。想象一下整个数据库包含一个城市的学生信息,那是 1.5k 科目的来源。有点多余和混乱。【参考方案2】:

您永远不应该使用分隔符存储数据,并且应该规范化表格并创建第三个表格来存储学生与主题的关系。

但是在当前情况下,您可以这样做

select
st.uid,
st.name,
group_concat(sb.subject_name) as subject_name
from student st
left join subject sb on find_in_set(sb.uid,replace(st.subject_id,'^',',')) > 0
group by st.uid

这里是创建第三个表并存储关系的选项

create table student_to_subject (id int primary key auto_increment, stid int, subid int);
insert into student_to_subject(stid,subid) values
(1,1),(1,2),(1,3),(1,4),(2,2),(2,3),(3,1);

现在您可以从 student 表中删除列 subject_id 所以查询变成了

select
st.uid,
st.name,
group_concat(sb.subject_name) as passed_subject
from student st
join student_to_subject sts on sts.stid = st.uid
join subject sb on sb.uid = sts.subid
group by st.uid;

http://www.sqlfiddle.com/#!9/f02df

【讨论】:

为什么会有人反对这个答案?! @DrewPierce 有人得到了我的回答真的 pi** :-) @SalmanA 是的,一旦我发布了答案,我就意识到了!但是我总是选择不提供任何重复的答案。并关闭重复的答案,无论答案多么简单:) @SalmanA,我是袜子木偶,嗯? Definition: a false online identity, typically created by a person or group in order to promote their own opinions or views.好的,如果你这么认为的话。 你好 abhik,谢谢你的推荐,目前学生表有相当多的数据,有什么方法可以根据前两个表自动填充/插入第三个表?【参考方案3】:

认为您可以在调用 find_in_set 之前将 ^ 替换为 ,

SELECT
student.uid,
student.name, 
group_concat(subject.subject_name) as subjects_passed 
from student 
join subject on find_in_set(subject.uid, replace(student.subject_id,'^',',') ) > 0
group by student.uid

当然,以这种格式存储值是非常糟糕的数据库设计。

【讨论】:

以上是关于MySQL 从列中选择使用 ^ 作为分隔符的主要内容,如果未能解决你的问题,请参考以下文章

Python - 从列中提取/复制分隔文本到新列 xlsx

MYSQL - 从列中选择一个值或(如果没有给出值)全选[关闭]

在 MySQL 中查询单个列中的多个值

如何从列分隔的数据集到逗号分隔的数据集?

MySQL函数替换列中的逗号分隔值

我可以用纯mysql解决这个问题吗? (加入“;”列中的分隔值)