user2301765
user2301765

Reputation: 729

Advanced Mysql Query to get master record if two conditions matches on different rows of child records

I was writing a mysql filter query which has a primary table and another table which holds multiple records against each record of primary table (I will call this table child).

Am trying to write a query which fetches record of primary table based on its values on child table. If the child table condition is one then I will be able to do it simply by joining, but I have 2 conditions which falls on same field.

For ex.
table 1:
id   name  url
1    XXX   http://www.yahoo.com
2    YYY   http://www.google.com
3    ZZZ   http://www.bing.com

table 2:
id masterid optionvalue
1  1        2
2  1        7
3  2        7
4  2        2
5  3        2
6  3        6

My query has to return unique master records when the optionvalue matches only both 2 different conditions match on second table. I wrote query with IN...

select * from table1 
left join table2 on table1.id=table2.masterid 
where table2.optionvalue IN(2,7) group by table1.id;

This gets me all 3 records because IN is basically checking 'OR', but in my case I should not get 3rd master record because it has values 2,6 (there is no 7). If I write query with 'AND' then am not getting any records...

select * from table1 
left join table2 on table1.id=table2.masterid 
where table2.optionvalue = 2 and table2.optionvalue = 7;

This will not return records as the and will fail as am checking different values on same column. I wanted to write a query which fetches master records which has child records with field optionvalues holds both 2 and 7 on different records.

Any help would be much appreciated.

Upvotes: 3

Views: 1617

Answers (4)

Stan
Stan

Reputation: 983

Indeed, as AsConfused hinted, you need to two joins to TABLE2 using aliases

-- both of these are tested:

-- find t1 where it has 2 and 7 in t2

    select t1.*
    from table1 t1
    join table2 ov2 on t1.id=ov2.masterid and ov2.optionValue=2
    join table2 ov7 on t1.id=ov7.masterid and ov7.optionValue=7

-- find t1 where it has 2 and 7 in t2, and no others in t2

select t1.*, ovx.id
    from table1 t1
      join table2 ov2 on t1.id=ov2.masterid and ov2.optionValue=2
      join table2 ov7 on t1.id=ov7.masterid and ov7.optionValue=7
      LEFT OUTER JOIN table2 ovx on t1.id=ovx.masterid and ovx.optionValue not in (2,7)
    WHERE ovx.id is null

Upvotes: 5

Karl Kieninger
Karl Kieninger

Reputation: 9149

This can also be done without the joins using correlated exists subqueries. That may be more efficient.

select *
  from table1 
 WHERE EXISTS (SELECT 1 FROM table2 WHERE table1.id=table2.masterid and optionvalue = 2)
   AND EXISTS (SELECT 1 FROM table2 WHERE table1.id=table2.masterid and optionvalue = 7)

If this is to be an exclusive match as suggested by, "when the optionvalue matches only both 2 different conditions match on second table" then you could ad yet a third exists condition. Performance-wise this may start to break down.

AND NOT EXISTS (SELECT 1 FROM table2 WHERE table1.id=table2.masterid AND optionvalue  NOT IN (2,7)

Edit: A note on correlated subqueries from Which one is faster: correlated subqueries or join?.

Upvotes: -2

Aleksandr Introvert
Aleksandr Introvert

Reputation: 1

select * from t1 where id in (select masterid from t2 where (t2.masterid in (select masterid from t2 where optionvalue=2)) and (t2.masterid in (select masterid from t2 where optionvalue=7)))

Old school :-) Query took 0.0009 sec.

Upvotes: 0

Ashalynd
Ashalynd

Reputation: 12573

You can try something like this (no performance guarantees, and assumes you only want exact matches):

select table1.* from table1 join
(select masterid, group_concat(optionvalue order by optionvalue) as opt from table2 
group by masterid) table2_group on table1.id=table2_group.masterid
where table2_group.opt='2,7';

http://sqlfiddle.com/#!9/673094/9

Upvotes: 2

Related Questions