SQL Query to Join tables - mysql

I have a order table like this
id | bookId | bookAuthorId
--------------------------
1 3 2
2 2 1
3 1 2
and another table
bookId | book
---------------
1 bookA
2 bookB
3 bookC
and
bookAuthorId | author
------------------------
1 authorA
2 authorB
I want to get record from order table where id = 1 with result-set like this
id | book | author
what i tried :
select * from order
join bookId,bookAuthorId
on order.bookId = books.bookId
and order.authorId = authors.authorId
I don't know how to join these table to get the desired result.How can i do this ?

select o.id, b.book, a.author
from 'order' o
join book b on o.bookid=b.bookid
join author a on o.bookauthorid=a.bookauthorid
where o.id=1

You can do it using the where clause
select
id, book, author
from
`order`, book, author
where
`order`.bookId = book.bookId
and
`order`.authorId = author.authorId
Or
select
o.id, b.book, a.author
from
`order` o
natural join
book b
natural join
author a

select `order`.id, book.book, author.author
from `order`
join book on (`order`.bookId = book.bookId)
join author on (author.bookAuthorId = book.bookId)
where `order`.id = 1;
Assuming that bookAuthorId can be linked to bookId, otherwise you'll need to add a foreign key.

Related

select same column twice having different values for single id using mysql

I have these three tables movies, category and relationship as shown below.
movies--
-----------------------
id|name|duration|
1 |x |5 mins |
2 |y |10 mins |
----------------------
category--
-----------------------
id|type |value |
1 |genre |action |
2 |language|english |
3 |genre |thriller |
4 |language|spanish |
------------------------
relationship--
id| movie_id|category_id|
1 |1 | 2 |
2 |1 | 3 |
------------------------------
i want a query that will fetch both genre and language for the movie in a single query.
below is the expected output.
name|duration|language|genre |
x |5 mins |english |thriller|
--------------------------------
in short i want to use the type column twice.
Please help
You need mysql pivot table for that. That is turn some columns into row data. The following query will produce what you want:
SELECT
m.name,
m.duration,
MAX(IF(c.type = 'language', c.value, NULL)) AS language,
MAX(IF(c.type = 'genre', c.value, NULL)) AS genre
FROM movies AS m
INNER JOIN relationship AS r ON m.id = r.movie_id
INNER JOIN category AS c ON r.category_id = c.id
WHERE m.name = 'x'
GROUP BY m.name;
That will produce:
| name | duration | language | genre |
| x | 5 mins | english | thriller |
See DEMO
Step 1: Join all the three table together. Now you get all the category infos for each movie.
Step 2: Select what you want from the big combined table.
Step 3: Use two subquery to satisfy your special needs for language and genre.
Step 4: Add a LIMIT 1 to avoid redundant records.
The final query might be something like this:
SELECT name, duration, (SELECT value FROM t WHERE type = 'language' AND name = 'x') AS language, (SELECT value FROM t WHERE type = 'genre' AND name = 'x') AS genre
FROM
(
SELECT m.name, m.duration, c.type FROM movies AS m
JOIN relationship AS r ON m.id = r.movie_id
JOIN category AS c ON r.category_id = c.id
) AS t LIMIT 1;
Note:
Replace your own query condition for WHERE clause.
This query might not be strictly syntax correct. Please fix it by yourself.
One method uses two joins, one for each type:
select m.*, cl.value as language, cg.language as genre
from movies m join
relationships r
on m.id = r.movie_id left join
categories cl
on cl.id = r.category_id and type = 'language' left join
categories cg
on cg.id = r.category_id and type = 'genre';
Note that movies typically have only one language, but they can have multiple genres. If this is the case you will get a separate row for each genre.

Mysql select 4 tables with 3 count

I have four tables
users
ID display_name
1 Name1
2 Name2
3 Name3
A user can add books to table books
books
book_id AddedByuserID
1 1
2 1
3 2
4 3
Also a user can add ebooks to table ebooks
ebooks
ebook_id AddedByuserID
1 1
2 2
3 2
4 3
Now a user can add books only to his collection (not ebooks)
collection
userID book_id
1 1
1 2
1 3
I need an output like this:
display_name books_added ebooks_added books_in_collection
Name1 2 1 3
Name2 1 2 2
Name3 1 1 1
This is what got:
SELECT users.*, COUNT(DISTINCT collection.book_id) AS books_in_collection, COUNT(DISTINCT books.AddedByuserID) AS books_added, COUNT(DISTINCT ebooks.AddedByuserID) AS ebooks_added
FROM users LEFT JOIN collection ON users.ID = collection.userID
LEFT JOIN books ON users.ID = books.AddedByuserID
LEFT JOIN ebooks ON users.ID = ebooks.AddedByuserID
GROUP BY users.ID
ORDER BY display_name ASC
The user display_name gets displayed correct and also the collection count, but the two other counts are showing 1.
If I remove DISTINCT the collection count says 86, and the two other counts show nothing.
I try to understand LEFT join and read tutorials but i'm stuck at the moment.
I would suggest correlated subqueries:
select u.*,
(select count(*) from collection c where u.id = c.userId) as books_in_collection,
(select count(*) from books b where u.id = b.AddedByUserId) as books_added,
(select count(*) from ebooks e where u.id = e.AddedByUserId) as ebooks_added
from users u;
I don't know why you are filtering out the third user, however.

