I have 3 tables : news, users_regions_favorites and users_categories_favorites. Each news has a region and a category.
I want to return all news that are related the a user's favorites (by the regions or categories he likes). And never return a news twice, so no UNION.
Is there a way to do this with join?
You can indeed use UNION:
SELECT n.id
FROM news n
INNER JOIN users_categories_favorites c
ON c.id = n.catid
WHERE c.uid = 1 -- your user here
UNION
SELECT n.id
FROM news n
INNER JOIN users_regions_favorites r
ON r.id = n.regid
WHERE r.uid = 1; -- your user here
UNION will deduplicate, only UNION ALL won't.
But you can also do this using only JOINs:
SELECT DISTINCT n.id
FROM news n
LEFT JOIN users_categories_favorites c
ON c.id = n.catid
LEFT JOIN users_regions_favorites r
ON r.id = n.regid
WHERE c.uid = 1 OR r.uid = 1; -- your user here
See this fiddle showing both results.
you could make (schematically) :
select distinct
news where exists users_regions_favorites
union
news where exists users_categories_favorites
Related
I have this query in SQL that I KNOW it is horribly written. Could you guys help me write it in a decent, normal person manner?
Thanks.
select distinct R.*, X.LIKED
from Recipe R
left join (select distinct R.* , '1' as LIKED
from Recipe R, Likes L
where R.id = L.idRecipe
and L.email = 'dvader#deathstar.galacticempire') X
on R.id = X.id
looks like you need all from recipe with marks on liked by vader#deathstar.galacticempire
select R.*, likedR.LIKED
from Recipe R
left join (select distinct R.id , '1' as LIKED
from Recipe R
inner join Likes L on R.id = L.idRecipe
where
L.email = 'dvader#deathstar.galacticempire') likedR
on R.id = likedR.id
Thanks everyone for your help.
I was able to do what i wanted with this query:
select distinct R.*, X.LIKED, U.imgUrl
from User U, Recipe R
left join
(select distinct R.* , '1' as LIKED
from Recipe R, Likes L
where R.id = L.idRecipe and L.email = 'dvader#deathstar.ge') X
on R.id = X.id
where R.email = U.email
This will bring all the info i need in one table plus 1 extra column with either a 1 or a null if the entry of dvader is in another table, Using joins.
SELECT
id
FROM
Posts
WHERE
subject_id = 1
OR subject_id IN (
SELECT related_subject_id
FROM RelatedSubjects
WHERE parent_subject_id = 1);
Trying to select all posts for a current subject but also for any sub-subjects which are stored in another lookup table. The above query works, wondering how to accomplish the same thing with a join
SELECT DISTINCT id
FROM Posts AS p
LEFT JOIN RelatedSubjects AS r
ON p.subject_id = r.related_subject_id AND r.parent_subject_id = 1
WHERE p.subject_id = 1 OR r.related_subject_id IS NOT NULL
Assuming proper indexes, UNION often performs better than JOIN with OR:
SELECT p.id
FROM Posts AS p
WHERE p.subject_id = 1
UNION
SELECT p.id
FROM RelatedSubjects AS r
JOIN Posts AS p
ON p.subject_id = r.related_subject_id
WHERE r.parent_subject_id = 1
select
`Posts`.`id`
From posts as `Posts`
LEFT join RelatedSubjects as `RelatedSubjects`
on (`RelatedSubjects`.`related_subject_id` = `Posts`.`subject_id`)
where `Posts`.`subject_id` = 1
Is it possible to INNER JOIN a MySQL query to achieve this result?
I have a table with Strategies and a table with Members. The Strategy table holds the ID of the author that corresponds to their ID in the Member table and the ID of an author that updated the existing author's work. Is it possible to grab a reference to both of these people at the same time? Something like the following, which returns no errors, but also no results...
SELECT * FROM Strategies
INNER JOIN Members AS a
INNER JOIN Members AS b
WHERE Strategies.ID='2'
AND Strategies.AuthorID = a.ID
AND Strategies.UpdateAuthorID = b.ID
Use a LEFT JOIN:
SELECT
s.*,
a.Name AS MemberName,
b.Name AS UpdatedMemberName
FROM Strategies AS s
LEFT JOIN Members AS a ON s.AuthorID = a.ID AND s.ID = 2
LEFT JOIN Members AS b ON s.UpdateAuthorID = b.ID AND s.ID = 2 ;
If you want them in one column use COALESCE:
SELECT
s.*,
COALESCE(a.Name, b.Name) AS MemberName
FROM Strategies AS s
LEFT JOIN Members AS a ON s.AuthorID = a.ID AND s.ID = 2
LEFT JOIN Members AS b ON s.UpdateAuthorID = b.ID AND s.ID = 2
SELECT toD.dom_url AS ToURL,
fromD.dom_url AS FromUrl,
rvw.*
FROM reviews AS rvw
LEFT JOIN domain AS toD
ON toD.Dom_ID = rvw.rev_dom_for
LEFT JOIN domain AS fromD
ON fromD.Dom_ID = rvw.rev_dom_from
if domain is table name
I have three tables in Mysql that are link together:
Profile (ID, Name, Stuff..)
Contact(ID, ProfileID,desc,Ord)
Address(ID,ProfileID, desc, Ord)
Now I need to select all profile from the profile table, with the “desc” field from Contact and Address where Ord = 1. (this is for a search function where in a table I’ll display the name, main contact info and main Address of a client.
I can currently do this with three separate SQL request:
SELECT Name, ID FROM Profile WHERE name=”bla”
Then in a foreach loop, I’ll run the other two requests:
SELECT ProfileID, desc FROM Contact WHERE ProfileID=MyProfileID AND Ord=1
SELECT ProfileID, desc FROM Address WHERE ProfileID=MyProfileID AND Ord=1
I know you can do multiple SELECT in one query, is there a way I could group all three SELECT into one query?
You should be able to JOIN the tables on the profile.id and the profileid in the other tables.
If you are sure the profileid exists in all three tables, then you can use an INNER JOIN. The INNER JOIN returns matching rows in all of the tables:
select p.id,
p.name,
c.desc ContactDesc,
a.desc AddressDesc
from profile p
inner join contact c
on p.id = c.profileid
inner join address a
on p.id = a.profileid
where p.name = 'bla'
and c.ord = 1
and a.ord = 1
If you are not sure that you will have matching rows, then you can use a LEFT JOIN:
select p.id,
p.name,
c.desc ContactDesc,
a.desc AddressDesc
from profile p
left join contact c
on p.id = c.profileid
and c.ord = 1
left join address a
on p.id = a.profileid
and a.ord = 1
where p.name = 'bla'
If you need help learning JOIN syntax, here is a great visual explanation of joins
This query below only selects column when an ID from Profile table has atleast one match on tables: Contact and Address. If one or both of them are nullable, use LEFT JOIN instead of INNER JOIN because LEFT JOIN displays all records from the Left-hand side table regardless if it has a match on other tables or not.
SELECT a.*,
b.desc as BDESC,
c.desc as CDESC
FROM Profile a
INNER JOIN Contact b
ON a.ID = b.ProfileID
INNER JOIN Address c
ON a.ID = c.ProfileID
WHERE b.ORD = 1 AND
c.ORD = 1 AND
a.Name = 'nameHERE'
The LEFT JOIN version:
SELECT a.*,
b.desc as BDESC,
c.desc as CDESC
FROM Profile a
INNER JOIN Contact b
ON a.ID = b.ProfileID AND b.ORD = 1
INNER JOIN Address c
ON a.ID = c.ProfileID AND c.ORD = 1
WHERE a.Name = 'nameHERE'
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
i have created working demo as your requirement :
The query bellow will retrieve all matching records from the database.its retrieving profile id,name stufff and description of contact tables
select p.id,p.name,p.stauff,c.descr,a.descr from profile as p
inner join contact as c on c.profileid=p.id
inner join address as a on a.profileid=p.id
where p.name="bla" and c.ord=1 and a.ord=1
Im trying to select a table with multiple joins, one for the number of comments using COUNT and one to select the total vote value using SUM, the problem is that the two joins affect each other, instead of showing:
3 votes 2 comments
I get 3 * 2 = 6 votes and 2 * 3 comments
This is the query I'm using:
SELECT t.*, COUNT(c.id) as comments, COALESCE(SUM(v.vote), 0) as votes
FROM (topics t)
LEFT JOIN comments c ON c.topic_id = t.id
LEFT JOIN votes v ON v.topic_id = t.id
WHERE t.id = 9
What you're doing is an SQL antipattern that I call Goldberg Machine. Why make the problem so much harder by forcing it to be done in a single SQL query?
Here is how I would really solve this problem:
SELECT t.*, COUNT(c.id) as comments
FROM topics t
LEFT JOIN comments c ON c.topic_id = t.id
WHERE t.id = 9;
SELECT t.*, SUM(v.vote) as votes
FROM topics t
LEFT JOIN votes v ON v.topic_id = t.id
WHERE t.id = 9;
As you have found, combining these two into one query results in a Cartesian product. There may be clever and subtle ways to force it to give you the correct answer in one query, but what happens when you need a third statistic? It's much simpler to do it in two queries.
SELECT t.*, COUNT(c.id) as comments, COALESCE(SUM(v.vote), 0) as votes
FROM (topics t)
LEFT JOIN comments c ON c.topic_id = t.id
LEFT JOIN votes v ON v.topic_id = t.id
WHERE t.id = 9
GROUP BY t.id
or perhaps
SELECT `topics`.*,
(
SELECT COUNT(*)
FROM `comments`
WHERE `topic_id` = `topics`.`id`
) AS `num_comments`,
(
SELECT IFNULL(SUM(`vote`), 0)
FROM `votes`
WHERE `topic_id` = `topics`.`id`
) AS `vote_total`
FROM `topics`
WHERE `id` = 9
SELECT t.*, COUNT(DISTINCT c.id) as comments, COALESCE(SUM(v.vote), 0) as votes
FROM (topics t)
LEFT JOIN comments c ON c.topic_id = t.id
LEFT JOIN votes v ON v.topic_id = t.id
WHERE t.id = 9