I do have two mysql tables where I would like to mark keywords inside the second table that are inside the main table.
e.g.:
main:
labrador
chihuahua
buldog
second
KEYWORD SIMILAR
labrador puppies 1
red dogs 0
good medicine 1
Is this even possible with one mysql statement? I would try this with PHP, but hope to find a mysql only solution.
Something like:
UPDATE `keywords`
SET SIMILAR = 1
WHERE keyword like (% SELECT KEYWORD FROM second %")
Has anybody an idea if this is doable and could give me a hint? Thank you for any help on this.
You can connect two tables with joins: MySQL Inner Join Tutorial
UPDATE
keywords
INNER JOIN
second
ON keywords.KEYWORD LIKE '%', second.KEYWORDS ,'%'
SET
keywords.SIMILAR = 1
WHERE
keywords.SIMILAR = 0;
this query make only an update if the keyword in keywords table similar like keyword in your second table and doesn't yet marked as similar.
Related
I am coding a tiny search engine for my practice. I want to add up search functionality in it. I am trying to select all rows of questions table upon matching title, description and keywords.
I created the following 3 tables:
questions(id(PK), title, description)
keywords(id(PK), label);
questions_keywords(id(PK), question_id(FK), keyword_id(FK));
So far my SQL query looks like this:
SELECT q.* FROM question_keywords qk
JOIN keywords k ON qk.keyword_id=k.id
JOIN questions q ON qk.question_id=q.id
WHERE q.description LIKE '%javascript%'
OR
k.keyword_label LIKE '%java%'
In this query, i am selecting all the rows from questions table containing the substring java or javascript
Am I doing it right or there is a better way to do it??
Thanks in advance.
AS others mentioned I would add distinct. I would also reorder the tables. Functionally I don't think it matters it just bugged me... ha ha
SELECT DISTINCT
q.*
FROM
questions AS q
JOIN
question_keywords AS qk ON q.id = qk.question_id
JOIN
keywords AS k ON qk.keyword_id = k.id
WHERE
q.description LIKE '%javascript%'
OR
k.label LIKE '%java%';
As you can see in this DBfiddle
https://www.db-fiddle.com/f/pcVqcMm1yUoU6NdSHitCVr/2
The reason you get duplicates is basically called a Cartesian product
https://en.wikipedia.org/wiki/Cartesian_product
In simple terms is just a consequence of having a "Many to Many" relationship.
If you see in the fiddle I intentionally created this situation by what I added to the Bridge ( or Junction ) table question_keywords in the last 2 Inserts
INSERT INTO question_keywords (question_id,keyword_id)VALUES(4,1);
INSERT INTO question_keywords (question_id,keyword_id)VALUES(4,2);
The duplicate row, is simply because there are 2 entries for this table with the matching value of 4 for question_id. So these are only Duplicates in the sense that we are only selecting the fields form the questions table. If we included fields from the keywords table. Then one row would have a keyword or Java #1 while the other would have Javascript #2 as the keyword.
Hope that helps explain it.
A few other things to note:
You have a syntax error in the query you posted k.keyword_label LIKE '%java%' should be k.label LIKE '%java%' according to your table definition in the question.
Typically the Junction table should be a combination of both tables it joins ( which you almost did ) but the pluralization is wrong question_keywords should be questions_keywords it's a small thing but it could cause confusion when writing queries.
There is really not a need for a separate primary key for the Junction table.
If you notice how I created the table in the fiddle.
CREATE TABLE question_keywords(
question_id INT(10) UNSIGNED NOT NULL,
keyword_id INT(10) UNSIGNED NOT NULL,
PRIMARY KEY(question_id,keyword_id)
);
The primary key is a compound of the 2 foreign keys. This has the added benefit of preventing real duplicate rows from being made. For example if you tried this
INSERT INTO question_keywords (question_id,keyword_id)VALUES(4,1);
INSERT INTO question_keywords (question_id,keyword_id)VALUES(4,1);
With the setup I have it would be impossible to create the duplicate. You can still have a separate primary key (surrogate key), but you should create a compound unique index on those 2 keys in place of it.
Last time you guys were super helpful, let's hope we can also resolve the following challenge that I'm having.
I have 2 tables in the same database and trying to match fields. Here is the query I'm looking for with the table name however I cannot get it to work:
I want to MATCH table "projects" and Column "categorysecond" table "users_profile" and Column "category".
projects.categorysecond might include example; "Roofing,Windows,Landscaping" and users_profile.category might only have EITHER "Roofing" OR "Windows" OR "Landscaping", so I want to pull the results from "projects" if a result from users_profile.category FITS in projects.categorysecond
***Important - I do not have unique identifiers to do a inner join on example ID. The only match should be on the tables listed above, if words(%Wildcard) from one fits the other.
SAMPLE OF MY ATTEMPT
$sql = "SELECT DISTINCT users_profiles.username, projects.id FROM users_profiles, projects WHERE users_profiles.category like '%' + projects.categorysecond + '%'";
Does this make sense? :)
Thank you in advance.
select distinct
up.username
,p.id
from users_profiles as up
join projects as p
on concat(',',p.categorysecond,',') like concat('%,',up.category,',%')
You have a really bad data format. You should not be storing lists of things in a comma-delimited field. The trouble you are having with this query is just one example of the issues. You cannot get such queries to take advantage of indexes or other optimization techniques.
Sometimes, we are stuck with other people's really bad design decisions. MySQL has the function find_in_set() with works in this case:
SELECT DISTINCT up.username, p.id
FROM users_profiles up JOIN
projects p
ON find_in_set(up.category, p.categorysecond) > 0;
Note: If you don't need the DISTINCT, then don't include it. It just incurs a performance penalty.
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
I'm developing a search function for a website. I have a table called keywords with two fields id and keyword. I have two separate search queries for AND and OR. The problem is with the AND query. It is not returning the result that I expect.
The printed SQL is :
SELECT COUNT(DISTINCT tg_id)
FROM tg_keywords
WHERE tg_keyword='keyword_1'
AND tg_keyword='keyword_2'
The count returned is 0, while if I perform the same SQL with OR instead of AND the count returned is 1. I expected the count to be 1 in both cases, and I need it to be this way as the AND results will take priority over the OR results.
Any advice will be much appreciated.
Thanks
Archie
It will always return 0, unless keyword_1=keyword_2. tg_keyword can only have one value, and when you say AND, you're asking for both conditions to be true.
It's the same, logically speaking, as asking "How many friends do I have whose name is 'JACK' and 'JILL'"? None, nobody is called both JACK and JILL.
I don't know what your table looks like and how things are related to each other, but this query makes no sense. You're returning rows where the keyword is one thing and another thing at the same time? That's impossible.
You probably have another table that links to the keywords? You should search with that, using a join, and search for both keywords. We could give you a more precise answer if you could tell us what your tables look like.
EDIT: Based on what you wrote in a comment below (please edit your question!!), you're probably looking for this:
SELECT COUNT(DISTINCT tg_id)
FROM tg_keywords AS kw1, tg_keywords AS kw2
WHERE kw1.tg_id = kw2.tg_id
AND kw1.tg_keyword='keyword_1'
AND kw2.tg_keyword='keyword_2'
your query can't work because you have a condition which is always false so no record will be selected!
tg_keyword='keyword_1' AND tg_keyword='keyword_2'
what are you trying to do? Could you post the columns of this table?
tg_keyword='keyword_1' AND tg_keyword='keyword_2'
Logically this cannot be true, ever. It cannot be both. Did you mean something like:
SELECT * FROM keywords
WHERE tg_keyword LIKE '%keyword_1%' OR tg_keyword LIKE '%keyword_2%'
ORDER BY tg_keyword LIKE '%keyword_1%' + tg_keyword LIKE '%keyword_2%' DESC;
Based on the OP's clarification:
I have a table with multiple keywords with the same id. How can I get more than one keyword compared for the same id, as the search results need to be based on how many keywords from a search array match keywords in the keywords table from each unique id. Any ideas?
I assume you're looking to return search results based on a ranking of how many of the selected keywords are a match with those results? In other words, is the ID field that multiple keywords share the ID of a potential search result?
If so, assuming you pass in an array of keywords of the form {k1, k2, k3, k4}, you might use a query like this:
SELECT ID, COUNT(ID) AS ResultRank FROM tg_keywords WHERE tg_keyword IN (k1, k2, k3, k4) GROUP BY ID ORDER BY ResultRank DESC
This example also assumes a given keyword might appear in the tables multiple times with different IDs (because a keyword might apply to multiple search results). The query will return a list of IDs in descending order based on the number of times they appear with any of the selected keywords. In the given example, the highest rank for a given ID should be 4, meaning ALL keywords apply to the result with that ID...
I think you will need to join tg_keywords to itself. Try playing around with something like
select *
from tg_keywords k1
join tg_keywords k2 on k1.tg_id = k2.tg_id
where k1.tg_keyword = 'keyword_1' and k2.tg_keyword = 'keyword_2'
Try:
SELECT tg_id
FROM tg_keywords
WHERE tg_keyword in ('keyword_1','keyword_2')
GROUP BY tg_id
HAVING COUNT(DISTINCT tg_keyword) = 2
I want to make a search engine in an intranet. Now i use this clause in PHP.
$k = explode(" ",$_GET[key]);
$sql = "select entreprise.*, employee.* where entreprise.* or employee.* like '%$k[0]%' or '%$k[1]%'";
But it seems doesn't work. Do you know where is wrong?
Thanks in advance.
Edit:
$sql = "select * from entreprise, site, salarie where entreprise.*, site.*, salarie.* like '%$k[0]%' or '%$k[1]%'";
I have modified the query clause. With this code, i think you can know what i want to do.
I want to find anything that matches the content in all the columns of entreprise table and the content in all the columns of employee table.
It's hard to exactly see what you're trying to do, but you need, in your SQL query, to specify :
on which tables you are working, with a from clause
on which fields the search has to be done, in the where clause.
how the data between employees and enterprises are related :
do you want to search for entreprises and their employees ?
for employees and there enterprises ?
for all enterprises and the employees when the employee or the enterprise contains the words ?
You could use something like this to search for entreprises that contain the word, and get their employees to :
select *
from entreprise
inner join employee on employee.id_entreprise = entreprise.id
where entreprise.name like '%word%'
or entreprise.description like '%word%';
Or, to search for employees that match the criteria and get their entreprise too :
select *
from employee
inner join entreprise on entreprise.id = employee.id_entreprise
where employee.name like '%word%';
(just some ideas -- you'll have to build from there !)
This:
$sql = "select entreprise.*, employee.* where entreprise.* or employee.* like '%$k[0]%' or '%$k[1]%'";
is not valid SQL. It is hard to guess what you want to do, but I'm trying anyway: you want to find employees, and search them by name or by enterprise that employs them. Is that the case? Or do you want to search employess and/or enterprises?
EDIT
I want to find anything that matches the content in all the columns of entreprise table and the content in all the columns of employee table.
Ok, first of all you should realize that SQL is probably not the best tool for this job. See the other commenter - his suggestions about sphinx and friends are good. But still, if you really want to:
$sql = '
SELECT e.id, e.name
FROM enterprise e
-- first, look in column1
WHERE e.column1 LIKE '."'%".$k[0]."%'".'
OR e.column1 LIKE '."'%".$k[1]."%'".'
...etc for all entries in k...
OR e.column1 LIKE '."'%".$k[N]."%'".'
-- then, look in column2
OR e.column2 LIKE '."'%".$k[0]."%'".'
OR e.column2 LIKE '."'%".$k[1]."%'".'
...and so on and so forth for all entries in $k and all columns in enterprise...
UNION ALL
SELECT s.id, s.name
FROM salarie s
WHERE ...and the same for columns of salarie...
...
UNION ALL
...any other tables you want to search...
';
As you can see, not something that makes you happy.
Another approach that might give you more joy is having some overnight job to scan all rows in the tables you're interested in, parse the texts you want to search into separate words, and store those in a keyword table, and storing the association between an object from the source database and the keyword in a separate table. You can then search the keyword table and use the id's and table names you find for a collection of keywords to build the actual query to retrieve those rows. This is what I do, and it works great. It works better because there is a relatively small amount of words that you will encounter, whereas the collection of objects is quite possible very large.