MySQL Many to Many query confusion

I've looked at a bunch of questions and solutions regarding many to many queries. I just can't seem to wrap my head around it. Maybe I'm not completely understanding the keywords in MySQL. But...
I have 3 tables. The first table is a list of peoples contact information. The second table is a list of mailing list categories. The third table is an associative table that holds the id's from the first and second table. How would I write a MySQL query to get all the contacts from the contact table that match the VIP list id (which I already have)?
Table 1 (contacts)
id | name | email
-----------------------------
1 | John | john#gmail.com
-----------------------------
2 | Jane | jane#gmail.com
-----------------------------
Table 2 (list_type)
id | list_name |
-----------------
1 | VIP's |
-----------------
2 | Generic |
-----------------
Table 3 (list_contact_joiner)
contact_id | list_type_id |
----------------------------
1 | 2 |
----------------------------
2 | 1 |
----------------------------
This is what I tried but get a syntax error
$listID = 1;
SELECT list_contact_joiner.contact_id
FROM list_contact_joiner
WHERE list_id = $listID AS lcj
INNER JOIN contact_lists AS cl
ON cl.id = lcj.contact_id
SELECT c.*
FROM contacts c
JOIN list_contact_joiner j on j.contact_id = c.id
JOIN list_type t on j.list_type_id = t.id
WHERE t.list_name = 'VIP''s'
If you already have the id of VIP's then you need to join only 2 tables
SELECT c.*
FROM contacts c
JOIN list_contact_joiner j on j.contact_id = c.id
WHERE j.list_type_id = 1
Yes the join statement is not correct. It should be something as
select
c.name,
c.email,
lt.list_type
from list_contact_joiner lcj
join contacts c on c.id = lcj.contact_id
join list_type lt on lt.id = lcj.list_type_id
where
lt.id = ?
If you are looking for data with $listID = 1; then the place holder is
lt.id = ?
Your syntax error is because all the table specification (FROM and JOIN) has to occur before the WHERE and you got your alias syntax a little messed up - this should work better:
$listID = 1;
SELECT lcj.contact_id
FROM list_contact_joiner AS lcj
INNER JOIN contact_lists AS cl
ON cl.id = lcj.contact_id
WHERE lcj.list_id = $listID
But if all you are trying to do is get the contact_id then you don't need to do any join at all...
SELECT contact_id
FROM list_contact_joiner
WHERE list_id = $listID
If you need the rest of the contact information then you might try this:
SELECT contact.*
FROM list_contact_joiner
JOIN contacts ON contacts.id = list_contact_joiner.contact_id
WHERE list_id = $listID
Note that you still don't need to get the list_type table at all.

SQL Query: How to improve?

