SELECT if left join IS AND IS NOT ( MYSQL )? - mysql

I got one table "people".
Another one with "hobbiesConnection", and they are connected as an OneToMany.
I would like to build a search, where it is possible to search people which have a hobby and don't have a hobby.
Something like :
SELECT * FROM people
LEFT JOIN hobbiesConnection ON hobbiesConnection.people_id =
hobbiesConnection.hobby_id
WHERE hobby_id = 4 AND hobby_id != 5
Now I get the person with the hobby 4, but I want to get an empty result, because both conditions have to fit to the person.
Does anybody have an idea how to accomplish this ?

Firstly, your JOIN is not correct. The two tables should be linked with a foreign key / common column. Try the below query;
SELECT * FROM people
LEFT JOIN hobbiesConnection
ON hobbiesConnection.people_id = people.people_id
And (hobbiesConnection.hobby_id = 4 AND hobbiesConnection.hobby_id != 5)

use (NOT) EXISTS clause:
SELECT * FROM people p
WHERE TRUE
AND EXISTS (
SELECT TRUE FROM hobbiesConnection hc
WHERE hc.people_id = p.people_id -- or p.id? you didnt mention
AND hobby_id = 4
)
AND NOT EXISTS (
SELECT TRUE FROM hobbiesConnection hc
WHERE hc.people_id = p.people_id -- or p.id? you didnt mention
AND hobby_id = 5
)
You can achieve the same using joins
SELECT p.*
FROM people p
JOIN hobbiesConnection h4 ON TRUE
AND h4.people_id = p.people_id -- or p.id? you didnt mention
AND h4.hobby_id = 4
LEFT JOIN hobbiesConnection h5 ON TRUE
AND h5.people_id = p.people_id -- or p.id? you didnt mention
AND h5.hobby_id = 5
WHERE h5.id IS NULL -- or whatever column from that table
have a look at the fiddle: http://sqlfiddle.com/#!9/d9926/4

Related

How do I make this complex query run faster?

This query is taking between 20-40 seconds to run. I need to speed it up greatly if possible.
SELECT DISTINCT a.category, a.key
FROM system_permissions AS a, system_permission_to_role AS b,
system_user_to_role AS c, system_users AS d
WHERE
(
(
a.system_permission_id=b.system_permission_id
AND (b.system_role_id=c.system_role_id || c.system_role_id = 0)
AND a.system_permission_id NOT IN (
SELECT system_permission_id FROM system_permission_exclusions AS f
WHERE d.system_user_id=f.system_user_id
)
AND c.system_user_id=d.system_user_id
)
OR a.system_permission_id IN (
SELECT system_permission_id
FROM system_permission_inclusions AS g
WHERE d.system_user_id=g.system_user_id
)
)
AND d.ldap_objectguid = '?';
The reason behind doing it this way is that I am creating exclusion and inclusion tables for permissions that fall outside of the standard defined roles, so first I need to exclude ones that are part of the role but exist in the exclusion table, then I need to add ones that are NOT part of their role, but exist in the inclusion table.
I am open to the idea of redesigning the tables also.
Does this work?
SELECT DISTINCT P.category, P.key
FROM system_users U
LEFT OUTER JOIN system_permission_inclusions PI ON PI.system_user_id = U.system_user_id
INNER JOIN system_user_to_role UR ON UR.system_user_id = U.system_user_id
INNER JOIN system_permission_to_role PR ON PR.system_role_id = UR.system_role_id
INNER JOIN system_permissions P ON P.system_permission_id = PR.system_permission_id OR P.system_permission_id = PI.system_permission_id
WHERE U.ldap_objectguid = '?'
AND P.system_permission_id NOT IN (SELECT system_permission_id FROM system_permission_exclusions WHERE system_user_id = U.system_user_id)

Full outer join in mysql with movie database

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

How to get the columns from three different tables?

