我必须创建一些学生完成报告.每个学生都属于一个客户.以下是表格(此问题已简化).
CREATE TABLE `clients` (
`clientId` int(10) unsigned NOT NULL auto_increment,
`clientName` varchar(100) NOT NULL default '',
`courseNames` varchar(255) NOT NULL default ''
)
Run Code Online (Sandbox Code Playgroud)
该courseNames字段包含以逗号分隔的课程名称字符串,例如"AB01,AB02,AB03"
CREATE TABLE `clientenrols` (
`clientEnrolId` int(10) unsigned NOT NULL auto_increment,
`studentId` int(10) unsigned NOT NULL default '0',
`courseId` tinyint(3) unsigned NOT NULL default '0'
)
Run Code Online (Sandbox Code Playgroud)
courseId此处的字段是clients.courseNames字段中课程名称的索引.因此,如果客户courseNames是"AB01,AB02,AB03",并且courseId注册的是2,则学生在AB03.
有没有办法可以在包含课程名称的这些表上进行单一选择?请记住,将有来自不同客户的学生(因此具有不同的课程名称,并非所有课程名称都是连续的,例如:"NW01,NW03")
基本上,如果我可以拆分该字段并从结果数组中返回单个元素,那将是我正在寻找的.这就是我在魔法伪代码中的意思:
SELECT e.`studentId`, SPLIT(",", c.`courseNames`)[e.`courseId`]
FROM ...
Run Code Online (Sandbox Code Playgroud)
小智 30
到现在为止,我想在我的SQL数据库中保留这些以逗号分隔的列表 - 充分了解所有警告!
我一直认为它们比查找表(它提供了一种规范化数据库的方法)有好处.经过几天的拒绝,我看到了光明:
简而言之,MySQL中没有原生SPLIT()函数是有原因的.
eit*_*hed 22
看到这是一个相当受欢迎的问题 - 答案是肯定的.
对于包含所有逗号分隔值的column表格table中的列:
CREATE TEMPORARY TABLE temp (val CHAR(255));
SET @S1 = CONCAT("INSERT INTO temp (val) VALUES ('",REPLACE((SELECT GROUP_CONCAT( DISTINCT `column`) AS data FROM `table`), ",", "'),('"),"');");
PREPARE stmt1 FROM @s1;
EXECUTE stmt1;
SELECT DISTINCT(val) FROM temp;
Run Code Online (Sandbox Code Playgroud)
但请记住,不要在您的数据库中存储CSV
Per @Mark Amery - 因为这会将昏迷分隔的值转换为INSERT语句,所以在未经过数据处理的数据上运行它时要小心
重申一下,请不要将CSV存储在数据库中; 此功能旨在将CSV转换为合理的数据库结构,而不是在代码中的任何位置使用.如果您必须在生产中使用它,请重新考虑您的数据库结构
Jos*_*ius 12
您可以为此创建一个函数:
/**
* Split a string by string (Similar to the php function explode())
*
* @param VARCHAR(12) delim The boundary string (delimiter).
* @param VARCHAR(255) str The input string.
* @param INT pos The index of the string to return
* @return VARCHAR(255) The (pos)th substring
* @return VARCHAR(255) Returns the [pos]th string created by splitting the str parameter on boundaries formed by the delimiter.
* @{@example
* SELECT SPLIT_STRING('|', 'one|two|three|four', 1);
* This query
* }
*/
DROP FUNCTION IF EXISTS SPLIT_STRING;
CREATE FUNCTION SPLIT_STRING(delim VARCHAR(12), str VARCHAR(255), pos INT)
RETURNS VARCHAR(255) DETERMINISTIC
RETURN
REPLACE(
SUBSTRING(
SUBSTRING_INDEX(str, delim, pos),
LENGTH(SUBSTRING_INDEX(str, delim, pos-1)) + 1
),
delim, ''
);
Run Code Online (Sandbox Code Playgroud)
将魔法伪代码转换为使用此代码,您将拥有:
SELECT e.`studentId`, SPLIT_STRING(',', c.`courseNames`, e.`courseId`)
FROM...
Run Code Online (Sandbox Code Playgroud)
根据上面的Alex回答(/sf/answers/771570201/),我提出了更好的解决方案.解决方案不包含确切的一个记录ID.
假设逗号分隔列表在表中data.list,并且它包含来自其他表的代码列表classification.code,您可以执行以下操作:
SELECT
d.id, d.list, c.code
FROM
classification c
JOIN data d
ON d.list REGEXP CONCAT('[[:<:]]', c.code, '[[:>:]]');
Run Code Online (Sandbox Code Playgroud)
所以如果你有这样的表和数据:
CLASSIFICATION (code varchar(4) unique): ('A'), ('B'), ('C'), ('D')
MY_DATA (id int, list varchar(255)): (100, 'C,A,B'), (150, 'B,A,D'), (200,'B')
Run Code Online (Sandbox Code Playgroud)
以上SELECT将返回
(100, 'C,A,B', 'A'),
(100, 'C,A,B', 'B'),
(100, 'C,A,B', 'C'),
(150, 'B,A,D', 'A'),
(150, 'B,A,D', 'B'),
(150, 'B,A,D', 'D'),
(200, 'B', 'B'),
Run Code Online (Sandbox Code Playgroud)
MySQL唯一的字符串分割功能是SUBSTRING_INDEX(str, delim, count).你可以使用它,例如:
在字符串中的第一个分隔符之前返回该项:
mysql> SELECT SUBSTRING_INDEX('foo#bar#baz#qux', '#', 1);
+--------------------------------------------+
| SUBSTRING_INDEX('foo#bar#baz#qux', '#', 1) |
+--------------------------------------------+
| foo |
+--------------------------------------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)在字符串中的最后一个分隔符后返回该项:
mysql> SELECT SUBSTRING_INDEX('foo#bar#baz#qux', '#', -1);
+---------------------------------------------+
| SUBSTRING_INDEX('foo#bar#baz#qux', '#', -1) |
+---------------------------------------------+
| qux |
+---------------------------------------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)返回字符串中第三个分隔符之前的所有内容:
mysql> SELECT SUBSTRING_INDEX('foo#bar#baz#qux', '#', 3);
+--------------------------------------------+
| SUBSTRING_INDEX('foo#bar#baz#qux', '#', 3) |
+--------------------------------------------+
| foo#bar#baz |
+--------------------------------------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)通过链接两个调用返回字符串中的第二项:
mysql> SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('foo#bar#baz#qux', '#', 2), '#', -1);
+----------------------------------------------------------------------+
| SUBSTRING_INDEX(SUBSTRING_INDEX('foo#bar#baz#qux', '#', 2), '#', -1) |
+----------------------------------------------------------------------+
| bar |
+----------------------------------------------------------------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)通常,获取#分离字符串的第n个元素的一种简单方法(假设您确定它至少具有n个元素)是:
SUBSTRING_INDEX(SUBSTRING_INDEX(your_string, '#', n), '#', -1);
Run Code Online (Sandbox Code Playgroud)
内部SUBSTRING_INDEX调用将丢弃第n个分隔符及其后的所有内容,然后外部SUBSTRING_INDEX调用将丢弃除剩余的最终元素之外的所有内容.
如果你想要一个更健壮的解决方案,NULL如果你要求一个不存在的元素(例如,要求第五个元素'a#b#c#d'),则返回,那么你可以计算分隔符REPLACE,然后NULL使用条件返回IF():
IF(
LENGTH(your_string) - LENGTH(REPLACE(your_string, '#', '')) / LENGTH('#') < n - 1,
NULL,
SUBSTRING_INDEX(SUBSTRING_INDEX(your_string, '#', n), '#', -1)
)
Run Code Online (Sandbox Code Playgroud)
当然,这非常难看,难以理解!所以你可能想把它包装在一个函数中:
CREATE FUNCTION split(string TEXT, delimiter TEXT, n INT)
RETURNS TEXT DETERMINISTIC
RETURN IF(
(LENGTH(string) - LENGTH(REPLACE(string, delimiter, ''))) / LENGTH(delimiter) < n - 1,
NULL,
SUBSTRING_INDEX(SUBSTRING_INDEX(string, delimiter, n), delimiter, -1)
);
Run Code Online (Sandbox Code Playgroud)
然后你可以使用这样的函数:
mysql> SELECT SPLIT('foo,bar,baz,qux', ',', 3);
+----------------------------------+
| SPLIT('foo,bar,baz,qux', ',', 3) |
+----------------------------------+
| baz |
+----------------------------------+
1 row in set (0.00 sec)
mysql> SELECT SPLIT('foo,bar,baz,qux', ',', 5);
+----------------------------------+
| SPLIT('foo,bar,baz,qux', ',', 5) |
+----------------------------------+
| NULL |
+----------------------------------+
1 row in set (0.00 sec)
mysql> SELECT SPLIT('foo###bar###baz###qux', '###', 2);
+------------------------------------------+
| SPLIT('foo###bar###baz###qux', '###', 2) |
+------------------------------------------+
| bar |
+------------------------------------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
小智 5
基于 Alwin Kesler 的解决方案,这里有一些更实际的现实世界示例。
假设逗号分隔列表在 my_table.list 中,并且它是 my_other_table.id 的 ID 列表,您可以执行以下操作:
SELECT
*
FROM
my_other_table
WHERE
(SELECT list FROM my_table WHERE id = '1234') REGEXP CONCAT(',?', my_other_table.id, ',?');
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
203316 次 |
| 最近记录: |