I'm building a simple shopping cart. I need to allow for related products. My initial thought was to have a db field in the product table called tags which will have a comma delimited list of tags in it:
tag1,tag2,tag3
When I grab the product from the db I could also grab the tags and explode the string on the comma.
Problem is i'm having trouble thinking of a good way to then call to the db for all other products that have a matching tag. Is there way to search a string in SQL?
can anyone think of a good way to achieve this
You can use FIND_IN_SET() for that purpose:
SELECT * FROM tableName WHERE FIND_IN_SET('tag1', tags) > 0
However, I would strongly suggest to read on database normalization and joins instead.
Pleaso do not use any of the answers mentioning the LIKE syntax. For example WHERE tags LIKE %tag1% would match tag1 but also tag12 which is just wrong.
I would not go down the route of storing comma separated strings in fields, its not very scalable (or normalized) . I would split this up into 3 different tables:
products:
-------------
id | name
-------------
1 | product 1
2 | product 2
tags:
---------------
id | tag
---------------
1 | tag 1
2 | tag 2
product_tags:
----------------------
product_id | tag_id
----------------------
1 | 1
1 | 2
When you want to find products with related tags you would just do
SELECT product_id FROM product_tags WHERE tag_id = TAG_ID
You could then use more advanced joining statements to return the records from the products table (instead of just product_id's from the tags table):
SELECT products.* FROM products
INNER JOIN product_tags ON product_tags.product_id = products.id
WHERE product_tags.tag_id = TAG_ID
Its a bit more work but it will save you headaches in the future.
Consider using MySQL LIKE clause (check out this guide: http://www.tutorialspoint.com/mysql/mysql-like-clause.htm). You may use it on each tag, something like this:
SELECT * FROM `product` WHERE `tags` LIKE '%tag1%' OR `tags` LIKE '%tag2%' OR `tags` lIKE '%tag3'
To search for a string in SQL you can use the LIKE operator. Here is an example:
mysql_query("SELECT * FROM table_name WHERE value LIKE '%str%' ");
Related
I'm trying to make something similar to "related articles". This is what I have.
$query = "SELECT * FROM posts WHERE post_tags LIKE '%$post_tags%'";
I want it to 'select all from post where the post tags are similar to the current post's tags'.
Note: The tags look like this in the database: "tech, news, technology, iphone"
I looked into things like
$tags = explode(",", $post_tags );
But I'm not sure.
Use FullText search -- docs
SELECT * FROM `posts` WHERE MATCH(post_tags) AGAINST('$post_tags' IN BOOLEAN MODE)
Live demo
The query will require you to add a FULLTEXT index to your post_tags table column (unless you have the older MyISAM table). This query will be a lot faster than your current attempt.
query to add the index
ALTER TABLE `posts` ADD FULLTEXT INDEX `tag_search` (`post_tags`)
A better, faster approach
Change how you store the post-to-tag relationship in the DB. Your posts table should not be used to store tags because one post has many tags, but each post has only one record in the posts table. Instead, have a two other tables:
tags table
tag_id | name
1 | technology
2 | news
3 | hobbies
post_tags table
post_id | tag_id
1 | 1
1 | 3
2 | 1
Notice it's easy to tell that post_id #1 has the technology and hobbies tags. This will make your queries easier, and faster.
Even faster!
If you do want to store everything in the posts table but have even faster performance, you will need to store your tags as bit flags. For instance, if the following is true in your PHP application:
$techBit = 0b001; // number 1 in binary form
$newsBit = 0b010; // number 2 in binary form
$hobbiesBit = 0b100; // number 4 in binary form
Then it's easy to store tags in one field. A post that has technology and hobbies tag would have a value:
$tag = $techBit | $hobbiesBit; // 1 + 4 = 5
And if you wanted to search for all records with technology or hobbies, you would do:
// means: records where post_tags has either techBit or hobbiesBit turned ON
SELECT * FROM `posts` WHERE (`post_tags` & ($techBit | $hobbiesBit)) > 0
Well instead of "LIKE" you could use the "IN" clause.
$Results = join("','",$post_tags);
$SQLQuery = "SELECT * FROM galleries WHERE id IN ('$Results')";
Example: Passing an array to a query using a WHERE clause
Table
Hello i try to finds all hashtags with name #c3 and mysqli query show me: 3 rows but correct is 2 rows with #c3 ??? where is problem ? I want to show me 2Rows !
$sql_query = mysqli_query($Connection, "SELECT * FROM my_table WHERE hashtag LIKE '%#c3%'");
echo mysqli_num_rows($sql_query);
To answer this and as left in comments (by myself)
Use '%#c3' by removing the last %
Using LIKE, the % wildcard does the following and a few examples:
%XXX% - Matches anything before and after XXX
%XXX - Matches anything before XXX
XXX% - Matches anything after XXX.
References:
http://dev.mysql.com/doc/refman/5.7/en/string-comparison-functions.html
http://dev.mysql.com/doc/refman/5.7/en/pattern-matching.html
http://www.tutorialspoint.com/mysql/mysql-like-clause.htm
Plus, should there be any user input, consider using a prepared statement:
https://en.wikipedia.org/wiki/Prepared_statement
It will help against a potential SQL injection.
https://en.wikipedia.org/wiki/SQL_injection
Hi Your query is wrong try to use this
SELECT * from my_table WHERE FIND_IN_SET('#c3', hashtag);
FIND_IN_SET returns the position of a string if it is present (as a substring) within a list of strings. The string list itself is a string contains substrings separated by ‘,’ (comma) character.
for more info read http://www.w3resource.com/mysql/string-functions/mysql-find_in_set-function.php
You can use FIND_IN_SET
SELECT * FROM my_table WHERE FIND_IN_SET('#c3',hashtag)
See docs here and example here
Split the table into 2 tables:
post: id | text | date
1
2
3
post_hashtag: post_id | hashtag
1 #c1
1 #c3
2 #c3
3 #c3blabla
Then your query becomes:
SELECT post.*,post_hashtag.hashtag FROM post JOIN post_hashtag ON post.id=post_hashtag.post_id WHERE hashtag='#c3#';
The act of splitting the table is called normalizing and you need to do this because your tables are not in any normal form which makes them not relational which defeats the purpose of storing them in a relational database. Check https://en.wikipedia.org/wiki/First_normal_form for more information.
Looking at your table, I would suggest that you break up your tables to have a many to many link for hashtag. That way you can search for all records that have a matching hashtag.
data table
+----+------+------+
| id | text | date |
+----+------+------+
hash table
+----+------+
| id | hash |
+----+------+
link table
+---------+---------+
| data_id | hash_id |
+---------+---------+
This would then allow you to use an SQL statement like:
SELECT * FROM data
INNER JOIN link ON data_id = data.id
INNER JOIN hash ON hash_id = hash.id
WHERE hash = '#3';
I am having a database with a table to stock the products of my site and the table has the following column for all the categories a specific product belongs to:
After making a query to get the categories the first row belongs to, The information is stored in an object which looks like this $productDetails->ProductCategoryID and the content is the following: dinner,casual,kids
Now,my question is that how can I use the SQL command SELECT to get all the products having at least one category in common by using PHP.
Kindly help me solve this problem. Sorry I am not a native english speaker
If I've understood, you have a column which contains a string representing product's categories separated by comma. In this case you have to execute a substring function on the column ProductCategoryID, which is always discouraged.
I suggest you, instead of using the column ProductTable.ProductCategoryID, to make a link table ProductsCategories with the columns ProductID, CategoryID.
----------------------
| ProductsCategories |
----------------------
| ProductID |
| CategoryID |
----------------------
In this way you can use a more efficient QUERY like this one:
SELECT DISTINCT ProductTable.*
FROM ProductTable
INNER JOIN ProductsCategories ON (ProductsCategories.ProductID = ProductTable.ProductID)
WHERE CategoryID IN
(
SELECT CategoryID
FROM ProductsCategories
WHERE ProductID != ProductTable.ProductID
)
;
All this, of course, has sense if I've understood in the right way the structure of ProductCategoryID column :)
my MySQL table is in this structure:
|id|title|duration|thumb|videoid|tags|category|views
|1||Video Name|300|thumb1.jpg|134|tag1|tag2|tag3|category|15
|2||Video Name2|300|thumb2.jpg|1135|tag2|tag3|tag4|category|10
Table contains about 317k rows.
Query is:
SELECT id,title,thumb FROM videos WHERE tags LIKE '%$keyword%' or title LIKE '%$keyword%' order by id desc limit 20
And this is taking 0.8s to 3s to load results.
Im new in php/mysql, how can I speed up these queries, suggestions please, thank you.
The only other suggestion I can throw in is to have a multi-part index of
( tags, title, id )
This way, it can utilize the index to qualify the WHERE clause criteria for both tags and title, and have the ID for the order by clause without having to go back to the raw data pages. Then, when records ARE found, only for those entries does it need to actually retrieve the raw data pages for the other columns associated with the row.
You are using this search construct:
column LIKE '%$keyword%'
The leading % wildcard character definitely defeats the use of indexes to do these searches. How to cure this terrible performance problem? You could use FULLTEXT search, about which you can read. Or, you could try to organize your tables so
column LIKE 'keyword%'
will find what you need, and then index the columns being searched. To do this, you would create a tag table, with a name and id for each distinct tag. This table will have a primary key on the id, and a unique key on the tag. E.g.
tag_id | tag
1 | drama
2 | comedy
3 | horror
4 | historical
The you would create another table, known in the trade as a join table, with two ids in it. The primary key of this table is a composite of the two columns. You also need a non-unique index on the tag_id field.
video_id | tag_id
1 | 1
1 | 4
This sample data gives video with id = 1 the tags "drama" and "historical."
Then to match tags you need
SELECT v.id, v.title, v.thumb
FROM video AS v
JOIN tag_video AS tv ON v.id = tv.video_id
JOIN tag AS t ON tv.tag_id = t.tag_id
WHERE t.tag IN ('drama', 'comedy')
This will look up your tags very fast, and let you look up multiple ones in a single query if you wish.
It won't help with your requirement for full text search on your titles, however.
EDITED:
define indexes on title and keyword fields.
try this:
ALTER TABLE `videos` ADD INDEX (`title`);
ALTER TABLE `videos` ADD INDEX (`keyword`);
I have two tables in the database, parts, and products.
I have a column in the products table with strings of ids (comma separated). Those ids match ids of the parts table.
**parts**
ID | description (I'm searching this part)
-------------------------------
1 | some text here
2 | some different text here
3 | ect...
**products**
ID | parts-list
--------------------------------
1 | 1,2,3
2 | 2,3
3 | 1,2
I'm really struggling with the SQL query on this one.
I've done the 1st part, got the id's from the parts table
SELECT * FROM parts WHERE description LIKE '%{$search}%'
The biggest problem is the comma separated structure of the the description column.
Obviously, I could do it in PHP, create an array of the the results from the parts table, use that to search the products table for id's, and then use those results to grab the row data from the parts table (again). Not very efficient.
I also tried this, but I'm obviously trying to compare two arrays here, not sure how this should be done.
SELECT * FROM `products` WHERE
CONCAT(',', description, ',')
IN (SELECT `id` FROM `parts` WHERE `description` LIKE '%{$search}%')
Can anybody help?
I would perhaps try a combination of LOCATE() and SUBSTR(). I work mainly in MSSQL which has CHARINDEX() that I think works like MySQL's LOCATE(). It is bound to be messy. Are there a variable number of elements in the parts-list field?