I have three different table as mention below
mRNA_GO
MSU7_LOC
GO_ID
Gene Ontology
GO_ID (Primary Key)
Category
Term
Evidence
miRNA_mRNA
miRNA_ID
MSU7_LOC
Table 1 is connected with table 2 by GO_ID and with table 3 by MSU7_LOC.
I want following columns in my output.
table1.MSU7_LOC
table2.GO_ID
table2.Category
table2.term
table2.Evidence
tabke3.miRNA_ID
I have written two diff query
Query 1
select gene_ontology.go_id , gene_ontology.category, gene_ontology.evidence, gene_ontology.term , mrna_go.MSU7_LOC
from gene_ontology inner join mrna_go on mrna_go.go_id = gene_ontology.go_id
where mrna_go.go_id in ('GO:0009058') ;
Which will give me following columns
table1.MSU7_LOC
table2.GO_ID
table2.Category
table2.term
table2.Evidenc
Query 2
SELECT mrna_go.go_id, mirna_mrna.mirna
from mirna_mrna inner join mrna_go on mrna_go.MSU7_LOC = mirna_mrna.MSU7_LOC
where mrna_go.go_id in ('GO:0009058') ;
which will give me
table2.GO_ID
tabke3.miRNA_ID
Can any one tell me how can I get the output using only one query not two different query..
Just join third table
SELECT
mg.go_id,
mm.mirna ,
g.go_id ,
g.category,
g.evidence,
g.term ,
mg.MSU7_LOC
FROM mirna_mrna mm
inner join mrna_go mg on mg.MSU7_LOC = mm.MSU7_LOC
inner join gene_ontology g on mg.go_id = g.go_id
where mg.go_id in ('GO:0009058') ;
just add a 2nd join in like;
SELECT gene_ontology.go_id , gene_ontology.category, gene_ontology.evidence, gene_ontology.term , mrna_go.MSU7_LOC, mrna_go.go_id, mirna_mrna.mirna
FROM gene_ontology
INNER JOIN mrna_go ON mrna_go.go_id = gene_ontology.go_id
INNER JOIN mirna_mrna ON mrna_go.MSU7_LOC = mirna_mrna.MSU7_LOC
WHERE mrna_go.go_id IN ('GO:0009058') ;

MySQL Query between 2 tables and find not null

I have 2 tables, one for the articles and one for some attributes
I have some products that have one attribute with value Yes. I also have other attributes.
The query that i want to create is to get all products that don't have the Attribute 7.
You can check the mysql tables.
http://sqlfiddle.com/#!2/f75eec/1
select a.ArticleID,a.ArticleTitle,aa.ArticleID,aa.AttrID,aa.StringValue
from cms_articles a
inner join cms_attr_art aa on aa.ArticleID = a.ArticleID
where a.ArticleID NOT IN (select ArticleID from cms_attr_art where AttrID = 7);
You can use this query
SELECT a.ArticleId, b.attrId
FROM cms_articles a
INNER JOIN cms_attr_art b
ON a.articleId = b.articleId
WHERE NOT EXISTS (SELECT 1 FROM cms_attr_art c WHERE c.articleid = a.articleid AND c.attrId = 7)

MySQL - Using column value for joining in the same query

I have three tables that looks something like this:
Table joins
|ID|JOIN_NAME|
1 persons
2 companies
Table information
|ID|JOIN_ID|
1 1
2 2
Table information_extra_persons
|ID|INFORMATION_ID|NAME|
1 1 John
Table information_extra_companies
|ID|INFORMATION_ID|NAME|
1 2 IBM
How can i join together these tables in one SQL? I've tried something like:
SELECT * FROM `information`
INNER JOIN `information_extra_(SELECT `name` FROM `joins` WHERE `id` = `join_id`)`
ON `information_extra_(SELECT `name` FROM `joins` WHERE `id` = `join_id`)`.`information_id` = `information`.`id`
but I can't get it to work. Of course this isn't my actual table setup, but it's the same principle. Does anyone know how to get all the info in just one SQL?
That's actually four tables, not three. This isn't just a nitpick - it looks as though the substance of your question is "how can I use the name of the table as part of the join criteria?" (ie. how can the information_extra_ tables be treated as a single table?)
To which the answer is: you can't. (Outside of dynamic SQL.)
In this specific case, the following should return what I think you are looking for:
select j.join_name joined_entity,
case when j.join_name = 'persons' then p.name
else c.name
end joined_entity_name
from information i
inner join joins j on i.join_id = j.id
left join information_extra_persons p on i.id = p.information_id
left join information_extra_companies c on i.id = c.information_id
Alternatively, a less efficient (but more general) approach might be:
select j.join_name joined_entity,
v.name joined_entity_name
from information i
inner join joins j on i.join_id = j.id
inner join (select 'persons' entity, information_id, name from information_extra_persons
union all
select 'companies' entity, information_id, name from information_extra_companies) v
on i.id = v.information_id and j.join_name = v.entity