Query for matching multiple keyword and displaying results? - php

I have a table called cakes that contains the columns: id, title, description, keywords. I also have a table called keywords, with cakes being the parent. The keywords table contains two columns: id and keyword. I need to write the following two queries:
If a person types in ingredients such as chocolate, hazelnut, strawberry (could be any number of keywords separated by a comma) I need the query to search for cakes that contain ALL of the keywords and display results. Display ONLY cakes that contain all keywords. If no cake matches, I need a message saying nothing found.
I have a label on the search box which says, Find similar cakes. If a person types in Vanilla Raspberry or example, the query needs to locate the cake in the database and match its keywords to the keywords of other cakes and display results. Display ONLY cakes that have the same keywords and a MINIMUM of three keywords that are the same.
Not sure how to write these queries. Any help is appreciated. Thanks!

SELECT CakeID, CakeName
FROM TableName
WHERE IngredientName IN ('chocolate', 'hazelnut', 'strawberry' )
GROUP BY CakeID, CakeName
HAVING COUNT(*) = 3
or if uniqueness was not enforce on ingredients for every cakes, use DISTINCT
SELECT CakeID, CakeName
FROM TableName
WHERE IngredientName IN ('chocolate', 'hazelnut', 'strawberry' )
GROUP BY CakeID, CakeName
HAVING COUNT(DISTINCT IngredientName) = 3
SQL of Relational Division

Related

mysql match against values from a table

I found a couple of questions with the same basic heading - but not the same question
i have a content table :
contentid
contentbody
i have a keyword table:
keywordid
keywordgroupid
keywordbody
i have a keywordgroup table:
keywordgroupid
keywordgroupbody
a normail query will look like this:
SELECT `contentid`,`contentbody` MATCH(`contentbody`) AGAINST ('whateverkeyword')
and i want to do a query like this:
how ever i want to the replace the 'whateverkeyword' with the results of a query e.g.
SELECT `keywordbody` FROM `keywordgroup` WHERE `keywordgroupid`=1
the idea is that the user selects a keyword group which is stored in the keyword table for instance if this was a person skills database you would have:
programmer keyword group that would have as keywords: logical,focused,technical
sales person keyword group that would have as keywords: people skills,friendly,outgoing
etc.
essentially I want to have a dynamic match value any ideas?

MSQL query for displaying results based on the same keywords

