I have written the following query:
select title, branch_name, no_of_copies
from Book_Copies BC
inner join Book B on BC.book_id = B.book_id
inner join Library_Branch LB on BC.branch_id = LB.branch_id
where title = 'Grapes of Wrath';
But my issue is that this displays only the titles and branch names that have > 0 no_of_copies. How do I display ones that do not have a no_of_copies row? (Where it would be equal to 0).
Here is the table I currently get:
+-----------------+-------------+--------------+
| title | branch_name | no_of_copies |
+-----------------+-------------+--------------+
| Grapes of Wrath | Central | 5 |
| Grapes of Wrath | Allentown | 2 |
+-----------------+-------------+--------------+
This is what I need it to be:
+-----------------+-------------+--------------+
| title | branch_name | no_of_copies |
+-----------------+-------------+--------------+
| Grapes of Wrath | Central | 5 |
| Grapes of Wrath | Allentown | 2 |
| Grapes of Wrath | Sharpstown | 0 |
+-----------------+-------------+--------------+
You need to use an outer join instead starting from the book table. Perhaps something like this:
select title, branch_name, no_of_copies
from Book B
left join Book_Copies BC on BC.book_id = B.book_id
left join Library_Branch LB on BC.branch_id = LB.branch_id
where title = 'Grapes of Wrath';
Reading your comments, it sounds like you want to use a cross join between book and library_branch to get all combinations of books and branches (otherwise known as a cartesian product). Then outer join those results to the lookup table:
select title, branch_name, coalesce(no_of_copies,0) copies
from Book B
cross join Library_Branch LB
left join Book_Copies BC on BC.book_id = B.book_id
and BC.branch_id = LB.branch_id
where title = 'Grapes of Wrath';
Related
How do I build a joint to select either table
Table jobs
Id | name | salary | company | type
1 | php | 17.850 | 5 | 1
2 | mysql | 4.500 | 89 | 2
2 | nodejs | 7.500 | 89 | 1
Table Company
Id | name | Area | status
1 | Facebook| Developer| 1
2 | Google | Manager | 1
Table Candidate
Id | name | City | phone
1 | Alan Kout | Nevada | 1 555 6666
2 | Wagner Mom | L.A. | 1 444 8965
My query mysql, inner join candidate or company
If type == 1 in table jobs INNER JOIN ON table company
If type == 2 in table jobs INNER JOIN ON table candidate
Example
SELECT * FROM table_jobs
IF(table_jobs.type == 1, INNER JOIN table_company, INNER JOIN table_candidate)
This is possible?
You can achieve this using a LEFT JOIN instead of an INNER JOIN:
SELECT *
FROM table_jobs tj
LEFT JOIN table_company tco ON tj.type = 1 AND tco.id = tj.id
LEFT JOIN table_candidate tca ON tj.type = 2 AND tca.id = tj.id
This will join to table_company where the type is 1, and table_candidate where the type is 2.
You can then SELECT whichever columns are needed from each table as appropriate.
Use left join and coalesce():
SELECT tj.*,
coalesce(co.name, ca.name) as name,
. . .
FROM table_jobs tj LEFT JOIN
table_company co
ON co.id = tj.id and tj.type = 1 LEFT JOIN
table_candidate ca
ON ca.id = tj.id and tj.type = 2;
If you want both joins in one result you can use the UNION operator
SELECT *
FROM table_jobs INNER JOIN table_company
WHERE table_jobs.type=1
UNION
SELECT *
FROM table_jobs INNER JOIN table_candidate
WHERE table_jobs.type=2
I have three tables like this:
Animal
| id | cat_id | horse_id | dog_id |
|:--:|:------:|:--------:|--------|
| 1 | 15 | 16 | 17 |
Cat
| id | lang_id |
|:--:|:-------:|
| 15 | 3716 |
Horse
| id | lang_id |
|:--:|:-------:|
| 16 | 3717 |
Dog
| id | lang_id |
|:--:|:-------:|
| 17 | 3718 |
Language
| id | en |
|:----:|:--------------:|
| 3716 | BRAVE LEGEND |
| 3717 | N Rawiller |
| 3718 | DRAGON GENERAL |
I want to get all the animals en name from Language table through each animal's table lang_id. It would be like by using Animal: cat_id -> Cat: lang_id -> Language: en. The final results would be like:
| animal_id | cat_name | horse_name | dog_name |
|:---------:|:------------:|:----------:|:--------------:|
| 1 | BRAVE LEGEND | N Rawiller | DRAGON GENERAL |
I am trying to use this:
select animal.id, lang.* from animal
left join cat on animal.cat_id = cat.id
left join horse on animal.horse_id = horse.id
left join dog on animal.dog_id = dog.id
left join lang on cat.lang_id = lang.id or (horse.lang_id = lang.id) or (dog.lang_id = lang.id)
where animal.id = 1
But I can't get cat_name, dog_name, horse_name because it's all coming from the same Language table.
Try below query:
You need to JOIN lang table multiple times, using one JOIN with multiple OR will not give you desired result,
SELECT animal.id, lang.en as cat_name,l1.en as horse_name,l2.en as dog_name
FROM animal
LEFT JOIN cat ON animal.cat_id = cat.id
LEFT JOIN horse ON animal.horse_id = horse.id
LEFT JOIN dog ON animal.dog_id = dog.id
LEFT JOIN lang ON cat.lang_id = lang.id
LEFT JOIN lang l1 ON horse.lang_id = l1.id
LEFT JOIN lang l2 ON dog.lang_id = l2.id
WHERE animal.id = 1
Try this:
select animal.id, lang1.cat_name, lang2.horse_name, lang3.dog_name
from animal
left join cat on animal.cat_id = cat.id
left join horse on animal.horse_id = horse.id
left join dog on animal.dog_id = dog.id
left join lang AS lang1 on cat.lang_id = lang1.id
left join lang AS lang2 ON horse.lang_id = lang2.id
left join lang AS lang3 ON (dog.lang_id = lang3.id)
where animal.id = 1
Try this:
SELECT a.id, lang1.en as cat_name,lang2.en as horse_name,lang3.en as dog_name
FROM `animal` a
LEFT JOIN cat c ON c.id = a.cat_id
LEFT JOIN LANGUAGE l on l.id=c.lang_id
LEFT JOIN dog d ON d.id = a.dog_id
LEFT JOIN horse h ON h.id = a.horse_id
LEFT JOIN language lang1 ON c.lang_id=lang1.id
LEFT JOIN language lang2 ON h.lang_id=lang2.id
LEFT JOIN language lang3 ON d.lang_id=lang3.id
I have a journal system that I am currently developing.
There are some tables:
Table 1: issues
issueid | issue_title
1 | November 2016
Table 2: articles
articleid | issueid | article_title
1 | 1 | Yet another article title
Table 3: authors
authorid | firstname | lastname
1 | John | Doe
2 | Jack | Foe
Table 4: articlesauthors
authorarticleid | authorid | articleid
1 | 1 | 1
2 | 2 | 1
The table articlesauthors have the records which author authoring which article.
Now I need to get all the articles with the authors for a specific issue. It should be something like this but cannot figure it out, as I mentioned:
SELECT i.issue_title, ar.article_title, au.firstname, au.lastname
FROM articles ar
INNER JOIN articlesauthors aa1 ON aa1.articleid = ar.articleid
INNER JOIN articlesauthors aa2 ON aa2.articleid = au.authorid
INNER JOIN issues i ON i.issueid = ar.issueid
WHERE i.issueid = 1
Well I am stuck here that I do not know where the type authors table in the query.
Desired output should be like this:
issue_title | article_title | firstname | lastname
November 2... | Yet anothe... | John | Doe
November 2... | Yet anothe... | Jack | Foe
You can also check the modified SQL query :
SELECT ar.article_title, aut.firstname, aut.lastname
FROM issues as issue
INNER JOIN articles as ar ON ar.issueid = issue.issueid
INNER JOIN articlesauthors as aa ON ar.articleid = aa.articleid
INNER JOIN authors as aut ON aut.authorid = aa.authorid
WHERE issue.issueid = 1
This will result in expected output.
according to your posted query, your are using three tables only. you want to get auther firstname and lastname but your are not joining auther table(you are selecting au.firstname ,au.lastname but au id not defined)..try with the below query
select article_title,firstname,lastname from articles
inner join articlesauthors on articlesauthors.articleid=articles.articleid
inner join auther on auther.authorid=articlesauthors.authorid
inner join issue on issue.issueid=articles.issueid
Well thinking a few minutes brought me the solution.
SELECT i.issue_title, ar.article_title, au.firstname, au.lastname
FROM articles ar
INNER JOIN articlesauthors aa ON aa.articleid = ar.articleid
INNER JOIN authors au ON aa.authorid = au.authorid
INNER JOIN issues i ON i.issueid = ar.issueid
WHERE i.issueid = 1
Now this query brings me correct dataset.
I have this tables:
I want to show an article where its subject related term is 'milk'.
subject_catalog table dictionary:
index_key = primary key
subject = takes any words
rt_key = serves as 'related term' foreign key to its own.
sample data for subject_catalog:
|index_key|subject|rt_key|
|------------------------|
| 1 | tea | null |
| 2 | milk | 1 |
|------------------------|
sample data for article:
|article_key|title |pages|
|----------------------------|
| 1 | article_1| 5 |
| 2 | article_2| 3 |
|----------------------------|
sample data for article_subject:
|article_key|index_key|
|---------------------|
| 1 | 1 |
|---------------------|
here is my trial query but it wont show any article:
SELECT
`article`.`title`
FROM
`article_subject`
INNER JOIN `article`
ON (`article_subject`.`article_key` = `article`.`article_key`)
INNER JOIN `subject_catalog`
ON (`article_subject`.`index_key` = `subject_catalog`.`index_key`)
INNER JOIN `subject_catalog` AS `subject_catalog_1`
ON (`subject_catalog_1`.`rt_key` = `subject_catalog`.`index_key`)
WHERE `subject_catalog_1`.`subject` LIKE 'milk%'
Try this
SELECT article.title
FROM article_subject
LEFT JOIN article USING (article_key)
LEFT JOIN subject_catalog USING (index_key)
LEFT JOIN subject_catalog sc2 ON subject_catalog.index_key = sc2.rt_key
WHERE subject_catalog.subject LIKE 'milk%' OR sc2.subject LIKE 'milk%'
http://sqlfiddle.com/#!2/7d5f5/3/0
Select A.title from article A inner Join article_subject S
On A.article_key =S.article_key inner join subject_catalog C
on C.index_key = C.index_key where C.rt_key =1
SQLFIDDLE
So I want to do the following for a project.
I have 3 tables. First two concern us now (the third is for your better understanding):
author {id, name}
authorship {id, id1, id2}
paper {id, title}
authorship connects author with paper and authorship.id1 refers to author.id, authorship.id2 refers to paper.id.
What I want to do is make a graph with a node for each author and edge that is determined by the amount of common papers between two authors.
w=1 - union_of_common_papers/intersection_of_common_papers
So what I have built (with some help from stackoverflow) an sql script that returns all couples of co-authors plus the amount of union and intersection of common papers. After that I will use the data with java. It's the following:
SELECT DISTINCT a1.name, a2.name, (
SELECT concat(count(a.id2), ',', count(DISTINCT a.id2))
FROM authorship a
WHERE a.id1=a1.id or a.id1=a2.id) as weight
FROM authorship au1
INNER JOIN authorship au2 ON au1.id2 = au2.id2 AND au1.id1 <> au2.id1
INNER JOIN author a1 ON au1.id1 = a1.id
INNER JOIN author a2 ON au2.id1 = a2.id;
this does my job and returns a list like:
+-----------------+---------------------+---------+
| name | name | weight |
+-----------------+---------------------+---------+
| Kurt | Michael | 161,157 |
| Kurt | Miron | 138,134 |
| Kurt | Manish | 19,18 |
| Roy | Gregory | 21,20 |
| Roy | Richard | 74,71 |
....
where in weight I can see 2 numbers a,b where b is intersection an b-a is the union of the common papers.
but this takes a lot of time.
And all the overhead is by this extra subselect
(SELECT concat(count(a.id2), ',', count(DISTINCT a.id2))
FROM authorship a
WHERE a.id1=a1.id or a.id1=a2.id) as weight
without this line all records (1M+) were returned in less than 2mins.
with this line 50 records need more than 1.5mins
I use mysql on linux through command line
Any ideas how I can optimize it?
author has ~130,000 records
authorship ~1,300,000 records
query should return ~1,200,000 records
This is what explain returns for this query. don't know how to use it.
+----+--------------------+-------+--------+---------------------+-----------+---------+--------------+---------+-----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+-------+--------+---------------------+-----------+---------+--------------+---------+-----------------+
| 1 | PRIMARY | a1 | ALL | PRIMARY | NULL | NULL | NULL | 124768 | Using temporary |
| 1 | PRIMARY | au1 | ref | NewIndex1,NewIndex2 | NewIndex1 | 5 | dblp.a1.ID | 4 | Using where |
| 1 | PRIMARY | au2 | ref | NewIndex1,NewIndex2 | NewIndex2 | 5 | dblp.au1.id2 | 1 | Using where |
| 1 | PRIMARY | a2 | eq_ref | PRIMARY | PRIMARY | 4 | dblp.au2.id1 | 1 | |
| 2 | DEPENDENT SUBQUERY | a | ALL | NewIndex1 | NULL | NULL | NULL | 1268557 | Using where |
+----+--------------------+-------+--------+---------------------+-----------+---------+--------------+---------+-----------------+
You should be able to get your data directly from the joins in the outer query.
You can count the number of papers in common by counting the distinct id2 where that is the same for both authors.
You can count the total number of papers as the number of distinct papers for each author minus the ones in common (because otherwise, these would be counted twice):
SELECT a1.name, a2.name,
COUNT(distinct case when au1.id2 = au2.id2 then au1.id2 end) as CommonPapers,
COUNT(distinct au1.id2) + COUNT(distinct au2.id2) - COUNT(distinct case when au1.id2 = au2.id2 then au1.id2 end) as TotalPapers
FROM authorship au1 INNER JOIN
authorship au2
ON au1.id2 = au2.id2 AND au1.id1 <> au2.id1 INNER JOIN
author a1
ON au1.id1 = a1.id INNER JOIN
author a2
ON au2.id1 = a2.id
group by a1.name, a2.name;
In your data structure, id1 and id2 are lousy names. Have you considered something like idauthor and idpaper or something like that?
The above query counts the intersection correctly, but not the total, because of the initial inner join. one way around this is a full outer join, but that is not allowed in MySQL. We can do this with additional subqueries:
SELECT a1.name, a2.name,
COUNT(distinct case when au1.id2 = au2.id2 then au1.id2 end) as CommonPapers,
(ap1.NumPapers + ap2.NumPapers - COUNT(distinct case when au1.id2 = au2.id2 then au1.id2 end)
) as TotalPapers
FROM authorship au1 INNER JOIN
authorship au2
ON au1.id2 = au2.id2 AND au1.id1 <> au2.id1 INNER JOIN
author a1
ON au1.id1 = a1.id INNER JOIN
author a2
ON au2.id1 = a2.id inner join
(select au.id1, count(*) as numpapers
from authorship au
) ap1
on ap1.id1 = au1.id1 inner join
(select au.id1, count(*) as numpapers
from authorship au
) ap2
on ap2.id1 = au2.id1 inner join
group by a1.name, a2.name;