I have two tables in a MySQL database:
Book(title, publisher, year) title is primary key
Author(name, title) title is foreign key to Book
I am trying to select the name of the Authors that published a book each year from 2000 to 2005 inclusive. This SQL query works, but is there a way to do this that makes it easier to change the date range if needed?
SELECT DISTINCT name
FROM Author
WHERE name IN (SELECT Author.name
FROM Author INNER JOIN Book ON (Author.title = Book.title)
WHERE year = 2000)
AND name IN
(SELECT Author.name
FROM Author INNER JOIN Book ON (Author.title = Book.title)
WHERE year = 2001)
AND name IN
(SELECT Author.name
FROM Author INNER JOIN Book ON (Author.title = Book.title)
WHERE year = 2002)
AND name IN
(SELECT Author.name
FROM Author INNER JOIN Book ON (Author.title = Book.title)
WHERE year = 2003)
AND name IN
(SELECT Author.name
FROM Author INNER JOIN Book ON (Author.title = Book.title)
WHERE year = 2004)
AND name IN
(SELECT Author.name
FROM Author INNER JOIN Book ON (Author.title = Book.title)
WHERE year = 2005);
Here's two ways to do it, and how another approach is wrong due to a subtle fault.
SQL Fiddle
MySQL 5.5.32 Schema Setup:
create table Book (title varchar(10), year int) ;
create table Author (name varchar(10), title varchar(10));
insert Book values
('Book1',2000),('Book2',2000),
('Book3',2000),('Book4',2000),
('Book5',2000),('Book6',2000),
('Book7',2001),('Book8',2002),
('Book9',2003),('Book10',2004),
('Book11',2005);
insert into Author values
('Author1','Book1'),('Author1','Book2'),
('Author1','Book3'),('Author1','Book4'),
('Author1','Book5'),('Author1','Book6'),
('Author2','Book6'),('Author2','Book7'),
('Author2','Book8'),('Author2','Book9'),
('Author2','Book10'),('Author2','Book11');
# author1 has written 6 books in one year
# author2 has written 1 book in every of the six years
Query 1:
# incorrect as it matches author1 who has 6 books in a single year
SELECT name from Author
INNER JOIN BOOK on Author.title = Book.Title
WHERE year IN (2000,2001,2002,2003,2004,2005)
GROUP BY name
HAVING COUNT(name) = 6
Results:
| NAME |
|---------|
| Author1 |
| Author2 |
Query 2:
# correct as it counts distinct years
SELECT name from Author
INNER JOIN BOOK on Author.title = Book.Title
WHERE year IN (2000,2001,2002,2003,2004,2005)
GROUP BY name
HAVING COUNT(DISTINCT year) = 6
Results:
| NAME |
|---------|
| Author2 |
Query 3:
# correct using relational division
SELECT DISTINCT name
FROM Author A1
INNER JOIN Book B1 ON A1.title = B1.Title
WHERE NOT EXISTS (
SELECT *
FROM Book B2
WHERE year IN (2000,2001,2002,2003,2004,2005)
AND NOT EXISTS (
SELECT *
FROM Author A2
INNER JOIN Book B3 ON A2.title = B3.Title
WHERE (A1.name = A2.name)
AND (B3.year = B2.year)
)
)
Results:
| NAME |
|---------|
| Author2 |
I would put an 'OR' clause in the where statement. It depends on how your table is set up but it should work:
SELECT DISTINCT name
FROM Author
WHERE name IN (SELECT Author.name
FROM Author INNER JOIN Book ON (Author.title = Book.title)
WHERE year = 2000)
Something like this, I didn't test it but you can group by and select only the ones that would have 6 rows:
SELECT a.name FROM Author a
INNER JOIN Book b
ON a.title = b.title
WHERE b.year BETWEEN 2000 AND 2005
GROUP BY name HAVING COUNT(a.name) = 6
I would use arguments
declare #StartYear int = 2000
declare #EndYear int = 2005
select a.name
from author a
inner join book b on a.title = b.title
where year between #StartDate and #EndDate
group by a.name
having count(distinct year) = #EndDate- #StartDate
It's easy to modify and modify itself whenever year you input

MySQL SELECT multiple rows based on specific field value and number of rows

I have three tables:
author (columns: aut_id, aut_name)
book (columns: book_id, book_title)
authorbook (linking table, columns: aut_id, book_id)
Each author can be associated with one or more books.
Each book can be associated with one or more authors.
I would like to select a book by the name(s) and the exact number of its authors.
Table structure:
author
aut_id | aut_name
1 Aname
2 Bname
3 Cname
book
book_id | book_title (the titles are identical on purpose)
1 Atitle
2 Atitle
3 Atitle
authorbook
aut_id | book_id
1 1
1 2
2 2
1 3
2 3
3 3
Here is my code (I left out the author table for better clarification):
SELECT authorbook.book_id
FROM authorbook
INNER JOIN book
ON authorbook.book_id = book.book_id
WHERE book_title='Atitle'
AND FIND_IN_SET (authorbook.aut_id,'1,2')
GROUP BY authorbook.book_id
HAVING (COUNT(authorbook.aut_id)=2)
Problem: This code not only returns the desired authorbook.book_id(2) with TWO authorbook.aut_ids (1,2) but also the authorbook.book_id(3) with THREE authorbook.aut_ids (1,2,3).
Question: How can I SELECT a book associated with exactly the authors in the FIND_IN_SET clause (and no additional authors)?
Thanks a lot for your help!
Try this:
SELECT a.book_id
FROM authorbook a
INNER JOIN book b
ON a.book_id = b.book_id
WHERE b.book_title='Atitle'
AND FIND_IN_SET (a.aut_id,'1,2')
GROUP BY a.book_id
HAVING COUNT(DISTINCT a.aut_id) = 2
AND COUNT(DISTINCT a.aut_id) = (SELECT COUNT(DISTINCT a2.aut_id)
FROM authorbook a2
WHERE a2.book_id = a.book_id);
SQL Fiddle Demo
This should work
SELECT COUNT(aut_id) AS authors, book_id FROM (SELECT authorbook.*
FROM authorbook
INNER JOIN book
ON authorbook.book_id = book.book_id
WHERE book_title='Atitle') AS t1 GROUP BY book_id HAVING authors='2'