Please read here why your design is a bad idea. You should store you data in a normalized way as follows:
table studens:
id | name
1 | John
2 | Jane
3 | Mike
4 | Spike
table hobbies:
id | name
1 | biology
2 | geogryphy
3 | football
4 | programming
table students_hobbies:
student_id | hobby_id
1 | 3
1 | 4
2 | 1
2 | 2
3 | 1
3 | 2
3 | 4
4 | 3
Schema definition:
CREATE TABLE students (
id INT UNSIGNED AUTO_INCREMENT,
name VARCHAR(50),
PRIMARY KEY (id),
INDEX (name)
);
CREATE TABLE hobbies (
id INT UNSIGNED AUTO_INCREMENT,
name VARCHAR(50),
PRIMARY KEY (id),
INDEX (name)
);
CREATE TABLE students_hobbies (
student_id INT UNSIGNED,
hobby_id INT UNSIGNED,
PRIMARY KEY (student_id, hobby_id),
INDEX (hobby_id, student_id)
);
And your SELECT query now would be:
SELECT s.*
FROM students s
JOIN students_hobbies sh ON sh.student_id = s.id
JOIN hobbies h ON h.id = sh.hobby_id
WHERE h.name = 'geogryphy';
Result:
| id | name |
| --- | ---- |
| 2 | Jane |
| 3 | Mike |
View on DB Fiddle
However - If you want to stick with your design, you can try something like this:
SELECT *
FROM students
WHERE student_hobbys LIKE '_|1%'
View on DB Fiddle
But it would be quite complex to generate this query programmatically. It will probably also be slower than the above solution on big dada sets, because there is no way to use an index for this kind of query.
If you want to avoid complex code in your application, you will need a quite more comlex query. One way would be to convert your string to a bitmask, and then use the bit operator &
to check the bit at a specific position:
SET @hobby_position = 2;
SELECT *
FROM students
WHERE CONV(REVERSE(REPLACE(student_hobbys, '|', '')), 2, 10) & 1 << (@hobby_position - 1);
| id | name | student_hobbys |
| --- | ---- | --------------- |
| 2 | Jane | 1|1|1|1|0|0|1|0 |
| 3 | Mike | 1|1|1|1|0|0|1|0 |
View on DB Fiddle
There are other ways - But you will unlikely find a simple one, which can work with your design.