I am pretty new to sql and searching the forum did not give me the right answer, so I place a new one. I have three tables:
Products
product_id
product_description
Keywords
keyword_id
Keyword_description
And a reference table keywords_to_products:
reference_id
keyword_id-> relates to keywords table
product_id -> relates to products table
I am looking for two queries :
One that gives all products matching one OR more specific keywords (I think I already have this)
ie: all products having the keywords 'bolt' OR 'screw'
One that gives all products matching multiple keywords (AND) this is the one I don't get...
ie: all products having the keywords 'bolt' AND 'nut'
Although I think it is not the most exciting thing to do, I just cannot figure it out.
Besides, I am wondering if I do the right thing anyway.
I am writing an application having appr. 1.000.000 different products in it with an article number and a description. I add important words from the description to the keyword database and also add additional keywords like EAN number or equivalent productnumber which are not in the product table.
These are all connected through the keyword-to-product table.
Every keyword, even EAN numbers for example, can refer to multiple products.
The idea is searching through the keyword_to_product_table only instead of searching through multiple fields in the products table. Good idea ??
Thanks in advance for your replies..
Regards, Arno Verkley
Is this what you want?
select distinct p.Id, p.Description
from Product p
join ProductKeyword pk
on p.id = pk.ProductId
join Keyword k
on k.id = pk.KeyWordId
and k.description in ("Red", "Yellow")
http://sqlfiddle.com/#!2/b6053/3
Searching directly in your main table, say in the description column, you would have a where looking like this
WHERE
description like "%bolt%"
and description like "%nut%"
Now using a keyword table (product_id, keyword), I can suggest
SELECT
DISTINCT(p.*)
FROM Product p
JOIN ProductKeyword pk1
ON p.id = pk1.productId
JOIN ProductKeyword pk2
ON p.id = pk2.productId
WHERE
pk1.keyword = "bolt"
AND
pk2.keyword = "nut"
And yes, a keyword_to_product table sounds a good idea. You can use an index on keyword, that will keep your queries fast (when the 'like' operator will slow down a lot queries on a big table).
First of all, thanks a lot for the answers !
A little bit of both answers seem to do the trick (on the fiddle; by the way thanks for this very usefull trial and error tool, although it is not very fast ;o( )
SELECT distinct p.id, p.descriptionFROM Product p
JOIN ProductKeyword pk1
ON p.id = pk1.ProductId
join Keyword k1
on k1.id = pk1.KeyWordId
JOIN ProductKeyword pk2
ON p.id = pk2.ProductId
join Keyword k2
on k2.id = pk2.KeyWordId
WHERE
k1.description = "Yellow"
AND
k2.description = "Red"
With indexes on the id's and keyword.description will this be the fastest method ?? And what if I will be using more then two keywords ?? just add more joins and where's ??
Regards, Arno
Related
Not being an SQL wiz at all, browsing through the results here, I was unable to find a proper solution, although the problem itself is fairly simple.
Two tables:
products
id
title
strings
id
language_en
An entry in products may look like this:
id = 1
title = 10
Corresponding entry in strings:
id = 10
language_en = "myProduct"
Where as the number in products.title contains the id of a corresponding entry in strings.
I want to search products for a certain title, but those titles are stored in strings (because of multi-language capacities).
This is what i came up with:
SELECT p.* FROM products p JOIN strings s ON p.title LIKE s.language_en WHERE s.language_en LIKE "myProduct"
Unfortunately, this does not yield any proper results. Obviously i have trouble understanding the concept behind the join, but even reading some articles on the concept does not get me there. It's not my pair of shoes.
In your sql condition may be wrong i think, i modified that sql.
select p.* FROM products p JOIN strings s ON p.title = s.id and s.language_en = "Product name"
you can execute and see the result.
Thank you.
The join is wrong - it's comparing p.title to s.language_en instead of s.id which you described should match it.
Also note that when used without a wildcard, the like operator is essentially equivalent to =, and it may make the code easier to read if you use it directly:
SELECT p.*
FROM products p
JOIN strings s ON p.title = s.id
WHERE s.language_en = 'myProduct'
I've searched a bit but haven't found exactly what I'm looking for, so far. Basically I have a MySQL database with a couple tables (keywords, company and link tables). I want to be able to supply an array of keywords and find the associated companies. When I run the second query without the WHERE IN clause, it works. When I supply an array, it doesn't.
select keywords.idkeywords into #keyId
from keywords where
keywords.keyword IN ('Entertainment', 'Public');
select distinct company.company_name
from keywords, keyword_to_company, company
where keyword_to_company.keywordId = #keyId
and keyword_to_company.compId = company.idcompany;
Your query just doesn't make sense. First, you are trying to put multiple values in #keyid, but you can't do that. And, MySQL doesn't have the concept of table variables. You could use a temporary table.
Then the second query is worse. Does this query work for you?
select distinct c.company_name
from keywords k natural join
keyword_to_company k2c natural join
company c
where k.keyword IN ('Entertainment', 'Public') and
k2c.compId = company.idcompany;
I'm only using natural join because you don't specify the join keys. In general, you should always specify the columns being joined, using either on or using.
Thanks...
Your query didn't work..
This query does work however. Althought #keyId returns multiple rows, the query succeeds and results in a listing of associated companies. i agree that it shouldn't work, but it does.
select keywords.idkeywords into #keyId from keywords where
keywords.keyword = 'Entertainment'
and
keywords.keyword = 'Public';
select distinct company.company_name from keywords, keyword_to_company, company
where
keyword_to_company.keywordId = #keyId
and
keyword_to_company.compId = company.idcompany;
I need to fetch some data from a MySQL db. I have the function working using two separate, simple queries, but i'm sure this is probably achievable with one query using a JOIN. SQL isn't my strong point and I keep getting syntax errors when I try. Sure, I could leave it as it is, why not, it works. But i would prefer to see a real world example of how they can be joined so i can try and apply it on other queries in the future.
Query one is:
select manufacturers_id from products where products_name = product a
The result is then put into a variable and used in the following
select manufacturers_name from manufacturers where manufacturers id = $man_id
So, basically, the products table holds the manufacturers_id, which we need to collect for a given product to find out what the manufacturers name is from the manufacturers table.
manufacturers_id is the common field.
Try this:
SELECT b.manufacturers_name
FROM products a
LEFT JOIN manufacturers b ON a.manufacturers_id = b.manufacturers_id
WHERE a.products_name = 'PRODUCT NAME'
Below is a diagram of SQL Joins
Image Source
Try this:
select m.manufacturers_name from products p, manufacturers m
where p.products_name = 'productA' and p.manufacturers_id = m.id
I believe this is what you're looking for
SELECT manufacturers.manufacturers_name
FROM products
JOIN manufacturers on manufacturers_id=products.manufacturers_id
WHERE manufacturers_name='product a'
With a join, you just need to follow this syntax, and remember that you have to set the matching columns equal to each other so you don't end up with invalid rows.
I'd show you how the equivalent of this using table joins, but I really don't want to encourage the use of that syntax, even by accident.
I've got three tables.
Table 1 is packages.
Table 2 is package_to_keyword.
Table 3 is keywords.
Packages can be connected to multiple keywords. So if I query package_to_keyword Joining keywords and packages I can search for all packages that relate to a certain keyword. That's the part I understand.
NOW... my question is, how do I retrieve packages that match a LIST of keywords? Right now, in php, I loop a sql statement and then loop through all the results for each keyword and do an array_intersect() to filter down to the packages that show up in all the result sets. However, I'm sure this is bad, because I'm running a query for each keyword when I'm certain SQL is built to handle this type of relationship, I'm just not sure what type of query to perform.
The key is the list of keywords can be any number of words. If I use something like IN ('keyword','array','returns','all','results') I just get a list for all the packages that have a relationship with ANY of the keywords when I just want packages that have a relationship with ALL of the keywords.
Thoughts?
select title
from packages p
inner join pack_to_tag pt on p.index = pt.pIndex
inner join keyworks w on w.index = pt.kindex
where word in ('keyword','array','returns','all','results')
group by title
having count(*) = 5
First, the "PreQuery" (qualified products result) looks only the products joined to keywords that have ANY of the keywords you are looking for, and will ultimately return 1 or more entries. The GROUP BY then confirms however many you ARE EXPECTING... Then join to products for final results.
select
p.*
from
( select ptt.pIndex
from pack_to_tag ptt
join keywords k
on ptt.kindex = k.index
and k.word in ( 'word1', 'word2', 'word3' )
group by
ptt.pIndex
having
count(*) = 3 ) QualifiedProducts
join Products p
on QualifiedProducts.pIndex = p.index
I'm using H2, and I have a database of books (table Entries) and authors (table Persons), connected through a many-to-many relationship, itself stored in a table Authorship.
The database is fairly large (900'000+ persons and 2.5M+ books).
I'm trying to efficiently select the list of all books authored by at least one author whose name matches a pattern (LIKE '%pattern%'). The trick here is that the pattern should severly restrict the number of matching authors, and each author has a reasonably small number of associated books.
I tried two queries:
SELECT p.*, e.title FROM (SELECT * FROM Persons WHERE name LIKE '%pattern%') AS p
INNER JOIN Authorship AS au ON au.authorId = p.id
INNER JOIN Entries AS e ON e.id = au.entryId;
and:
SELECT p.*, e.title FROM Persons AS p
INNER JOIN Authorship AS au ON au.authorId = p.id
INNER JOIN Entries AS e ON e.id = au.entryId
WHERE p.name like '%pattern%';
I expected the first one to be much faster, as I'm joining a much smaller (sub)table of authors, however they both take as long. So long in fact that I can manually decompose the query into three selects and find the result I want faster.
When I try to EXPLAIN the queries, I observe that indeed they are very similar (a full join on the tables and only then a WHERE clause), so my question is: how can I achieve a fast select, that relies on the fact that the filter on authors should result in a much smaller join with the other two tables?
Note that I tried the same queries with MySQL and got results in line with what I expected (selecting first is much faster).
Thank you.
OK, here is something that finally worked for me.
Instead of running the query:
SELECT p.*, e.title FROM (SELECT * FROM Persons WHERE name LIKE '%pattern%') AS p
INNER JOIN Authorship AS au ON au.authorId = p.id
INNER JOIN Entries AS e ON e.id = au.entryId;
...I ran:
SELECT title FROM Entries e WHERE id IN (
SELECT entryId FROM Authorship WHERE authorId IN (
SELECT id FROM Persons WHERE name LIKE '%pattern%'
)
)
It's not exactly the same query, because now I don't get the author id as a column in the result, but that does what I wanted: take advantage of the fact that the pattern restricts the number of authors to a very small value to search only through a small number of entries.
What is interesting is that this worked great with H2 (much, much faster than the join), but with MySQL it is terribly slow. (This has nothing to do with the LIKE '%pattern%' part, see comments in other answers.) I suppose queries are optimized differently.
SELECT * FROM Persons WHERE name LIKE '%pattern%' will always take LONG on a 900,000+ row table no matter what you do because when your pattern '%pattern%' starts with a % MySql can't use any indexes and should do a full table scan. You should look into full-text indexes and function.
Well, since the like condition starts with a wildcard it will result in a full table scan which is always slow, no internal caching can take place.
If you want to do full text searches, mysql is not the best bet you have. Look into other software (solr for instance) to solve this kind of problems.