MySQL joins confuse me and I always get syntax errors - mysql

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.

Related

ON statement in sql for joins

Good day! I'm searching the entire web for the purpose of 'on' statement in MySQL. But i can't find an exact answer about the purpose of it. For example:
SELECT Customers.CustomerName, Orders.OrderID
FROM Customers
INNER JOIN Orders
ON Customers.CustomerID=Orders.CustomerID
ORDER BY Customers.CustomerName;
What i'm trying to trace is to find the purpose of this:
ON Customers.CustomerID=Orders.CustomerID
You should not look for the ON syntax but for the inner join syntax and there you will find a lot explanations on line. E.g. http://www.w3schools.com/sql/sql_join_inner.asp
The 'ON' in this case is similar to 'Where' It defines on which fields the join is based.
I guess you are fooled by the fact that in your particular case, the joining field name is the same in both table: CustomerID.
That is not always the case, hence the necessity of specifying in SQL which fields are used for joining tables, in the ONclause.
You are joining two tables on customerId.
It means that you will join two tables side by side having same customerId from both the tables, so you could select customer and their order together at the same time.

SQL query to select based on many-to-many relationship

This is really a two-part question, but in order not to mix things up, I'll divide into two actual questions. This one is about creating the correct SQL statement for selecting a row based on values in a many-to-many related table:
Now, the question is: what is the absolute simplest way of getting all resources where e.g metadata.category = subject AND where that category's corresponding metadata.value ='introduction'?
I'm sure this could be done in a lot of different ways, but I'm a novice in SQL, so please provide the simplest way possible... (If you could describe briefly what the statement means in plain English that would be great too. I have looked at introductions to SQL, but none of those I have found (for beginners) go into these many-to-many selections.)
The easiest way is to use the EXISTS clause. I'm more familiar with MSSQL but this should be close
SELECT *
FROM resources r
WHERE EXISTS (
SELECT *
FROM metadata_resources mr
INNER JOIN metadata m ON (mr.metadata_id = m.id)
WHERE mr.resource_id = r.id AND m.category = 'subject' AND m.value = 'introduction'
)
Translated into english it's 'return me all records where this subquery returns one or more rows, without returning the data for those rows'. This sub query is correlated to the outer query by the predicate mr.resource_id = r.id which uses the outer row as the predicate value.
I'm sure you can google around for more examples of the EXIST statement

MySQL JOIN based on dynamic LIKE statement between multiple tables

