tags:

views:

230

answers:

2

Hi. Say for example, I have the following two tables:

TableA { _id }
TableB { _id, TableA_id, OptionString }

Each row in TableA has one or more rows in TableB referencing it (using the TableA_id foreign key).

My query lists rows in TableA to display to the user.

OptionString can be one of two values - let's say "Option1" and "Option2".

Now I want the query to still list rows in TableA, but I want to provide the user with a filter to say "only display rows in TableA where the OptionString has either "Option1" OR "Option2" (ie. exclusive or).

I've tried using COUNT, but the problem is that a zero count displays no results (not '0' as I would want).

I'm sure I must be missing something simple with this.

Any help would be greatly appreciated.

Cheers, Dan.

+3  A: 

Try this, if I understand your question correctly

select a._id
from tableA a
join tableB b on a._id=b.tableA_id
where b.optionString in ('Option1','Option2')
group by a._id
having count(*)=1

Revised query based on new information

select a._id
from tableA a
join (select distinct _id,tablea_id,optionString from TableB) b 
        on a._id=b.tableA_id
where b.optionString in ('Option1','Option2')
group by a._id
having count(*)=1

What I am doing here is forcing distinct values from tableB

Sparky
If TableB had 5 Option1's and no Option2s referencing a specific row in TableA - wouldn't the count(*) for that row be 5, rather than 1?
Dan
If would be, but I wasn't sure by your example that the tableb could have multiple occurrences of the pattern... Can tableb have other values for the optionString (other than Option1 and Option2)
Sparky
Currently it can only have Option1 and Option2. It 'may' in the future want another option, but most likely not.
Dan
Well, the second variation of the query should handle it regardless, but if TableB gets large, I would add the where clause inside the distinct query. You also probably don't need _id in the inner query, but only your code can tell you that or not...
Sparky
The problem is that the tableb actually has a lot more fields to it (and there's also other tables involved). My examples tables were a very much cutdown version of the real world version. I'm on the verge of saying to the powers that be that this won't be done, as it will really slow things down.Thankyou very much for the help though. Greatly appreciated.
Dan
Since TableB is large, I would add a covering Index for the above query (i.e. an index on the 3 (or 2 if you remove _id) fields used in the subquery)
Sparky
+1  A: 

A naive approach (might be able to improve upon this...)

SELECT * 
FROM TableA
WHERE _id IN 
  (SELECT TableA_id
   FROM TableB
   WHERE OptionString IN ('Option1', 'Option2')
  )
AND _id NOT IN
  (SELECT T1.TableA_id
   FROM TableB T1
   JOIN TableB T2 ON T1.TableA_id = T2.TableA_id
   WHERE T1.optionString = 'Option1'
     AND T2.optionString = 'Option2'
  )

The idea is simply to select qualifying records where the Option1 OR the Option2 are found, and to exclude the records where both Option1 AND Option2 are found.

If we know that a given Optionx value can only be found once for a given item of TableA, a group by query may be applicable (see Sparky's answer).

mjv
This looks like the kind of things I'm after. Thanks for that.
Dan