I have a table called cakes that contains the columns: id, title, description, keywords. I also have a table called keywords, with cakes being the parent. The keywords table contains two columns: id and keyword
I need two queries: UPDATED
If a person types in ingredients such as chocolate, hazelnut, strawberry (could be anything separated by a comma) I need the query to search for cakes that contain all three keywords and display results. Display ONLY cakes that contain all three. If no cake matches, I need a message saying nothing found.
I have a label on the search box which says, Find similar cakes. If a person types in Vanilla Raspberry or example, the query needs to locate the cake in the database and match its keywords to the keywords of other cakes and display results. Display ONLY cakes that have the same keywords.
Not sure how to write these queries. Any help is appreciated. Thanks!
If the database must use a delimited long-string field for "keywords" rather than putting them in rows, then you will want to use the LIKE Operator
Assuming your [keywords] column is formatted like this:
'chocolate,ganache,strawberry'
You can search for "similar" cakes like this:
SELECT
columns
FROM
table t
WHERE
t.[keywords] LIKE '%chocolate%'
OR t.[keywords] LIKE '%cheesecake%'
Though, if you can change the schema, I would do so. Searching normalized keyword rows will be much more efficient and fast than having the DB parse through text using LIKE
If you could make a keywords table, which references the parent table by ID, you could do an equality search using a JOIN which would be superior, in my opinion.
It might have three columns: Id, ParentId, Keyword
EDIT: So based on your update, you have a cakewords table which can be searched.
This is untested, and there is likely a more efficient way using no IN clause. But the idea is that you know all the keyword id's for your specific cake. Then you are looking for other cakes having keywords in that collection.
SELECT
columns
FROM
cake AS cs
JOIN
cakewords AS csw
ON csw.[cakeid] = cs.[id]
WHERE
csw.[wordid] IN
(SELECT
cw.[wordid]
FROM
cakewords AS cw
JOIN
cakes AS c
ON c.[id] = cw.[cakeid]
WHERE
c.[id] = #pMyCurrenctCakeId
(
EDIT2: Here is a good related question:
What's the optimal solution for tag/keyword matching?
Based on an answer within, you might try this:
SELECT DISTINCT
c.[id]
FROM
cakewords AS cw1
INNER JOIN cakewords cw2
ON cw2.[wordid] = cw1.[wordid]
INNER JOIN cake AS c
ON c.[id] = cw.[cakeid]
WHERE
cw1.[cakeid] = #current_cake_id

How to sort MySQL results with letters first, symbols last?

Long-time reader, first-time poster here.
I'm trying to figure out how to sort a list of artists for a music app I'm writing.
To help understand the database structure: Rather than having a relational system where each song in the songs table has an artist ID that references a row in the artists table, I simply have a list of songs with the artist's name as a string in a column. I then use GROUP BY artist in a MySQL query to return a list of individual artists.
My app retrieves this data from my server in the form of a JSON-encoded array which is the result of the following MySQL query:
SELECT artist FROM songs GROUP BY artist ORDER BY artist ASC
However, this query results with artists with names like &i, +NURSE, and 2007excalibur2007 being sorted before the alphabetical results (such as AcousticBrony, ClaireAnneCarr, d.notive, etc.).
What I need is the artists whose names begin with numbers and symbols returned after the alphabetically-sorted artist list.
The solution can be PHP-based, but I'd prefer the elegance of it being done in the MySQL query.
This will put all the artists who's names begin with a letter in a-z before those that don't:
SELECT DISTINCT artist
FROM songs
ORDER BY artist REGEXP '^[a-z]' DESC, artist
See it working online: sqlfiddle
But you might prefer to store a second column with the simplified name so that you can put them in an order that makes more sense:
artists
artist | simplified_name
------------------------------------
&i | i
+NURSE | nurse
2007excalibur2007 | excalibur
The values for simplified_name cannot be easily generated in MySQL, so you may want to use a general purpose programming language to pull out all the artists, transform them to simplified names, then populate the database with the results.
Once this is done, you can use this query:
SELECT DISTINCT artist
FROM artists
ORDER BY simplified_name
You can add an extra ORDER BY clause that puts the items that start with a non-alphabetic character last, like so:
SELECT artist
FROM songs
ORDER BY artist REGEXP '^[^A-Za-z]' ASC, artist
This should move every artist that doesn't start with A-Z or a-z to the end of your ordering.
ORDER BY ASCII(SUBSTR(artist, 1, 1)) NOT BETWEEN 65 AND 122, artist
This will order all artists that start with an alphabetical character before non alphabetical.
Note that because of how ascii works [ \ ] & _ ` will be considered alphabetical. If this matters you can split it into two boolean expressions to do the upper and lower case letters separately.
Or maybe:
ORDER BY ASCII(UPPER(SUBSTR(artist, 1, 1))) NOT BETWEEN 65 AND 90, artist
Be aware that this will only work for ascii characters. Letters that are part of other character sets won't be recognized as such.
if you want sort by symbol first
★★★ Symbol ★★★
101 Hair Care
Abc
Def
then use below query
ORDER BY artist REGEXP '^[^A-Za-z0-9]' DESC, artist ASC

Make a list of most used keywords

I have a mysql table with these columns: id, text, keywords.
ID is an id. Text is a title. Keywords is a list of tags in this format: tag1 tag2 tag3.
How would I go about getting a list of the most used keywords in the column? Eg. if I wanted to build a tag cloud from all the items in the table.
There are ways to do what you want. But it won't be simple. The way you have organized your keywords in this database is going to cause quite a few headaches. You should try to normalize the data.
Perhaps instead of this:
id text keywords
1 bob he she it
2 thing white yellow hello
Have an separate table for the keywords:
id keyword
1 he
1 she
2 white
2 yellow
That way, it would be a much simpler matter to find what you want:
select count(keyword) as num from `keywords` group by keyword order by num desc
A simple way would be to create an array where each key is tag#. The value of each of those keys is the number of times tag# appears in the database; this would involve traversing through each tag in the database.
You might be better off normalising your database tables. Maybe something like this:
Items table : id, text
Tags table : id, text
items_tags table: item_id, tag_id
This way you can associate multiple tags with each item, and queries for tag counts become easy.

MySQL query based on 3 tables

I work with PHP. I have a table named books. In table books I have the book_name with the name of the book, book_publisher with the publisher's ID and book_author with the author's ID. Besides the books table I have the books_author table with the authors names and IDs and books_publisher with the books publishers names and IDs.
I give my users 3 input fields that represents author name, book name and publisher name and a search button. They can input an author name, a book name and publisher name in the same search and I have to query my database and return the books names that have author name LIKE (%..%) inputted author name, book name LIKE the inputted book name and publisher name LIKE the inputted publisher name.
The problem is that I have stored only the author's id and publisher's id in my books table and I need to search by all three fields and exclude duplicates (books that were match by name and also by publisher).
Can anybody help me building this query ?
Just join the query:
SELECT *
FROM books b
JOIN book_authors ba ON b.author_id = ba.id
JOIN book_publishers bp ON b.publisher_id = bp.id
WHERE b.book_name LIKE '...'
AND ba.author_name LIKE '...'
AND bp.publisher_name LIKE '...'
Usually in these situations the search boxes are optional so you'll need to dynamically construct the query, meaning the WHERE clause to only filter on, say, publisher name if the user actually entered a publisher name.
Also, searching on LIKE '%blah%' is not scalable beyond thousands or possibly tens of thousands of records. No indexing can cater for that. You may want to look into using something like the MySQL full-text searching instead.
Lastly, make sure you sanitize your input, meaning pass all your input fields through mysql_real_escape_string().

Categories