I have a table called faq. This table consists from fields faq_id,faq_subject.
I have another table called article which consists of article_id,ticket_id,a_body and which stores articles in a specific ticket. Naturally there is also a table "ticket" with fields ticket_id,ticket_number.
I want to retrieve a result table in format:
ticket_number,faq_id,faq_subject.
In order to do this I need to search for faq_id in the article.a_body field using %LIKE% statement.
My question is, how can I do this dynamically such that I return with SQL one result table, which is in format ticket_number,faq_id,faq_subject.
I tried multiple configurations of UNION ALL, LEFT JOIN, LEFT OUTER JOIN statements, but they all return either too many rows, or have different problems.
Is this even possible with MySQL, and is it possible to write an SQL statement which includes #variables and can take care of this?
First off, that kind of a design is problematic. You have certain data embedded within another column, which is going to cause logic as well as performance problems (since you can't index the a_body in such a way that it will help the JOIN). If this is a one-time thing then that's one issue, but otherwise you're going to have problems with this design.
Second, consider this example: You're searching for faq_id #123. You have an article that includes faq_id 4123. You're going to end up with a false match there. You can embed the faq_id values in the text with some sort of mark-up (for example, [faq_id:123]), but at that point you might as well be saving them off in another table as well.
The following query should work (I think that MySQL supports CAST, if not then you might need to adjust that).
SELECT
T.ticket_number,
F.faq_id,
F.faq_subject
FROM
Articles A
INNER JOIN FAQs F ON
A.a_body LIKE CONCAT('%', F.faq_id, '%')
INNER JOIN Tickets T ON
T.ticket_id = A.ticket_id
EDIT: Corrected to use CONCAT
SELECT DISTINCT t.ticket_number, f.faq_id, f.faq_subject
FROM faq.f
INNER JOIN article a ON (a.a_body RLIKE CONCAT('faq_id: ',faq_id))
INNER JOIN ticket t ON (t.ticket_id = a.ticket_id)
WHERE somecriteria

SQL to Filter on multiple dimensions with a many-to-many relationship

In my rails app I have three tables to deal with the many-to-many relationship between courses and categories
courses
course_categories_courses
course_categories
I have groups of categories, and I want to allow filtering of the listing of the courses by categories through an interface like:
Location
very near
near
far
Type
short
medium
long
To search for medium types either near or far I had thought of using:
SELECT distinct courses.*
FROM `courses`
inner join course_categories on
course_categories_courses.course_category_id = course_categories.id
and (
course_categories.id in ('medium')
and course_categories.id in ('near', 'far')
)
but that's not working. Anyone able to point me in the right direction please?
You generally want to put to 'relationships' as join conditions, and values (literals) to filter by in the where clauses
ex. join condition - on course_categories_courses.course_category_id = course_categories.id
ex. where clause - where course_categories.id in ('near', 'far')
So you might want to rewrite your query that way. But more than that, how can the both of these possible be true?
(course_categories.id in ('medium') and course_categories.id in ('near', 'far'))
Is that what you intend?
You have to join both tables and you are using id field where type and location (according to your description) should be used
SELECT distinct courses.* FROM `courses`
inner course_categories_courses on course_categories_courses.course_category_id = courses.course_category_id
inner join course_categories on
course_categories.id = course_categories_courses.id
where (course_categories.type in ('medium') and course_categories.location in ('near', 'far'))
Syntactaclly the query you wrote is fine. There are two unusal things about it as other's have noted
Filter on a Inner join. (Typically done in the where but perhaps you have your reasons)
course_categories.id in ('medium'). Most would expect a number here but perhaps this is just for demonstration purposes.
The reason for it "not working"
You're getting an error that you've swept under the rug in your ruby that you're not sharing
Its working there simply are no records matching your criteria.
Ways to debug.
Run it in Workbench (or some other client) and check the results
If there are no errors and no record are returned run some queries in workbench
Select count(*) from course_categories where course_categories.id in ('medium')
Select count(*) from course_categories where course_categories.id in ('near', 'far')
If you got the results you wanted in Workbench then its probably your client (Ruby) code, bad connection string perhaps?

MySQL -- joining then joining then joining again

MySQL setup: step by step.
programs -> linked to --> speakers (by program_id)
At this point, it's easy for me to query all the data:
SELECT *
FROM programs
JOIN speakers on programs.program_id = speakers.program_id
Nice and easy.
The trick for me is this. My speakers table is also linked to a third table, "books." So in the "speakers" table, I have "book_id" and in the "books" table, the book_id is linked to a name.
I've tried this (including a WHERE you'll notice):
SELECT *
FROM programs
JOIN speakers on programs.program_id = speakers.program_id
JOIN books on speakers.book_id = books.book_id
WHERE programs.category_id = 1
LIMIT 5
No results.
My questions:
What am I doing wrong?
What's the most efficient way to make this query?
Basically, I want to get back all the programs data and the books data, but instead of the book_id, I need it to come back as the book name (from the 3rd table).
Thanks in advance for your help.
UPDATE:
(rather than opening a brand new question)
The left join worked for me. However, I have a new problem. Multiple books can be assigned to a single speaker.
Using the left join, returns two rows!! What do I need to add to return only a single row, but separate the two books.
is there any chance that the books table doesn't have any matching columns for speakers.book_id?
Try using a left join which will still return the program/speaker combinations, even if there are no matches in books.
SELECT *
FROM programs
JOIN speakers on programs.program_id = speakers.program_id
LEFT JOIN books on speakers.book_id = books.book_id
WHERE programs.category_id = 1
LIMIT 5
Btw, could you post the table schemas for all tables involved, and exactly what output (or reasonable representation) you'd expect to get?
Edit: Response to op author comment
you can use group by and group_concat to put all the books on one row.
e.g.
SELECT speakers.speaker_id,
speakers.speaker_name,
programs.program_id,
programs.program_name,
group_concat(books.book_name)
FROM programs
JOIN speakers on programs.program_id = speakers.program_id
LEFT JOIN books on speakers.book_id = books.book_id
WHERE programs.category_id = 1
GROUP BY speakers.id
LIMIT 5
Note: since I don't know the exact column names, these may be off
That's typically efficient. There is some kind of assumption you are making that isn't true. Do your speakers have books assigned? If they don't that last JOIN should be a LEFT JOIN.
This kind of query is typically pretty efficient, since you almost certainly have primary keys as indexes. The main issue would be whether your indexes are covering (which is more likely to occur if you don't use SELECT *, but instead select only the columns you need).