1

I am trying to use a LIKE statement in mysql, i have code that is sort of half working but its not working as intended (or at least how i imagine it to work)

Below is the code i have

SELECT * FROM `videos` WHERE `tags` LIKE '%1%' ORDER BY `videoID` DESC

So to try and explain the code inside the table "videos" i have a column "tags", tags is populated with some data like "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 " each video has its own set of tags made out of the above combination, now i am trying to select all videos with the tag 1 present however the above will select all videos with the numeric 1 so 1, 10, 11, if i change the code to

SELECT * FROM `videos` WHERE `tags` LIKE '%1' ORDER BY `videoID` DESC

It will pick 1, 10, 11 if i change it to

SELECT * FROM `videos` WHERE `tags` LIKE '1%' ORDER BY `videoID` DESC

It will pick both 1 and 11 however i just want it to pick 1 like wise if I'm picking all videos with 11 i just want the videos with 11 present in "tags" to be featured.

Anyone got an ideas on where i'm going wrong on this?

Tables I have 2 tables tags, and videos see below for an example

Tags table

| tagID | tagTitle | tagImage |
| 1     | Anime    | PATH     |
| 2     | FPS      | PATH     |
| 3     | RPG      | PATH     |

Video table

| videoID | tags     | videoTitle |
| 1       | 2 3      | EXAMPLE    |
| 2       | 1        | EXAMPLE    |
| 3       | 1 2 3    | EXAMPLE    |

I opted to go for 2 tables rather than 1 so the main videos table was not littered with tons of full tag names which can get very long with "beat em up and hack and slash" games "4" is much shorter.

Scenario (if this helps)

I'm making a website where i will store my YouTube videos so they can be found from more than once place on the site you can pick videos by tag (horror, rpg, etc) once you pick your tag you get taken to the page that will display all the videos under that tag.

If you need me to expand on anything just let me know.

Thanks in advance.

potashin
  • 44,205
  • 11
  • 83
  • 107
zoro724
  • 87
  • 3
  • 13
  • 6
    It's a lot better to use a separate table for the tags and not something like this. Otherwise you'll have performance problems as well as the problems you're already having searching for things. – Sami Kuhmonen Jul 06 '15 at 16:07
  • 3
    The common advise would be to *normalize all the things*. If it's just used for rare search queries, then storing a CSV list of tags `1,2,3` and using `FIND_IN_SET()` would be easier. – mario Jul 06 '15 at 16:07
  • 3
    See this question entitled "Is storing a delimited list in a database column really that bad?" https://stackoverflow.com/questions/3653462/is-storing-a-delimited-list-in-a-database-column-really-that-bad – Andy Lester Jul 06 '15 at 16:09
  • Thanks for the advice guys i'll go look into how i can normalize the table. – zoro724 Jul 06 '15 at 16:15

7 Answers7

1

You can try with multiple like:

where `tags` like '% 1 %'
   or `tags` like '1 %'
   or `tags` like '% 1'
   or `tags` = '1'

It should match 1 in the middle, start or end of the string. In case tags are ordered inside each string (assumption made upon your example), you can use just second like and exact match = check.

potashin
  • 44,205
  • 11
  • 83
  • 107
  • Probably won't work if the only tag is `1`, because there won't necessarily be a space after it or before it – Mark Baker Jul 06 '15 at 16:12
  • This works great thanks, @MarkBaker i don't think that will be an issue, every game fits into more than one tag however just encase i will look into how i can factor that into the query :) – zoro724 Jul 06 '15 at 16:17
  • Would almost be easier to just use a `REGEXP '(^| )(1)( |$)'` then. – mario Jul 06 '15 at 16:24
0

Include the separator in your like

SELECT * FROM `videos` WHERE `tags` LIKE '1 %' or `tags`=1 ORDER BY `videoID` DESC
Parsa
  • 3,054
  • 3
  • 19
  • 35
  • This doesn't answer the question – Sami Kuhmonen Jul 06 '15 at 16:06
  • Believe it or not I haven’t tried that because I didn’t think that would work because lets say a cell has the data “1 2 3” I didn’t think an exact match of 1 would work due to the 2 and 3 being in the cell, I hope I didn’t just spend 40 minutes wring this question because I over thought something… – zoro724 Jul 06 '15 at 16:08
  • Probably won't work if the only tag is `1`, because there won't necessarily be a space after it or before it – Mark Baker Jul 06 '15 at 16:12
0

You need to pad your column value with your spacer, the trick is to use a NON-SPACE as a delimiter so that MySQL does not auto tidy it, so use fullstop / period being as the delimiter for the numeric value.

Then simply run a single LIKE clause:

SELECT * FROM `videos` WHERE `tags` LIKE '%.1.%' ORDER BY `videoID` DESC

which will only select .1., and not .10. values.

when writing and updating your query you need to remember to wrap each tag in a delimiter, . and that's it, sorted.

Martin
  • 22,212
  • 11
  • 70
  • 132
0

i think that is better seprate you content whit commas "," then you can search

WHERE `tags` LIKE '%,1,%'

The exact match will be located in any position of the field.

Note: Tha start and the end of the field should be , (,1,2,3,4,)

Jjsg08
  • 124
  • 11
0

Perhaps you should consider using a pivot table instead of cramming all those tags into the same column, which means using regex parsing each time you'll do that query.

Since in your model a video can have many tag, and given your previous example, you could modify your database to add a pivot table :

| tagID | tagTitle | tagImage |
| 1     | Anime    | PATH     |
| 2     | FPS      | PATH     |
| 3     | RPG      | PATH     |

| videoID | videoTitle |
| 1       | EXAMPLE    |
| 2       | EXAMPLE    |
| 3       | EXAMPLE    |

The pivot table named tag_video :

| videoID  | tagID  |
| 1        | 2      |
| 1        | 3      |
| 2        | 1      |
| 3        | 1      |
| 3        | 2      |
| 3        | 3      |

Additionally, you should set your primary key for this pivot table on videoID and tagID (by using PRIMARY(videoID, tagID)).

Then to select videos based on one tag (ie. 1), you do :

SELECT * from `videos` as v
INNER JOIN `tag_video` as tv
ON v.videoID = tv.videoID
WHERE tv.`tagID` = 1
ORDER BY v.`videoID` DESC;

If you want to select videos based of multiple tags (ie. 1, 3 and 22), this structure will allow much faster results. You then do :

SELECT * from `videos` as v
INNER JOIN `tag_video` as tv
ON v.videoID = tv.videoID
WHERE tv.`tagID` IN (1, 3, 22)
ORDER BY v.`videoID` DESC;
Community
  • 1
  • 1
Alex
  • 1,241
  • 13
  • 22
0

Use Regular Expressions:

SELECT * FROMvideoswheretagsREGEXP '[[:<:]]10[[:>:]]';

Place the number you are looking for between those groups of characters.

[[:<:]],[[:>:]] : These markers stand for word boundaries, and as such they match the beginning and ending of words, respectively. Replace the comma with the number you are looking for.

geeves
  • 652
  • 7
  • 24
0

Here is a snippet of some code from one of my current projects

          $sql = 'SELECT * from tbl_fish where MATCH(fish_name,size_name,cat_name) AGAINST(:search_query)';

.............................................................. and here is what is returned

    $row_all = $statement->fetchall(PDO::FETCH_ASSOC);
            header('Content-type: application/json');
            echo json_encode($row_all);

In this, The user has to type the actual Name of the fish or the weight of it in order to Get its results which are then returned as listing the entire row associated with that name/ (ID)

In other words you could use a MATCH AGAINST clause combination to receive specific results and filter out unassociated ones.

WChampion
  • 75
  • 1
  • 9