How to determinate if the element 'word4' of the string 'word1;word2;word3;word4' is in the string 'word4','word5','word6','word7'?

StackOverflow https://stackoverflow.com/questions/19632458

Question

On my website, I have a system to categorize contents on a table T.Categories in a MySQL string looking like

category1;category2;category3;category4

(it could be more or less).

On the other hand, I let my users choose the categories they are interested in. Basically, they make their choice on a form and the result is listed in a PHP variable $var looking like

category2','category4','category5

(etc.)

By requesting

T.Categories IN ('".$var."'))";

I'm able to determinate if the content fits with their interests, ONLY WHEN the content is categorized under ONE SINGLE category.

By example:

  • I have a photo in a category called 'Cat'
  • My users want to see the photos which belong to 'Cat' and 'Dogs' categories
  • My SQL request looks like SELECT * FROM T Where T.Categories IN ('".$var."'))";

Practically, I'm telling the SGBD to watch if the content of T.Categories is IN the list $var

It's working when there is only one category in T.Categories. "Is Cat IN $var? yes, Cat is into 'Cat','Dog'. Then I get the content to the user (because Cat is in $var)"

But it's not working anymore if there is more than one categories in T.Categories. Because the whole categories are stored under the form category1;category2;category3;category4. Unhappily: the string 'Cat;Horse;Duck' is not into 'Cat','Dog'(MySQL is looking for the entire string)

What I need is to parse Cat;Horse;Duck in three part in order to make the SGBD looking for each part in the $var list. Is Cat IN $var? yes, Cat is into 'Cat','Dog'. Is Horse In $var? no, Horse is not into 'Cat','Dog'. Is Duck in $var? no, Duck is not into 'Cat','Dog'. Then I get the content to the user (because Cat is in $var).

How could I reach my goal, using a single request?

Was it helpful?

Solution

There is a problem with your design. You should not store categories in a string in MySQL.

You should store categories in a new table, with a many-to-many table linking the two:

Article linked to Categories using a many-to-many table

Once you have a many-to-many table linking your Articles to your Categories, you can retrieve articles based on Categories, and rate how well the match the required keywords.

SELECT A.*, L.Relevance
FROM Article AS A
INNER JOIN
(
    SELECT AC.ArticleID, COUNT(AC.CategoryID) AS Relevance
    FROM ArticleCategory AS AC
    INNER JOIN Category AS C
    ON AC.CategoryID = C.CategoryID   
    WHERE C.Name IN ('Cat','Dog','Donkey','Chicken')
    GROUP BY AC.ArticleID
) AS L
ON A.ArticleID = L.ArticleID
ORDER BY L.Relevance DESC, Name

You can see an example in SQLFiddle.

You can also get more information here:

An alternative is to use the full text search functions in MySQL. More information here:

OTHER TIPS

Really, you should store the categories in rows for each user rather than doing this, which would make your query simple and would also be more normalized. However, this would mean changes to your table structures.

If you can't do that, could you can generate your select request like this:

SELECT * FROM T Where concat(';', T.Categories, ';') like '%;cat;%' or
                      concat(';', T.Categories, ';') like '%;dog;%'

If you stored T.Categories with leading and trailing semi-colons you wouldn't need to use concat. This will mean a scan over the table T, i.e. indexes could not be used.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top