I need to get rows out from article and users table when the slug appears in my highlight table.
Highlight Table
id | slug
1 blue
2 green
Article Table
id | slug | title
1 blue
2 pink
User Table
id | slug | name
1 blue
2 green
3 brown
Heres my query:
SELECT slug from highlight_table
INNER JOIN article_table ON highlight_table.slug = article_table.slug
INNER JOIN user_table ON highlight_table.slug = user_table.slug
I would hope to get id 1 from article table and id 1 and 2 from users table.
The issue is Im getting nothing back from the query.
The query has an error because your SELECT slug is ambiguous. Your column slug appears in all of your tables so MySQL doesn't know which column to return. You need to do
SELECT `highlight_table`.`slug` from `highlight_table`
This will tell MySQL to only return the slug column from the highlight_table.
You should then only get 1 row which is blue, because blue exists in all three tables. Changing to LEFT JOIN for both article and user tables would get you 2 results back (green and blue) as INNER JOIN basically works as an AND and LEFT JOIN works more like an OR
Update!
Based on the final lot of information here is a query that does work:
SELECT highlight.slug from highlight
LEFT JOIN article ON highlight.slug = article.slug
LEFT JOIN user ON highlight.slug = user.slug
WHERE
article.slug IS NOT NULL OR user.slug IS NOT NULL
Another example of doing this:
SELECT `highlight`.`slug` from `highlight`
WHERE `highlight`.`slug` IN (SELECT `user`.`slug` FROM `user` UNION SELECT `article`.`slug` FROM `article`)
OR
SELECT `highlight`.`slug` from `highlight`
INNER JOIN (SELECT `user`.`slug` FROM `user` UNION SELECT `article`.`slug` FROM `article`) AS `allslugs` ON `highlight`.`slug` = `allslugs`.`slug`
Another update, I call this one "fun with joins"
SELECT `highlight`.`slug` from `highlight`
RIGHT JOIN `user` ON `highlight`.`slug` = `user`.`slug`
LEFT JOIN `article` ON `highlight`.`slug` = `article`.`slug`
WHERE
`highlight`.`slug` IS NOT NULL
Try changing your query to qualify the column name in select list
SELECT h.`slug` from HighlightTable h
INNER JOIN ArticleTable a ON h.`slug` = a.`slug`
INNER JOIN UserTable u ON h.`slug` = u.`slug`;
Can't reproduce the issue. See This Fiddle
per your latest comment you need a LEFT JOIN query like
SELECT h.`slug` from HighlightTable h
LEFT JOIN ArticleTable a ON h.`slug` = a.`slug`
LEFT JOIN UserTable u ON h.`slug` = u.`slug`;
Then do a separate JOIN and UNION the result set
SELECT h.`slug` from HighlightTable h
INNER JOIN ArticleTable a ON h.`slug` = a.`slug`
UNION
SELECT h.`slug` from HighlightTable h
INNER JOIN UserTable u ON h.`slug` = u.`slug`;
Related
Hi I have the following tables and columns.
movie: ID, title
person: ID, name
involved: personID, movieID
I need to answer the question:
"Which movies have either John Travolta or Uma Thurman, but not both starred in?"
I couldn't figure out how to do this without creating new tables, so I made 2 new tables. And tried to do the full outer join on, where you dont get intersecting results. I found out that you can't do full outer joins in mysql but had to do a left join, unioned with a right join. I tried this but don't get the results I wanted at all. I have been stuck for a while now. Can anyone point me in the right direction?
This is what I have so far.
DROP TABLE IF EXISTS Umatable;
DROP TABLE IF EXISTS Johntable;
CREATE TABLE Umatable(title VARCHAR(500));
CREATE TABLE Johntable(title VARCHAR(500));
INSERT INTO Umatable
SELECT m.title
FROM movie m, person p, involved i
WHERE p.name = "Uma Thurman"
AND p.id = i.personid
AND m.id = i.movieiD;
INSERT INTO Johntable
SELECT m.title
FROM movie m, person p, involved i
WHERE p.name = "John Travolta"
AND p.id = i.personid
AND m.id = i.movieiD;
SELECT *
FROM Umatable
LEFT JOIN Johntable ON Umatable.title = Johntable.title
WHERE Johntable.title IS NULL OR Umatable.title IS NULL
UNION
SELECT *
FROM Umatable
RIGHT JOIN Johntable ON Umatable.title = Johntable.title
WHERE Johntable.title IS NULL OR Umatable.title IS NULL
I would do this using aggregation and having:
select i.movieId
from involved i join
person p
on p.id = i.personId
group by i.movieId
having sum(p.name in ('John Travolta', 'Uma Thurman')) = 1;
A count(*) inside a correlated subquery will work:
select *
from movie m
where 1 = (select count(*)
from involved i
join person p
on p.ID = i.personID
and p.name IN ('John Travolta', 'Uma Thurman')
where i.movieID = m.ID)
SQLFiddle Demo
A bit of a newbie question, probably an INNER JOIN with an "AS" statement, but I can't figure it out...
This is for a MYSQL based competition app. I want to select the "img_title" for both img_id1 and img_id2. I can't figure out how to do it and still see which title is assigned to the associated _id1 or _id2.
My tables:
competitions
comp_id
img_id1
img_id2
on_deck
img_id
img_title
Desired results:
comp_id | img_id1 | img_title1 |img_id2 | img_title2
You need a join for each image:
SELECT comp.comp_id, img1.img_id, img1.img_title, img2.img_id, img2.img_title
FROM competitions comp
INNER JOIN on_deck img1 ON img1.img_id = comp.img_id1
INNER JOIN on_deck img2 ON img2.img_id = comp.img_id2
LEFT JOIN if img_id1 or img_id2 can be NULL.
select comp_id, img_id1, b.img_title as img_title1,
img_id2, b2.img_title as img_title2
from competitions a
left outer join on_deck b on b.img_id = a.img_id1
left outer join on_deck b2 on b2.img_id = a.img_id2
switch let outer join to inner join if you want to exclude rows in competitions that do not have two matching img_ids
This query should give you the results you want. This also assumes that comp.img_id1 and comp.img_id2 are never NULL.
SELECT comp.comp_id
, comp.img_id1
, deck1.img_title AS img_title1
, comp.img_id2
, deck2.img_title AS img_title2
FROM competitions AS comp
JOIN on_deck deck1 ON comp.img_id1 = deck1.img_id
JOIN on_deck deck2 ON comp.img_id2 = deck2.img_id
If you have plan on having a NULL or empty string comp.img_id1 and/or comp.img_id2 fields, you'll need to do some left joins.
I have the following query which returns data only if the join exists. How do I return from the last joined table (#__unis) datas, even if there is no relationship between those tables without to write another query?
select * from #__unis_faculties AS faculty
join #__unis_subjects AS subject ON subject.faculty = faculty.id
join #__unis AS uni ON uni.id= subject.university
where uni.id = 1
table structure http://sqlfiddle.com/#!2/19add
use LEFT JOIN instead of join
select * from #__unis_faculties AS faculty
join #__unis_subjects AS subject ON subject.faculty = faculty.id
right join #__unis AS uni ON uni.id= subject.university
where uni.id = 1
Try this..
select * from #__unis_faculties AS faculty
join #__unis_subjects AS subject ON subject.faculty = faculty.id
left join #__unis AS uni ON ( uni.id= subject.university AND uni.id = 1 )
I have a problem with joining some tables, heres my structure:
tbl_imdb:
fldID fldTitle fldImdbID
1 Moviename 0000001
tbl_genres:
fldID fldGenre
1 Action
2 Drama
tbl_genres_rel:
fldID fldMovieID fldGenreID
1 1 1
2 1 2
What I’m trying to do is a query that will find all movies that is both an action movie and drama, is this possible to do without a subquery, if so, how?
What I'm trying right now is:
SELECT tbl_imdb.*
FROM tbl_imdb
LEFT JOIN tbl_imdb_genres_rel ON ( tbl_imdb.fldID = tbl_imdb_genres_rel.fldMovieID )
LEFT JOIN tbl_imdb_genres ON ( tbl_imdb_genres_rel.fldGenreID = tbl_imdb_genres.fldID )
WHERE tbl_imdb_genres.fldGenre = 'Drama'
AND tbl_imdb_genres.fldGenre = 'Action';
But this dosnt work, however it does work if I only keep one of the two WHERE's, but thats not what I want.
Two ways to do it:
1
SELECT tbl_imdb.*
FROM tbl_imdb
INNER JOIN tbl_genres_rel rel_action
ON tbl_imdb.fldID = rel_action.fldMovieID
INNER JOIN tbl_genres genre_action
ON rel_action.fldGenreId = genre_action.fldID
AND 'Action' = genre_action.fldGenre
INNER JOIN tbl_genres_rel rel_drama
ON tbl_imdb.fldID = rel_drama.fldMovieID
INNER JOIN tbl_genres genre_drama
ON rel_drama.fldGenreId = genre_drama.fldID
AND 'Drama' = genre_drama.fldGenre
This method is on the same path as your original solution. 2 differences:
The join should be inner, not left because you're trying to get movies that certainly have the corresponding genre entry
Since you want to find 2 different generes, you'll have to do the join with tbl_genres_rel and tbl_genres twice, once for each particular genre you're interested in.
2
SELECT tbl_imdb.*
FROM tbl_imdb
INNER JOIN tbl_genres_rel
ON tbl_imdb.fldID = tbl_genres_rel.fldMovieID
INNER JOIN tbl_genres
ON tbl_genres_rel.fldGenreId = tbl_genres.fldID
AND tbl_genres.fldGenre IN ('Action', 'Drama')
GROUP BY tbl_imdb.fldID
HAVING COUNT(*) = 2
Again, the basic join plan is the same. Difference here is that we join to the tbl_genres_rel and tbl_genres path just once. This on itself fetches all genres for one film, and then filters for the one's you're interested in. The ones that qualify will now have 2 rows for each distinct value of tbl_imdb.fldId. The GROUP BY aggregates on that, flattening that into one row. By asserting in the HAVING clause that we have exactly 2 rows, we ensure that we keep only those rows that have both the genres.
(Note that this assumes that there is a unique constraint on tbl_genres_rel over {fldMovieID, fldGenreID}. If such a constraint is not present, you should consider adding it.)
LEFT JOIN is not applicable in your case because records should exist on both tables. And you need to count the instances of the movie
SELECT *
FROM tbl_imdb a
INNER JOIN tbl_genres_rel b
on a.fldID = fldMovieID
INNER JOIN tbl_genres c
on c.fldGenreID = b.fldID
WHERE c.fldGenre IN ('Drama', 'Action')
GROUP BY a.Moviename
HAVING COUNT(*) > 1
I have a situation where a property table holds an address id (from the g_addresses table) and an applicant table also holds an address id from the g_addresses.
I'd like to left join these together but select all the fields in the table.
I know of using 'as' to make an alias for fields, but is there any way to produce an alias for a whole table?
SELECT *
FROM (`reference`)
LEFT JOIN `applicants` ON `applicants`.`id` = `reference`.`applicant_id`
LEFT JOIN `g_people` applicant_person ON `applicant_person`.`id` = `applicants`.`person_id`
LEFT JOIN `g_addresses` applicant_address ON `applicant_address`.`id` = `applicants`.`address_id`
LEFT JOIN `properties` ON `properties`.`id` = `reference`.`property_id`
LEFT JOIN `g_addresses` property_address ON `property_address`.`id` = `properties`.`address_id`
WHERE `reference`.`id` = 4
This produces a result containing only one address row and not both,
The row that is returned is the row from the final join and not the one previously, indicating it is overwriting when it is returned.
I don't think you should use masked references, like * or `reference`.*, in your case, because you may end up with a row set containing identical column names (id, address_id).
If you want to pull all the columns from the joined tables, you should probably specify them individually in the SELECT clause and assign a unique alias to every one of them:
SELECT
ref.`id` AS ref_id,
ref.`…` AS …,
…
app.`id` AS app_id,
…
FROM `reference` AS ref
LEFT JOIN `applicants` AS app ON app.`id` = ref.`applicant_id`
LEFT JOIN `g_people` AS ape ON ape.`id` = app.`person_id`
LEFT JOIN `g_addresses` AS apa ON apa.`id` = app.`address_id`
LEFT JOIN `properties` AS pro ON pro.`id` = ref.`property_id`
LEFT JOIN `g_addresses` AS pra ON pra.`id` = pro.`address_id`
WHERE ref.`id` = 4
Be more specific about columns you select
SELECT
applicant_address.*,
property_address.*,
applicants.*,
applicant_person.*,
properties.*
FROM (`reference`)
LEFT JOIN `applicants` ON `applicants`.`id` = `reference`.`applicant_id`
LEFT JOIN `g_people` applicant_person ON `applicant_person`.`id` = `applicants`.`person_id`
LEFT JOIN `g_addresses` applicant_address ON `applicant_address`.`id` = `applicants`.`address_id`
LEFT JOIN `properties` ON `properties`.`id` = `reference`.`property_id`
LEFT JOIN `g_addresses` property_address ON `property_address`.`id` = `properties`.`address_id`
WHERE `reference`.`id` = 4