I have to create a report on some student completions. The students each belong to one client. Here are the tables (simplified for this question).
CREATE TABLE `clients` (
`clientId` int(10) unsigned NOT NULL auto_increment,
`clientName` varchar(100) NOT NULL default '',
`courseNames` varchar(255) NOT NULL default ''
)
The courseNames
field holds a comma-delimited string of course names, eg "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'
)
The courseId
field here is the index of the course name in the clients.courseNames field. So, if the client's courseNames
are "AB01,AB02,AB03", and the courseId
of the enrolment is 2
, then the student is in AB03.
Is there a way that I can do a single select on these tables that includes the course name? Keep in mind that there will be students from different clients (and hence have different course names, not all of which are sequential,eg: "NW01,NW03")
Basically, if I could split that field and return a single element from the resulting array, that would be what I'm looking for. Here's what I mean in magical pseudocode:
SELECT e.`studentId`, SPLIT(",", c.`courseNames`)[e.`courseId`]
FROM ...
Building on Alwin Kesler's solution, here's a bit of a more practical real world example.
Assuming that the comma separated list is in my_table.list, and it's a listing of ID's for my_other_table.id, you can do something like:
I used the above logic but modified it slightly. My input is of format : "apple:100|pinapple:200|orange:300" stored in a variable @updtAdvanceKeyVal
Here is the function block :
You can create a function for this:
Converting the magical pseudocode to use this, you would have:
MySQL's only string-splitting function is
SUBSTRING_INDEX(str, delim, count)
. You can use this, to, for example:Return the item before the first separator in a string:
Return the item after the last separator in a string:
Return everything before the third separator in a string:
Return the second item in a string, by chaining two calls:
In general, a simple way to get the nth element of a
#
-separated string (assuming that you know it definitely has at least n elements) is to do:The inner
SUBSTRING_INDEX
call discards the nth separator and everything after it, and then the outerSUBSTRING_INDEX
call discards everything except the final element that remains.If you want a more robust solution that returns
NULL
if you ask for an element that doesn't exist (for instance, asking for the 5th element of'a#b#c#d'
), then you can count the delimiters usingREPLACE
and then conditionally returnNULL
usingIF()
:Of course, this is pretty ugly and hard to understand! So you might want to wrap it in a function:
You can then use the function like this:
Here's how you do it for SQL Server. Someone else can translate it to MySQL. Parsing CSV Values Into Multiple Rows.
The idea is to cross join to a predefined table Tally which contains integer 1 through 8000 (or whatever big enough number) and run
SubString
to find the right ,word, position.If you need get table from string with delimiters: